Ver código fonte

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
Aakansha Doshi 1 ano atrás
pai
commit
4f0a2a9593
51 arquivos alterados com 1431 adições e 229 exclusões
  1. 1 0
      .gitignore
  2. 15 6
      examples/excalidraw/components/App.scss
  3. 171 130
      examples/excalidraw/components/App.tsx
  4. 13 14
      examples/excalidraw/components/CustomFooter.tsx
  5. 27 0
      examples/excalidraw/components/MobileFooter.tsx
  6. 0 0
      examples/excalidraw/components/sidebar/ExampleSidebar.scss
  7. 2 3
      examples/excalidraw/components/sidebar/ExampleSidebar.tsx
  8. 2 2
      examples/excalidraw/initialData.tsx
  9. 13 0
      examples/excalidraw/package.json
  10. 3 0
      examples/excalidraw/tsconfig.json
  11. 146 0
      examples/excalidraw/utils.ts
  12. 36 0
      examples/excalidraw/with-nextjs/.gitignore
  13. 36 0
      examples/excalidraw/with-nextjs/README.md
  14. 12 0
      examples/excalidraw/with-nextjs/next.config.js
  15. 25 0
      examples/excalidraw/with-nextjs/package.json
  16. 0 0
      examples/excalidraw/with-nextjs/public/images/doremon.png
  17. 0 0
      examples/excalidraw/with-nextjs/public/images/excalibot.png
  18. 0 0
      examples/excalidraw/with-nextjs/public/images/pika.jpeg
  19. 0 0
      examples/excalidraw/with-nextjs/public/images/rocket.jpeg
  20. BIN
      examples/excalidraw/with-nextjs/src/app/favicon.ico
  21. 11 0
      examples/excalidraw/with-nextjs/src/app/layout.tsx
  22. 23 0
      examples/excalidraw/with-nextjs/src/app/page.tsx
  23. 15 0
      examples/excalidraw/with-nextjs/src/common.scss
  24. 22 0
      examples/excalidraw/with-nextjs/src/excalidrawWrapper.tsx
  25. 22 0
      examples/excalidraw/with-nextjs/src/pages/excalidraw-in-pages.tsx
  26. 28 0
      examples/excalidraw/with-nextjs/tsconfig.json
  27. 3 0
      examples/excalidraw/with-nextjs/vercel.json
  28. 252 0
      examples/excalidraw/with-nextjs/yarn.lock
  29. 5 5
      examples/excalidraw/with-script-in-browser/index.html
  30. 28 0
      examples/excalidraw/with-script-in-browser/index.tsx
  31. 19 0
      examples/excalidraw/with-script-in-browser/package.json
  32. BIN
      examples/excalidraw/with-script-in-browser/public/images/doremon.png
  33. BIN
      examples/excalidraw/with-script-in-browser/public/images/excalibot.png
  34. BIN
      examples/excalidraw/with-script-in-browser/public/images/pika.jpeg
  35. BIN
      examples/excalidraw/with-script-in-browser/public/images/rocket.jpeg
  36. 1 1
      examples/excalidraw/with-script-in-browser/vercel.json
  37. 11 0
      examples/excalidraw/with-script-in-browser/vite.config.mts
  38. 313 0
      examples/excalidraw/yarn.lock
  39. 3 1
      package.json
  40. 0 2
      packages/excalidraw/.gitignore
  41. 4 1
      packages/excalidraw/components/App.tsx
  42. 0 1
      packages/excalidraw/constants.ts
  43. 0 20
      packages/excalidraw/example/MobileFooter.tsx
  44. 0 17
      packages/excalidraw/example/index.tsx
  45. 8 1
      packages/excalidraw/index.tsx
  46. 0 1
      packages/excalidraw/renderer/renderScene.ts
  47. 1 1
      packages/excalidraw/tsconfig.json
  48. 0 15
      packages/excalidraw/vite.config.mts
  49. 4 3
      scripts/buildExample.mjs
  50. 1 1
      tsconfig.json
  51. 155 4
      yarn.lock

+ 1 - 0
.gitignore

@@ -25,3 +25,4 @@ packages/excalidraw/types
 coverage
 dev-dist
 html
+examples/**/bundle.*

+ 15 - 6
packages/excalidraw/example/App.scss → examples/excalidraw/components/App.scss

@@ -15,14 +15,23 @@
       border-radius: 50%;
     }
   }
+  .app-title {
+    margin-block-start: 0.83em;
+    margin-block-end: 0.83em;
+  }
 }
 
-.button-wrapper button {
-  z-index: 1;
-  height: 40px;
-  max-width: 200px;
-  margin: 10px;
-  padding: 5px;
+.button-wrapper {
+  input[type="checkbox"] {
+    margin: 5px;
+  }
+  button {
+    z-index: 1;
+    height: 40px;
+    max-width: 200px;
+    margin: 10px;
+    padding: 5px;
+  }
 }
 
 .excalidraw .App-menu_top .buttonList {

+ 171 - 130
packages/excalidraw/example/App.tsx → examples/excalidraw/components/App.tsx

@@ -1,15 +1,30 @@
+import React, {
+  useEffect,
+  useState,
+  useRef,
+  useCallback,
+  Children,
+  cloneElement,
+} from "react";
 import ExampleSidebar from "./sidebar/ExampleSidebar";
 
-import type * as TExcalidraw from "../index";
+import type * as TExcalidraw from "@excalidraw/excalidraw";
 
-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 {
+  resolvablePromise,
+  ResolvablePromise,
+  distance2d,
+  fileOpen,
+  withBatchedUpdates,
+  withBatchedUpdatesThrottled,
+} from "../utils";
+
+import CustomFooter from "./CustomFooter";
+import MobileFooter from "./MobileFooter";
+import initialData from "../initialData";
+
 import type {
   AppState,
   BinaryFileData,
@@ -18,19 +33,14 @@ import type {
   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";
+} from "@excalidraw/excalidraw/dist/excalidraw/types";
+import type {
+  NonDeletedExcalidrawElement,
+  Theme,
+} from "@excalidraw/excalidraw/dist/excalidraw/element/types";
+import type { ImportedLibraryData } from "@excalidraw/excalidraw/dist/excalidraw/data/types";
 
-declare global {
-  interface Window {
-    ExcalidrawLib: typeof TExcalidraw;
-  }
-}
+import "./App.scss";
 
 type Comment = {
   x: number;
@@ -51,31 +61,6 @@ type PointerDownState = {
   };
 };
 
-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;
@@ -84,8 +69,38 @@ export interface AppProps {
   appTitle: string;
   useCustom: (api: ExcalidrawImperativeAPI | null, customArgs?: any[]) => void;
   customArgs?: any[];
+  children: React.ReactNode;
+  excalidrawLib: typeof TExcalidraw;
 }
-export default function App({ appTitle, useCustom, customArgs }: AppProps) {
+
+export default function App({
+  appTitle,
+  useCustom,
+  customArgs,
+  children,
+  excalidrawLib,
+}: AppProps) {
+  const {
+    exportToCanvas,
+    exportToSvg,
+    exportToBlob,
+    exportToClipboard,
+    useHandleLibrary,
+    MIME_TYPES,
+    sceneCoordsToViewportCoords,
+    viewportCoordsToSceneCoords,
+    restoreElements,
+    Sidebar,
+    Footer,
+    WelcomeScreen,
+    MainMenu,
+    LiveCollaborationTrigger,
+    convertToExcalidrawElements,
+    TTDDialog,
+    TTDDialogTrigger,
+    ROUNDNESS,
+    loadSceneOrLibraryFromBlob,
+  } = excalidrawLib;
   const appRef = useRef<any>(null);
   const [viewModeEnabled, setViewModeEnabled] = useState(false);
   const [zenModeEnabled, setZenModeEnabled] = useState(false);
@@ -147,8 +162,105 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
       };
     };
     fetchData();
-  }, [excalidrawAPI]);
+  }, [excalidrawAPI, convertToExcalidrawElements, MIME_TYPES]);
 
+  const renderExcalidraw = (children: React.ReactNode) => {
+    const Excalidraw: any = Children.toArray(children).find(
+      (child) =>
+        React.isValidElement(child) &&
+        typeof child.type !== "string" &&
+        //@ts-ignore
+        child.type.displayName === "Excalidraw",
+    );
+    if (!Excalidraw) {
+      return;
+    }
+    const newElement = cloneElement(
+      Excalidraw,
+      {
+        excalidrawAPI: (api: ExcalidrawImperativeAPI) => setExcalidrawAPI(api),
+        initialData: initialStatePromiseRef.current.promise,
+        onChange: (
+          elements: NonDeletedExcalidrawElement[],
+          state: AppState,
+        ) => {
+          console.info("Elements :", elements, "State : ", state);
+        },
+        onPointerUpdate: (payload: {
+          pointer: { x: number; y: number };
+          button: "down" | "up";
+          pointersMap: Gesture["pointers"];
+        }) => setPointerData(payload),
+        viewModeEnabled,
+        zenModeEnabled,
+        gridModeEnabled,
+        theme,
+        name: "Custom name of drawing",
+        UIOptions: {
+          canvasActions: {
+            loadScene: false,
+          },
+          tools: { image: !disableImageTool },
+        },
+        renderTopRightUI,
+        onLinkOpen,
+        onPointerDown,
+        onScrollChange: rerenderCommentIcons,
+        validateEmbeddable: true,
+      },
+      <>
+        {excalidrawAPI && (
+          <Footer>
+            <CustomFooter
+              excalidrawAPI={excalidrawAPI}
+              excalidrawLib={excalidrawLib}
+            />
+          </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";
+          }}
+        />
+      </>,
+    );
+    return newElement;
+  };
   const renderTopRightUI = (isMobile: boolean) => {
     return (
       <>
@@ -332,8 +444,8 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
     pointerDownState: PointerDownState,
   ) => {
     return withBatchedUpdates((event) => {
-      window.removeEventListener(EVENT.POINTER_MOVE, pointerDownState.onMove);
-      window.removeEventListener(EVENT.POINTER_UP, pointerDownState.onUp);
+      window.removeEventListener("pointermove", pointerDownState.onMove);
+      window.removeEventListener("pointerup", pointerDownState.onUp);
       excalidrawAPI?.setActiveTool({ type: "selection" });
       const distance = distance2d(
         pointerDownState.x,
@@ -397,8 +509,8 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
               onPointerMoveFromPointerDownHandler(pointerDownState);
             const onPointerUp =
               onPointerUpFromPointerDownHandler(pointerDownState);
-            window.addEventListener(EVENT.POINTER_MOVE, onPointerMove);
-            window.addEventListener(EVENT.POINTER_UP, onPointerUp);
+            window.addEventListener("pointermove", onPointerMove);
+            window.addEventListener("pointerup", onPointerUp);
 
             pointerDownState.onMove = onPointerMove;
             pointerDownState.onUp = onPointerUp;
@@ -490,7 +602,7 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
         }}
         onBlur={saveComment}
         onKeyDown={(event) => {
-          if (!event.shiftKey && event.key === KEYS.ENTER) {
+          if (!event.shiftKey && event.key === "Enter") {
             event.preventDefault();
             saveComment();
           }
@@ -523,7 +635,12 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
         </MainMenu.ItemCustom>
         <MainMenu.DefaultItems.Help />
 
-        {excalidrawAPI && <MobileFooter excalidrawAPI={excalidrawAPI} />}
+        {excalidrawAPI && (
+          <MobileFooter
+            excalidrawLib={excalidrawLib}
+            excalidrawAPI={excalidrawAPI}
+          />
+        )}
       </MainMenu>
     );
   };
@@ -672,83 +789,7 @@ export default function App({ appTitle, useCustom, customArgs }: AppProps) {
           </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>
+          {renderExcalidraw(children)}
           {Object.keys(commentIcons || []).length > 0 && renderCommentIcons()}
           {comment && renderComment()}
         </div>

+ 13 - 14
packages/excalidraw/example/CustomFooter.tsx → examples/excalidraw/components/CustomFooter.tsx

@@ -1,6 +1,6 @@
-import type { ExcalidrawImperativeAPI } from "../types";
+import type * as TExcalidraw from "@excalidraw/excalidraw";
+import type { ExcalidrawImperativeAPI } from "@excalidraw/excalidraw/dist/excalidraw/types";
 
-const { Button, MIME_TYPES } = window.ExcalidrawLib;
 const COMMENT_SVG = (
   <svg
     xmlns="http://www.w3.org/2000/svg"
@@ -17,24 +17,28 @@ const COMMENT_SVG = (
     <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,
+  excalidrawLib,
 }: {
   excalidrawAPI: ExcalidrawImperativeAPI;
+  excalidrawLib: typeof TExcalidraw;
 }) => {
+  const { Button, MIME_TYPES } = excalidrawLib;
+
   return (
     <>
       <Button
         onSelect={() => alert("General Kenobi!")}
-        className="you are a bold one"
-        style={{ marginLeft: "1rem" }}
+        style={{ marginLeft: "1rem", width: "auto" }}
         title="Hello there!"
       >
-        {COMMENT_SVG}
+        Hit me
       </Button>
-      <button
+      <Button
         className="custom-element"
-        onClick={() => {
+        onSelect={() => {
           excalidrawAPI?.setActiveTool({
             type: "custom",
             customType: "comment",
@@ -57,15 +61,10 @@ const CustomFooter = ({
           )}`;
           excalidrawAPI?.setCursor(`url(${url}), auto`);
         }}
+        title="Comments!"
       >
         {COMMENT_SVG}
-      </button>
-      <button
-        className="custom-footer"
-        onClick={() => alert("This is dummy footer")}
-      >
-        custom footer
-      </button>
+      </Button>
     </>
   );
 };

+ 27 - 0
examples/excalidraw/components/MobileFooter.tsx

@@ -0,0 +1,27 @@
+import { ExcalidrawImperativeAPI } from "@excalidraw/excalidraw/dist/excalidraw/types";
+import CustomFooter from "./CustomFooter";
+import type * as TExcalidraw from "@excalidraw/excalidraw";
+
+const MobileFooter = ({
+  excalidrawAPI,
+  excalidrawLib,
+}: {
+  excalidrawAPI: ExcalidrawImperativeAPI;
+  excalidrawLib: typeof TExcalidraw;
+}) => {
+  const { useDevice, Footer } = excalidrawLib;
+
+  const device = useDevice();
+  if (device.editor.isMobile) {
+    return (
+      <Footer>
+        <CustomFooter
+          excalidrawAPI={excalidrawAPI}
+          excalidrawLib={excalidrawLib}
+        />
+      </Footer>
+    );
+  }
+  return null;
+};
+export default MobileFooter;

+ 0 - 0
packages/excalidraw/example/sidebar/ExampleSidebar.scss → examples/excalidraw/components/sidebar/ExampleSidebar.scss


+ 2 - 3
packages/excalidraw/example/sidebar/ExampleSidebar.tsx → examples/excalidraw/components/sidebar/ExampleSidebar.tsx

@@ -1,9 +1,8 @@
+import { useState } from "react";
 import "./ExampleSidebar.scss";
 
-const React = window.React;
-
 export default function Sidebar({ children }: { children: React.ReactNode }) {
-  const [open, setOpen] = React.useState(false);
+  const [open, setOpen] = useState(false);
 
   return (
     <>

+ 2 - 2
packages/excalidraw/example/initialData.tsx → examples/excalidraw/initialData.tsx

@@ -1,5 +1,5 @@
-import type { ExcalidrawElementSkeleton } from "../data/transform";
-import type { FileId } from "../element/types";
+import type { ExcalidrawElementSkeleton } from "@excalidraw/excalidraw/data/transform";
+import type { FileId } from "@excalidraw/excalidraw/element/types";
 
 const elements: ExcalidrawElementSkeleton[] = [
   {

+ 13 - 0
examples/excalidraw/package.json

@@ -0,0 +1,13 @@
+{
+  "name": "examples",
+  "version": "1.0.0",
+  "private": true,
+  "dependencies": {
+    "react": "18.2.0",
+    "react-dom": "18.2.0",
+    "@excalidraw/excalidraw": "*"
+  },
+  "devDependencies": {
+    "typescript": "^5"
+  }
+}

+ 3 - 0
examples/excalidraw/tsconfig.json

@@ -0,0 +1,3 @@
+{
+  "extends": "../../tsconfig"
+}

+ 146 - 0
examples/excalidraw/utils.ts

@@ -0,0 +1,146 @@
+import { unstable_batchedUpdates } from "react-dom";
+import { fileOpen as _fileOpen } from "browser-fs-access";
+import type { MIME_TYPES } from "@excalidraw/excalidraw";
+import { AbortError } from "../../packages/excalidraw/errors";
+
+type FILE_EXTENSION = Exclude<keyof typeof MIME_TYPES, "binary">;
+
+const INPUT_CHANGE_INTERVAL_MS = 500;
+
+export type ResolvablePromise<T> = Promise<T> & {
+  resolve: [T] extends [undefined] ? (value?: T) => void : (value: T) => void;
+  reject: (error: Error) => void;
+};
+export const resolvablePromise = <T>() => {
+  let resolve!: any;
+  let reject!: any;
+  const promise = new Promise((_resolve, _reject) => {
+    resolve = _resolve;
+    reject = _reject;
+  });
+  (promise as any).resolve = resolve;
+  (promise as any).reject = reject;
+  return promise as ResolvablePromise<T>;
+};
+
+export const distance2d = (x1: number, y1: number, x2: number, y2: number) => {
+  const xd = x2 - x1;
+  const yd = y2 - y1;
+  return Math.hypot(xd, yd);
+};
+
+export const fileOpen = <M extends boolean | undefined = false>(opts: {
+  extensions?: FILE_EXTENSION[];
+  description: string;
+  multiple?: M;
+}): Promise<M extends false | undefined ? File : File[]> => {
+  // an unsafe TS hack, alas not much we can do AFAIK
+  type RetType = M extends false | undefined ? File : File[];
+
+  const mimeTypes = opts.extensions?.reduce((mimeTypes, type) => {
+    mimeTypes.push(MIME_TYPES[type]);
+
+    return mimeTypes;
+  }, [] as string[]);
+
+  const extensions = opts.extensions?.reduce((acc, ext) => {
+    if (ext === "jpg") {
+      return acc.concat(".jpg", ".jpeg");
+    }
+    return acc.concat(`.${ext}`);
+  }, [] as string[]);
+
+  return _fileOpen({
+    description: opts.description,
+    extensions,
+    mimeTypes,
+    multiple: opts.multiple ?? false,
+    legacySetup: (resolve, reject, input) => {
+      const scheduleRejection = debounce(reject, INPUT_CHANGE_INTERVAL_MS);
+      const focusHandler = () => {
+        checkForFile();
+        document.addEventListener("keyup", scheduleRejection);
+        document.addEventListener("pointerup", scheduleRejection);
+        scheduleRejection();
+      };
+      const checkForFile = () => {
+        // this hack might not work when expecting multiple files
+        if (input.files?.length) {
+          const ret = opts.multiple ? [...input.files] : input.files[0];
+          resolve(ret as RetType);
+        }
+      };
+      requestAnimationFrame(() => {
+        window.addEventListener("focus", focusHandler);
+      });
+      const interval = window.setInterval(() => {
+        checkForFile();
+      }, INPUT_CHANGE_INTERVAL_MS);
+      return (rejectPromise) => {
+        clearInterval(interval);
+        scheduleRejection.cancel();
+        window.removeEventListener("focus", focusHandler);
+        document.removeEventListener("keyup", scheduleRejection);
+        document.removeEventListener("pointerup", scheduleRejection);
+        if (rejectPromise) {
+          // so that something is shown in console if we need to debug this
+          console.warn("Opening the file was canceled (legacy-fs).");
+          rejectPromise(new AbortError());
+        }
+      };
+    },
+  }) as Promise<RetType>;
+};
+
+export const debounce = <T extends any[]>(
+  fn: (...args: T) => void,
+  timeout: number,
+) => {
+  let handle = 0;
+  let lastArgs: T | null = null;
+  const ret = (...args: T) => {
+    lastArgs = args;
+    clearTimeout(handle);
+    handle = window.setTimeout(() => {
+      lastArgs = null;
+      fn(...args);
+    }, timeout);
+  };
+  ret.flush = () => {
+    clearTimeout(handle);
+    if (lastArgs) {
+      const _lastArgs = lastArgs;
+      lastArgs = null;
+      fn(..._lastArgs);
+    }
+  };
+  ret.cancel = () => {
+    lastArgs = null;
+    clearTimeout(handle);
+  };
+  return ret;
+};
+
+export const withBatchedUpdates = <
+  TFunction extends ((event: any) => void) | (() => void),
+>(
+  func: Parameters<TFunction>["length"] extends 0 | 1 ? TFunction : never,
+) =>
+  ((event) => {
+    unstable_batchedUpdates(func as TFunction, event);
+  }) as TFunction;
+
+/**
+ * barches React state updates and throttles the calls to a single call per
+ * animation frame
+ */
+export const withBatchedUpdatesThrottled = <
+  TFunction extends ((event: any) => void) | (() => void),
+>(
+  func: Parameters<TFunction>["length"] extends 0 | 1 ? TFunction : never,
+) => {
+  // @ts-ignore
+  return throttleRAF<Parameters<TFunction>>(((event) => {
+    unstable_batchedUpdates(func, event);
+  }) as TFunction);
+};

+ 36 - 0
examples/excalidraw/with-nextjs/.gitignore

@@ -0,0 +1,36 @@
+# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+
+# dependencies
+/node_modules
+/.pnp
+.pnp.js
+.yarn/install-state.gz
+
+# testing
+/coverage
+
+# next.js
+/.next/
+/out/
+
+# production
+/build
+
+# misc
+.DS_Store
+*.pem
+
+# debug
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# local env files
+.env*.local
+
+# vercel
+.vercel
+
+# typescript
+*.tsbuildinfo
+next-env.d.ts

+ 36 - 0
examples/excalidraw/with-nextjs/README.md

@@ -0,0 +1,36 @@
+This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
+
+## Getting Started
+
+First, run the development server:
+
+```bash
+npm run dev
+# or
+yarn dev
+# or
+pnpm dev
+# or
+bun dev
+```
+
+Open [http://localhost:3000](http://localhost:3005) with your browser to see the result.
+
+You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
+
+This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
+
+## Learn More
+
+To learn more about Next.js, take a look at the following resources:
+
+- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
+- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
+
+You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
+
+## Deploy on Vercel
+
+The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
+
+Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.

+ 12 - 0
examples/excalidraw/with-nextjs/next.config.js

@@ -0,0 +1,12 @@
+/** @type {import('next').NextConfig} */
+const nextConfig = {
+  distDir: "build",
+  typescript: {
+    // The ts config doesn't work with `jsx: preserve" and if updated to `react-jsx` it gets ovewritten by next js throwing ts errors hence I am ignoring build errors until this is fixed.
+    ignoreBuildErrors: true,
+  },
+  // This is needed as in pages router the code for importing types throws error as its outside next js app
+  transpilePackages: ["../"],
+};
+
+module.exports = nextConfig;

+ 25 - 0
examples/excalidraw/with-nextjs/package.json

@@ -0,0 +1,25 @@
+{
+  "name": "with-nextjs",
+  "version": "0.1.0",
+  "private": true,
+  "scripts": {
+    "build:workspace": "yarn workspace @excalidraw/excalidraw run build:esm",
+    "dev": "yarn build:workspace && next dev -p 3005",
+    "build": "yarn build:workspace && next build",
+    "start": "next start -p 3006",
+    "lint": "next lint"
+  },
+  "dependencies": {
+    "@excalidraw/excalidraw": "*",
+    "next": "14.1",
+    "react": "^18",
+    "react-dom": "^18"
+  },
+  "devDependencies": {
+    "@types/node": "^20",
+    "@types/react": "^18",
+    "@types/react-dom": "^18",
+    "path2d-polyfill": "2.0.1",
+    "typescript": "^5"
+  }
+}

+ 0 - 0
packages/excalidraw/example/public/images/doremon.png → examples/excalidraw/with-nextjs/public/images/doremon.png


+ 0 - 0
packages/excalidraw/example/public/images/excalibot.png → examples/excalidraw/with-nextjs/public/images/excalibot.png


+ 0 - 0
packages/excalidraw/example/public/images/pika.jpeg → examples/excalidraw/with-nextjs/public/images/pika.jpeg


+ 0 - 0
packages/excalidraw/example/public/images/rocket.jpeg → examples/excalidraw/with-nextjs/public/images/rocket.jpeg


BIN
examples/excalidraw/with-nextjs/src/app/favicon.ico


+ 11 - 0
examples/excalidraw/with-nextjs/src/app/layout.tsx

@@ -0,0 +1,11 @@
+export default function RootLayout({
+  children,
+}: {
+  children: React.ReactNode;
+}) {
+  return (
+    <html lang="en">
+      <body>{children}</body>
+    </html>
+  );
+}

+ 23 - 0
examples/excalidraw/with-nextjs/src/app/page.tsx

@@ -0,0 +1,23 @@
+import dynamic from "next/dynamic";
+import "../common.scss";
+
+// Since client components get prerenderd on server as well hence importing the excalidraw stuff dynamically
+// with ssr false
+const ExcalidrawWithClientOnly = dynamic(
+  async () => (await import("../excalidrawWrapper")).default,
+  {
+    ssr: false,
+  },
+);
+
+export default function Page() {
+  return (
+    <>
+      <a href="/excalidraw-in-pages">Switch to Pages router</a>
+      <h1 className="page-title">App Router</h1>
+
+      {/* @ts-expect-error - https://github.com/vercel/next.js/issues/42292 */}
+      <ExcalidrawWithClientOnly />
+    </>
+  );
+}

+ 15 - 0
examples/excalidraw/with-nextjs/src/common.scss

@@ -0,0 +1,15 @@
+* {
+  box-sizing: border-box;
+  font-family: sans-serif;
+}
+
+a {
+  color: #1c7ed6;
+  font-size: 20px;
+  text-decoration: none;
+  font-weight: 550;
+}
+
+.page-title {
+  text-align: center;
+}

+ 22 - 0
examples/excalidraw/with-nextjs/src/excalidrawWrapper.tsx

@@ -0,0 +1,22 @@
+"use client";
+import * as excalidrawLib from "@excalidraw/excalidraw";
+import { Excalidraw } from "@excalidraw/excalidraw";
+import App from "../../components/App";
+
+import "@excalidraw/excalidraw/index.css";
+
+const ExcalidrawWrapper: React.FC = () => {
+  return (
+    <>
+      <App
+        appTitle={"Excalidraw with Nextjs Example"}
+        useCustom={(api: any, args?: any[]) => {}}
+        excalidrawLib={excalidrawLib}
+      >
+        <Excalidraw />
+      </App>
+    </>
+  );
+};
+
+export default ExcalidrawWrapper;

+ 22 - 0
examples/excalidraw/with-nextjs/src/pages/excalidraw-in-pages.tsx

@@ -0,0 +1,22 @@
+import dynamic from "next/dynamic";
+import "../common.scss";
+
+// Since client components get prerenderd on server as well hence importing the excalidraw stuff dynamically
+// with ssr false
+const Excalidraw = dynamic(
+  async () => (await import("../excalidrawWrapper")).default,
+  {
+    ssr: false,
+  },
+);
+
+export default function Page() {
+  return (
+    <>
+      <a href="/">Switch to App router</a>
+      <h1 className="page-title">Pages Router</h1>
+      {/* @ts-expect-error - https://github.com/vercel/next.js/issues/42292 */}
+      <Excalidraw />
+    </>
+  );
+}

+ 28 - 0
examples/excalidraw/with-nextjs/tsconfig.json

@@ -0,0 +1,28 @@
+{
+  "compilerOptions": {
+    "target": "es5",
+    "lib": ["dom", "dom.iterable", "esnext"],
+    "allowJs": true,
+    "skipLibCheck": true,
+    "strict": true,
+    "noEmit": true,
+    "esModuleInterop": true,
+    "module": "esnext",
+    "moduleResolution": "node",
+    "resolveJsonModule": true,
+    "isolatedModules": true,
+    "jsx": "preserve",
+    "incremental": true,
+    "plugins": [
+      {
+        "name": "next"
+      }
+    ],
+    "paths": {
+      "@/*": ["./src/*"]
+    },
+    "forceConsistentCasingInFileNames": true
+  },
+  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "build/types/**/*.ts"],
+  "exclude": ["node_modules"]
+}

+ 3 - 0
examples/excalidraw/with-nextjs/vercel.json

@@ -0,0 +1,3 @@
+{
+  "outputDirectory": "build"
+}

+ 252 - 0
examples/excalidraw/with-nextjs/yarn.lock

@@ -0,0 +1,252 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@excalidraw/excalidraw@workspace:^":
+  version "0.17.2"
+  resolved "https://registry.yarnpkg.com/@excalidraw/excalidraw/-/excalidraw-0.17.2.tgz#9a636a1e6bb3c88c5883347d3a7e75e9cce8ab96"
+  integrity sha512-7pqUWD8+mPjDhF4XxG3gw4rvE2JGaLW3Vss5UZfTbITPxAtFaGEc1K081bncitnaYhUwN9ENJE0i87QB3poDwQ==
+
+"@next/[email protected]":
+  version "14.0.4"
+  resolved "https://registry.yarnpkg.com/@next/env/-/env-14.0.4.tgz#d5cda0c4a862d70ae760e58c0cd96a8899a2e49a"
+  integrity sha512-irQnbMLbUNQpP1wcE5NstJtbuA/69kRfzBrpAD7Gsn8zm/CY6YQYc3HQBz8QPxwISG26tIm5afvvVbu508oBeQ==
+
+"@next/[email protected]":
+  version "14.0.4"
+  resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.0.4.tgz#27b1854c2cd04eb1d5e75081a1a792ad91526618"
+  integrity sha512-mF05E/5uPthWzyYDyptcwHptucf/jj09i2SXBPwNzbgBNc+XnwzrL0U6BmPjQeOL+FiB+iG1gwBeq7mlDjSRPg==
+
+"@next/[email protected]":
+  version "14.0.4"
+  resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.0.4.tgz#9940c449e757d0ee50bb9e792d2600cc08a3eb3b"
+  integrity sha512-IZQ3C7Bx0k2rYtrZZxKKiusMTM9WWcK5ajyhOZkYYTCc8xytmwSzR1skU7qLgVT/EY9xtXDG0WhY6fyujnI3rw==
+
+"@next/[email protected]":
+  version "14.0.4"
+  resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.0.4.tgz#0eafd27c8587f68ace7b4fa80695711a8434de21"
+  integrity sha512-VwwZKrBQo/MGb1VOrxJ6LrKvbpo7UbROuyMRvQKTFKhNaXjUmKTu7wxVkIuCARAfiI8JpaWAnKR+D6tzpCcM4w==
+
+"@next/[email protected]":
+  version "14.0.4"
+  resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.4.tgz#2b0072adb213f36dada5394ea67d6e82069ae7dd"
+  integrity sha512-8QftwPEW37XxXoAwsn+nXlodKWHfpMaSvt81W43Wh8dv0gkheD+30ezWMcFGHLI71KiWmHK5PSQbTQGUiidvLQ==
+
+"@next/[email protected]":
+  version "14.0.4"
+  resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.4.tgz#68c67d20ebc8e3f6ced6ff23a4ba2a679dbcec32"
+  integrity sha512-/s/Pme3VKfZAfISlYVq2hzFS8AcAIOTnoKupc/j4WlvF6GQ0VouS2Q2KEgPuO1eMBwakWPB1aYFIA4VNVh667A==
+
+"@next/[email protected]":
+  version "14.0.4"
+  resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.4.tgz#67cd81b42fb2caf313f7992fcf6d978af55a1247"
+  integrity sha512-m8z/6Fyal4L9Bnlxde5g2Mfa1Z7dasMQyhEhskDATpqr+Y0mjOBZcXQ7G5U+vgL22cI4T7MfvgtrM2jdopqWaw==
+
+"@next/[email protected]":
+  version "14.0.4"
+  resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.4.tgz#be06585906b195d755ceda28f33c633e1443f1a3"
+  integrity sha512-7Wv4PRiWIAWbm5XrGz3D8HUkCVDMMz9igffZG4NB1p4u1KoItwx9qjATHz88kwCEal/HXmbShucaslXCQXUM5w==
+
+"@next/[email protected]":
+  version "14.0.4"
+  resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.4.tgz#e76cabefa9f2d891599c3d85928475bd8d3f6600"
+  integrity sha512-zLeNEAPULsl0phfGb4kdzF/cAVIfaC7hY+kt0/d+y9mzcZHsMS3hAS829WbJ31DkSlVKQeHEjZHIdhN+Pg7Gyg==
+
+"@next/[email protected]":
+  version "14.0.4"
+  resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.0.4.tgz#e74892f1a9ccf41d3bf5979ad6d3d77c07b9cba1"
+  integrity sha512-yEh2+R8qDlDCjxVpzOTEpBLQTEFAcP2A8fUFLaWNap9GitYKkKv1//y2S6XY6zsR4rCOPRpU7plYDR+az2n30A==
+
+"@swc/[email protected]":
+  version "0.5.2"
+  resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.2.tgz#85ea0c76450b61ad7d10a37050289eded783c27d"
+  integrity sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==
+  dependencies:
+    tslib "^2.4.0"
+
+"@types/node@^20":
+  version "20.11.0"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.0.tgz#8e0b99e70c0c1ade1a86c4a282f7b7ef87c9552f"
+  integrity sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ==
+  dependencies:
+    undici-types "~5.26.4"
+
+"@types/prop-types@*":
+  version "15.7.11"
+  resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.11.tgz#2596fb352ee96a1379c657734d4b913a613ad563"
+  integrity sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==
+
+"@types/react-dom@^18":
+  version "18.2.18"
+  resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.18.tgz#16946e6cd43971256d874bc3d0a72074bb8571dd"
+  integrity sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==
+  dependencies:
+    "@types/react" "*"
+
+"@types/react@*", "@types/react@^18":
+  version "18.2.47"
+  resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.47.tgz#85074b27ab563df01fbc3f68dc64bf7050b0af40"
+  integrity sha512-xquNkkOirwyCgoClNk85BjP+aqnIS+ckAJ8i37gAbDs14jfW/J23f2GItAf33oiUPQnqNMALiFeoM9Y5mbjpVQ==
+  dependencies:
+    "@types/prop-types" "*"
+    "@types/scheduler" "*"
+    csstype "^3.0.2"
+
+"@types/scheduler@*":
+  version "0.16.8"
+  resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.8.tgz#ce5ace04cfeabe7ef87c0091e50752e36707deff"
+  integrity sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==
+
[email protected]:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893"
+  integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==
+  dependencies:
+    streamsearch "^1.1.0"
+
+caniuse-lite@^1.0.30001406:
+  version "1.0.30001576"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001576.tgz#893be772cf8ee6056d6c1e2d07df365b9ec0a5c4"
+  integrity sha512-ff5BdakGe2P3SQsMsiqmt1Lc8221NR1VzHj5jXN5vBny9A6fpze94HiVV/n7XRosOlsShJcvMv5mdnpjOGCEgg==
+
[email protected]:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1"
+  integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==
+
+csstype@^3.0.2:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
+  integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==
+
+glob-to-regexp@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
+  integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
+
+graceful-fs@^4.1.2, graceful-fs@^4.2.11:
+  version "4.2.11"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
+  integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
+
+"js-tokens@^3.0.0 || ^4.0.0":
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+  integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+loose-envify@^1.1.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
+  integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
+  dependencies:
+    js-tokens "^3.0.0 || ^4.0.0"
+
+nanoid@^3.3.6:
+  version "3.3.7"
+  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
+  integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
+
[email protected]:
+  version "14.0.4"
+  resolved "https://registry.yarnpkg.com/next/-/next-14.0.4.tgz#bf00b6f835b20d10a5057838fa2dfced1d0d84dc"
+  integrity sha512-qbwypnM7327SadwFtxXnQdGiKpkuhaRLE2uq62/nRul9cj9KhQ5LhHmlziTNqUidZotw/Q1I9OjirBROdUJNgA==
+  dependencies:
+    "@next/env" "14.0.4"
+    "@swc/helpers" "0.5.2"
+    busboy "1.6.0"
+    caniuse-lite "^1.0.30001406"
+    graceful-fs "^4.2.11"
+    postcss "8.4.31"
+    styled-jsx "5.1.1"
+    watchpack "2.4.0"
+  optionalDependencies:
+    "@next/swc-darwin-arm64" "14.0.4"
+    "@next/swc-darwin-x64" "14.0.4"
+    "@next/swc-linux-arm64-gnu" "14.0.4"
+    "@next/swc-linux-arm64-musl" "14.0.4"
+    "@next/swc-linux-x64-gnu" "14.0.4"
+    "@next/swc-linux-x64-musl" "14.0.4"
+    "@next/swc-win32-arm64-msvc" "14.0.4"
+    "@next/swc-win32-ia32-msvc" "14.0.4"
+    "@next/swc-win32-x64-msvc" "14.0.4"
+
[email protected]:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz#24c554a738f42700d6961992bf5f1049672f2391"
+  integrity sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==
+
+picocolors@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
+  integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
+
[email protected]:
+  version "8.4.31"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d"
+  integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==
+  dependencies:
+    nanoid "^3.3.6"
+    picocolors "^1.0.0"
+    source-map-js "^1.0.2"
+
+react-dom@^18:
+  version "18.2.0"
+  resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
+  integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
+  dependencies:
+    loose-envify "^1.1.0"
+    scheduler "^0.23.0"
+
+react@^18:
+  version "18.2.0"
+  resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
+  integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
+  dependencies:
+    loose-envify "^1.1.0"
+
+scheduler@^0.23.0:
+  version "0.23.0"
+  resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
+  integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
+  dependencies:
+    loose-envify "^1.1.0"
+
+source-map-js@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
+  integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
+
+streamsearch@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
+  integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
+
[email protected]:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.1.tgz#839a1c3aaacc4e735fed0781b8619ea5d0009d1f"
+  integrity sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==
+  dependencies:
+    client-only "0.0.1"
+
+tslib@^2.4.0:
+  version "2.6.2"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
+  integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
+
+typescript@^5:
+  version "5.3.3"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37"
+  integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==
+
+undici-types@~5.26.4:
+  version "5.26.5"
+  resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617"
+  integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==
+
[email protected]:
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d"
+  integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==
+  dependencies:
+    glob-to-regexp "^0.4.1"
+    graceful-fs "^4.1.2"

+ 5 - 5
packages/excalidraw/example/public/index.html → examples/excalidraw/with-script-in-browser/index.html

@@ -13,20 +13,20 @@
       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/[email protected]/umd/react.development.js"></script>
-    <script src="https://unpkg.com/[email protected]/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";
+      import * as ExcalidrawLib from "@excalidraw/excalidraw";
+
+      console.log(ExcalidrawLib);
       window.ExcalidrawLib = ExcalidrawLib;
     </script>
-    <script type="module" src="bundle.js"></script>
+    <script type="module" src="index.tsx"></script>
   </body>
 </html>

+ 28 - 0
examples/excalidraw/with-script-in-browser/index.tsx

@@ -0,0 +1,28 @@
+import App from "../components/App";
+import React, { StrictMode } from "react";
+import { createRoot } from "react-dom/client";
+
+import type * as TExcalidraw from "@excalidraw/excalidraw";
+
+import "@excalidraw/excalidraw/index.css";
+
+declare global {
+  interface Window {
+    ExcalidrawLib: typeof TExcalidraw;
+  }
+}
+
+const rootElement = document.getElementById("root")!;
+const root = createRoot(rootElement);
+const { Excalidraw } = window.ExcalidrawLib;
+root.render(
+  <StrictMode>
+    <App
+      appTitle={"Excalidraw Example"}
+      useCustom={(api: any, args?: any[]) => {}}
+      excalidrawLib={window.ExcalidrawLib}
+    >
+      <Excalidraw />
+    </App>
+  </StrictMode>,
+);

+ 19 - 0
examples/excalidraw/with-script-in-browser/package.json

@@ -0,0 +1,19 @@
+{
+  "name": "with-script-in-browser",
+  "version": "1.0.0",
+  "private": true,
+  "dependencies": {
+    "react": "18.2.0",
+    "react-dom": "18.2.0",
+    "@excalidraw/excalidraw": "*"
+  },
+  "devDependencies": {
+    "vite": "5.0.6",
+    "typescript": "^5"
+  },
+  "scripts": {
+    "start": "yarn workspace @excalidraw/excalidraw run build:esm && vite",
+    "build": "yarn workspace @excalidraw/excalidraw run build:esm && vite build",
+    "build:preview": "yarn build && vite preview --port 5002"
+  }
+}

BIN
examples/excalidraw/with-script-in-browser/public/images/doremon.png


BIN
examples/excalidraw/with-script-in-browser/public/images/excalibot.png


BIN
examples/excalidraw/with-script-in-browser/public/images/pika.jpeg


BIN
examples/excalidraw/with-script-in-browser/public/images/rocket.jpeg


+ 1 - 1
packages/excalidraw/vercel.json → examples/excalidraw/with-script-in-browser/vercel.json

@@ -1,4 +1,4 @@
 {
-  "outputDirectory": "example/public",
+  "outputDirectory": "dist",
   "installCommand": "yarn install"
 }

+ 11 - 0
examples/excalidraw/with-script-in-browser/vite.config.mts

@@ -0,0 +1,11 @@
+import { defineConfig } from "vite";
+
+// https://vitejs.dev/config/
+export default defineConfig({
+  server: {
+    port: 3001,
+    // open the browser
+    open: true,
+  },
+  publicDir: "public",
+});

+ 313 - 0
examples/excalidraw/yarn.lock

@@ -0,0 +1,313 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.11.tgz#2acd20be6d4f0458bc8c784103495ff24f13b1d3"
+  integrity sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.19.11.tgz#b45d000017385c9051a4f03e17078abb935be220"
+  integrity sha512-aiu7K/5JnLj//KOnOfEZ0D90obUkRzDMyqd/wNAUQ34m4YUPVhRZpnqKV9uqDGxT7cToSDnIHsGooyIczu9T+Q==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.19.11.tgz#f46f55414e1c3614ac682b29977792131238164c"
+  integrity sha512-5OVapq0ClabvKvQ58Bws8+wkLCV+Rxg7tUVbo9xu034Nm536QTII4YzhaFriQ7rMrorfnFKUsArD2lqKbFY4vw==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.19.11.tgz#bfc01e91740b82011ef503c48f548950824922b2"
+  integrity sha512-eccxjlfGw43WYoY9QgB82SgGgDbibcqyDTlk3l3C0jOVHKxrjdc9CTwDUQd0vkvYg5um0OH+GpxYvp39r+IPOg==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.19.11.tgz#533fb7f5a08c37121d82c66198263dcc1bed29bf"
+  integrity sha512-ETp87DRWuSt9KdDVkqSoKoLFHYTrkyz2+65fj9nfXsaV3bMhTCjtQfw3y+um88vGRKRiF7erPrh/ZuIdLUIVxQ==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.19.11.tgz#62f3819eff7e4ddc656b7c6815a31cf9a1e7d98e"
+  integrity sha512-fkFUiS6IUK9WYUO/+22omwetaSNl5/A8giXvQlcinLIjVkxwTLSktbF5f/kJMftM2MJp9+fXqZ5ezS7+SALp4g==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.11.tgz#d478b4195aa3ca44160272dab85ef8baf4175b4a"
+  integrity sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.19.11.tgz#7bdcc1917409178257ca6a1a27fe06e797ec18a2"
+  integrity sha512-JkUqn44AffGXitVI6/AbQdoYAq0TEullFdqcMY/PCUZ36xJ9ZJRtQabzMA+Vi7r78+25ZIBosLTOKnUXBSi1Kw==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.11.tgz#58ad4ff11685fcc735d7ff4ca759ab18fcfe4545"
+  integrity sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.19.11.tgz#ce82246d873b5534d34de1e5c1b33026f35e60e3"
+  integrity sha512-3CRkr9+vCV2XJbjwgzjPtO8T0SZUmRZla+UL1jw+XqHZPkPgZiyWvbDvl9rqAN8Zl7qJF0O/9ycMtjU67HN9/Q==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.11.tgz#cbae1f313209affc74b80f4390c4c35c6ab83fa4"
+  integrity sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.11.tgz#5f32aead1c3ec8f4cccdb7ed08b166224d4e9121"
+  integrity sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.19.11.tgz#38eecf1cbb8c36a616261de858b3c10d03419af9"
+  integrity sha512-B5x9j0OgjG+v1dF2DkH34lr+7Gmv0kzX6/V0afF41FkPMMqaQ77pH7CrhWeR22aEeHKaeZVtZ6yFwlxOKPVFyg==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.11.tgz#9c5725a94e6ec15b93195e5a6afb821628afd912"
+  integrity sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.19.11.tgz#2dc4486d474a2a62bbe5870522a9a600e2acb916"
+  integrity sha512-f3DY++t94uVg141dozDu4CCUkYW+09rWtaWfnb3bqe4w5NqmZd6nPVBm+qbz7WaHZCoqXqHz5p6CM6qv3qnSSQ==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.11.tgz#4ad8567df48f7dd4c71ec5b1753b6f37561a65a8"
+  integrity sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.11.tgz#b7390c4d5184f203ebe7ddaedf073df82a658766"
+  integrity sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.19.11.tgz#d633c09492a1721377f3bccedb2d821b911e813d"
+  integrity sha512-13jvrQZJc3P230OhU8xgwUnDeuC/9egsjTkXN49b3GcS5BKvJqZn86aGM8W9pd14Kd+u7HuFBMVtrNGhh6fHEQ==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.11.tgz#17388c76e2f01125bf831a68c03a7ffccb65d1a2"
+  integrity sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.11.tgz#e320636f00bb9f4fdf3a80e548cb743370d41767"
+  integrity sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.11.tgz#c778b45a496e90b6fc373e2a2bb072f1441fe0ee"
+  integrity sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.19.11.tgz#481a65fee2e5cce74ec44823e6b09ecedcc5194c"
+  integrity sha512-6YOrWS+sDJDmshdBIQU+Uoyh7pQKrdykdefC1avn76ss5c+RN6gut3LZA4E2cH5xUEp5/cA0+YxRaVtRAb0xBg==
+
+"@esbuild/[email protected]":
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.19.11.tgz#a5d300008960bb39677c46bf16f53ec70d8dee04"
+  integrity sha512-vfkhltrjCAb603XaFhqhAF4LGDi2M4OrCRrFusyQ+iTLQ/o60QQXxc9cZC/FFpihBI9N1Grn6SMKVJ4KP7Fuiw==
+
+"@rollup/[email protected]":
+  version "4.9.5"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.5.tgz#b752b6c88a14ccfcbdf3f48c577ccc3a7f0e66b9"
+  integrity sha512-idWaG8xeSRCfRq9KpRysDHJ/rEHBEXcHuJ82XY0yYFIWnLMjZv9vF/7DOq8djQ2n3Lk6+3qfSH8AqlmHlmi1MA==
+
+"@rollup/[email protected]":
+  version "4.9.5"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.5.tgz#33757c3a448b9ef77b6f6292d8b0ec45c87e9c1a"
+  integrity sha512-f14d7uhAMtsCGjAYwZGv6TwuS3IFaM4ZnGMUn3aCBgkcHAYErhV1Ad97WzBvS2o0aaDv4mVz+syiN0ElMyfBPg==
+
+"@rollup/[email protected]":
+  version "4.9.5"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.5.tgz#5234ba62665a3f443143bc8bcea9df2cc58f55fb"
+  integrity sha512-ndoXeLx455FffL68OIUrVr89Xu1WLzAG4n65R8roDlCoYiQcGGg6MALvs2Ap9zs7AHg8mpHtMpwC8jBBjZrT/w==
+
+"@rollup/[email protected]":
+  version "4.9.5"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.5.tgz#981256c054d3247b83313724938d606798a919d1"
+  integrity sha512-UmElV1OY2m/1KEEqTlIjieKfVwRg0Zwg4PLgNf0s3glAHXBN99KLpw5A5lrSYCa1Kp63czTpVll2MAqbZYIHoA==
+
+"@rollup/[email protected]":
+  version "4.9.5"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.5.tgz#120678a5a2b3a283a548dbb4d337f9187a793560"
+  integrity sha512-Q0LcU61v92tQB6ae+udZvOyZ0wfpGojtAKrrpAaIqmJ7+psq4cMIhT/9lfV6UQIpeItnq/2QDROhNLo00lOD1g==
+
+"@rollup/[email protected]":
+  version "4.9.5"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.5.tgz#c99d857e2372ece544b6f60b85058ad259f64114"
+  integrity sha512-dkRscpM+RrR2Ee3eOQmRWFjmV/payHEOrjyq1VZegRUa5OrZJ2MAxBNs05bZuY0YCtpqETDy1Ix4i/hRqX98cA==
+
+"@rollup/[email protected]":
+  version "4.9.5"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.5.tgz#3064060f568a5718c2a06858cd6e6d24f2ff8632"
+  integrity sha512-QaKFVOzzST2xzY4MAmiDmURagWLFh+zZtttuEnuNn19AiZ0T3fhPyjPPGwLNdiDT82ZE91hnfJsUiDwF9DClIQ==
+
+"@rollup/[email protected]":
+  version "4.9.5"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.5.tgz#987d30b5d2b992fff07d055015991a57ff55fbad"
+  integrity sha512-HeGqmRJuyVg6/X6MpE2ur7GbymBPS8Np0S/vQFHDmocfORT+Zt76qu+69NUoxXzGqVP1pzaY6QIi0FJWLC3OPA==
+
+"@rollup/[email protected]":
+  version "4.9.5"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.5.tgz#85946ee4d068bd12197aeeec2c6f679c94978a49"
+  integrity sha512-Dq1bqBdLaZ1Gb/l2e5/+o3B18+8TI9ANlA1SkejZqDgdU/jK/ThYaMPMJpVMMXy2uRHvGKbkz9vheVGdq3cJfA==
+
+"@rollup/[email protected]":
+  version "4.9.5"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.5.tgz#fe0b20f9749a60eb1df43d20effa96c756ddcbd4"
+  integrity sha512-ezyFUOwldYpj7AbkwyW9AJ203peub81CaAIVvckdkyH8EvhEIoKzaMFJj0G4qYJ5sw3BpqhFrsCc30t54HV8vg==
+
+"@rollup/[email protected]":
+  version "4.9.5"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.5.tgz#422661ef0e16699a234465d15b2c1089ef963b2a"
+  integrity sha512-aHSsMnUw+0UETB0Hlv7B/ZHOGY5bQdwMKJSzGfDfvyhnpmVxLMGnQPGNE9wgqkLUs3+gbG1Qx02S2LLfJ5GaRQ==
+
+"@rollup/[email protected]":
+  version "4.9.5"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.5.tgz#7b73a145891c202fbcc08759248983667a035d85"
+  integrity sha512-AiqiLkb9KSf7Lj/o1U3SEP9Zn+5NuVKgFdRIZkvd4N0+bYrTOovVd0+LmYCPQGbocT4kvFyK+LXCDiXPBF3fyA==
+
+"@rollup/[email protected]":
+  version "4.9.5"
+  resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.5.tgz#10491ccf4f63c814d4149e0316541476ea603602"
+  integrity sha512-1q+mykKE3Vot1kaFJIDoUFv5TuW+QQVaf2FmTT9krg86pQrGStOSJJ0Zil7CFagyxDuouTepzt5Y5TVzyajOdQ==
+
+"@types/[email protected]":
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4"
+  integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==
+
+esbuild@^0.19.3:
+  version "0.19.11"
+  resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.19.11.tgz#4a02dca031e768b5556606e1b468fe72e3325d96"
+  integrity sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA==
+  optionalDependencies:
+    "@esbuild/aix-ppc64" "0.19.11"
+    "@esbuild/android-arm" "0.19.11"
+    "@esbuild/android-arm64" "0.19.11"
+    "@esbuild/android-x64" "0.19.11"
+    "@esbuild/darwin-arm64" "0.19.11"
+    "@esbuild/darwin-x64" "0.19.11"
+    "@esbuild/freebsd-arm64" "0.19.11"
+    "@esbuild/freebsd-x64" "0.19.11"
+    "@esbuild/linux-arm" "0.19.11"
+    "@esbuild/linux-arm64" "0.19.11"
+    "@esbuild/linux-ia32" "0.19.11"
+    "@esbuild/linux-loong64" "0.19.11"
+    "@esbuild/linux-mips64el" "0.19.11"
+    "@esbuild/linux-ppc64" "0.19.11"
+    "@esbuild/linux-riscv64" "0.19.11"
+    "@esbuild/linux-s390x" "0.19.11"
+    "@esbuild/linux-x64" "0.19.11"
+    "@esbuild/netbsd-x64" "0.19.11"
+    "@esbuild/openbsd-x64" "0.19.11"
+    "@esbuild/sunos-x64" "0.19.11"
+    "@esbuild/win32-arm64" "0.19.11"
+    "@esbuild/win32-ia32" "0.19.11"
+    "@esbuild/win32-x64" "0.19.11"
+
+fsevents@~2.3.2, fsevents@~2.3.3:
+  version "2.3.3"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
+  integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==
+
+"js-tokens@^3.0.0 || ^4.0.0":
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+  integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+loose-envify@^1.1.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
+  integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
+  dependencies:
+    js-tokens "^3.0.0 || ^4.0.0"
+
+nanoid@^3.3.7:
+  version "3.3.7"
+  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
+  integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==
+
+picocolors@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
+  integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
+
+postcss@^8.4.32:
+  version "8.4.33"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.33.tgz#1378e859c9f69bf6f638b990a0212f43e2aaa742"
+  integrity sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==
+  dependencies:
+    nanoid "^3.3.7"
+    picocolors "^1.0.0"
+    source-map-js "^1.0.2"
+
[email protected]:
+  version "18.2.0"
+  resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
+  integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
+  dependencies:
+    loose-envify "^1.1.0"
+    scheduler "^0.23.0"
+
[email protected]:
+  version "18.2.0"
+  resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
+  integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
+  dependencies:
+    loose-envify "^1.1.0"
+
+rollup@^4.2.0:
+  version "4.9.5"
+  resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.9.5.tgz#62999462c90f4c8b5d7c38fc7161e63b29101b05"
+  integrity sha512-E4vQW0H/mbNMw2yLSqJyjtkHY9dslf/p0zuT1xehNRqUTBOFMqEjguDvqhXr7N7r/4ttb2jr4T41d3dncmIgbQ==
+  dependencies:
+    "@types/estree" "1.0.5"
+  optionalDependencies:
+    "@rollup/rollup-android-arm-eabi" "4.9.5"
+    "@rollup/rollup-android-arm64" "4.9.5"
+    "@rollup/rollup-darwin-arm64" "4.9.5"
+    "@rollup/rollup-darwin-x64" "4.9.5"
+    "@rollup/rollup-linux-arm-gnueabihf" "4.9.5"
+    "@rollup/rollup-linux-arm64-gnu" "4.9.5"
+    "@rollup/rollup-linux-arm64-musl" "4.9.5"
+    "@rollup/rollup-linux-riscv64-gnu" "4.9.5"
+    "@rollup/rollup-linux-x64-gnu" "4.9.5"
+    "@rollup/rollup-linux-x64-musl" "4.9.5"
+    "@rollup/rollup-win32-arm64-msvc" "4.9.5"
+    "@rollup/rollup-win32-ia32-msvc" "4.9.5"
+    "@rollup/rollup-win32-x64-msvc" "4.9.5"
+    fsevents "~2.3.2"
+
+scheduler@^0.23.0:
+  version "0.23.0"
+  resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
+  integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
+  dependencies:
+    loose-envify "^1.1.0"
+
+source-map-js@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
+  integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
+
[email protected]:
+  version "5.0.6"
+  resolved "https://registry.yarnpkg.com/vite/-/vite-5.0.6.tgz#f9e13503a4c5ccd67312c67803dec921f3bdea7c"
+  integrity sha512-MD3joyAEBtV7QZPl2JVVUai6zHms3YOmLR+BpMzLlX2Yzjfcc4gTgNi09d/Rua3F4EtC8zdwPU8eQYyib4vVMQ==
+  dependencies:
+    esbuild "^0.19.3"
+    postcss "^8.4.32"
+    rollup "^4.2.0"
+  optionalDependencies:
+    fsevents "~2.3.3"

+ 3 - 1
package.json

@@ -4,7 +4,9 @@
   "workspaces": [
     "excalidraw-app",
     "packages/excalidraw",
-    "packages/utils"
+    "packages/utils",
+    "examples/excalidraw",
+    "examples/excalidraw/*"
   ],
   "dependencies": {
     "@excalidraw/random-username": "1.0.0",

+ 0 - 2
packages/excalidraw/.gitignore

@@ -1,4 +1,2 @@
 node_modules
 types
-bundle.js
-bundle.css

+ 4 - 1
packages/excalidraw/components/App.tsx

@@ -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;

+ 0 - 1
packages/excalidraw/constants.ts

@@ -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);

+ 0 - 20
packages/excalidraw/example/MobileFooter.tsx

@@ -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;

+ 0 - 17
packages/excalidraw/example/index.tsx

@@ -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>,
-);

+ 8 - 1
packages/excalidraw/index.tsx

@@ -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,

+ 0 - 1
packages/excalidraw/renderer/renderScene.ts

@@ -82,7 +82,6 @@ import {
   getTargetFrame,
   isElementInFrame,
 } from "../frame";
-import "canvas-roundrect-polyfill";
 
 export const DEFAULT_SPACING = 2;
 

+ 1 - 1
packages/excalidraw/tsconfig.json

@@ -1,5 +1,5 @@
 {
-  "exclude": ["**/*.test.*", "tests", "types", "example", "dist"],
+  "exclude": ["**/*.test.*", "tests", "types", "examples", "dist"],
   "compilerOptions": {
     "target": "ESNext",
     "strict": true,

+ 0 - 15
packages/excalidraw/vite.config.mts

@@ -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",
-});

+ 4 - 3
scripts/buildExample.mjs

@@ -4,8 +4,9 @@ import { execSync } from "child_process";
 
 const createDevBuild = async () => {
   return await esbuild.build({
-    entryPoints: ["example/index.tsx"],
-    outfile: "example/public/bundle.js",
+    entryPoints: ["../../examples/excalidraw/with-script-in-browser/index.tsx"],
+    outfile:
+      "../../examples/excalidraw/with-script-in-browser/public/bundle.js",
     define: {
       "import.meta.env": "{}",
     },
@@ -26,7 +27,7 @@ const startServer = async (ctx) => {
   });
 };
 execSync(
-  `rm -rf example/public/dist && yarn build:esm && cp -r dist example/public`,
+  `rm -rf ../../examples/excalidraw/with-script-in-browser/public/dist && yarn build:esm && cp -r dist ../../examples/excalidraw/with-script-in-browser/public`,
 );
 
 const ctx = await createDevBuild();

+ 1 - 1
tsconfig.json

@@ -17,5 +17,5 @@
     "jsx": "react-jsx"
   },
   "include": ["packages", "excalidraw-app"],
-  "exclude": ["packages/excalidraw/types"]
+  "exclude": ["packages/excalidraw/types", "examples"]
 }

+ 155 - 4
yarn.lock

@@ -2649,6 +2649,56 @@
     "@jridgewell/resolve-uri" "3.1.0"
     "@jridgewell/sourcemap-codec" "1.4.14"
 
+"@next/[email protected]":
+  version "14.1.0"
+  resolved "https://registry.yarnpkg.com/@next/env/-/env-14.1.0.tgz#43d92ebb53bc0ae43dcc64fb4d418f8f17d7a341"
+  integrity sha512-Py8zIo+02ht82brwwhTg36iogzFqGLPXlRGKQw5s+qP/kMNc4MAyDeEwBKDijk6zTIbegEgu8Qy7C1LboslQAw==
+
+"@next/[email protected]":
+  version "14.1.0"
+  resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.1.0.tgz#70a57c87ab1ae5aa963a3ba0f4e59e18f4ecea39"
+  integrity sha512-nUDn7TOGcIeyQni6lZHfzNoo9S0euXnu0jhsbMOmMJUBfgsnESdjN97kM7cBqQxZa8L/bM9om/S5/1dzCrW6wQ==
+
+"@next/[email protected]":
+  version "14.1.0"
+  resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.0.tgz#0863a22feae1540e83c249384b539069fef054e9"
+  integrity sha512-1jgudN5haWxiAl3O1ljUS2GfupPmcftu2RYJqZiMJmmbBT5M1XDffjUtRUzP4W3cBHsrvkfOFdQ71hAreNQP6g==
+
+"@next/[email protected]":
+  version "14.1.0"
+  resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.0.tgz#893da533d3fce4aec7116fe772d4f9b95232423c"
+  integrity sha512-RHo7Tcj+jllXUbK7xk2NyIDod3YcCPDZxj1WLIYxd709BQ7WuRYl3OWUNG+WUfqeQBds6kvZYlc42NJJTNi4tQ==
+
+"@next/[email protected]":
+  version "14.1.0"
+  resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.0.tgz#d81ddcf95916310b8b0e4ad32b637406564244c0"
+  integrity sha512-v6kP8sHYxjO8RwHmWMJSq7VZP2nYCkRVQ0qolh2l6xroe9QjbgV8siTbduED4u0hlk0+tjS6/Tuy4n5XCp+l6g==
+
+"@next/[email protected]":
+  version "14.1.0"
+  resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.0.tgz#18967f100ec19938354332dcb0268393cbacf581"
+  integrity sha512-zJ2pnoFYB1F4vmEVlb/eSe+VH679zT1VdXlZKX+pE66grOgjmKJHKacf82g/sWE4MQ4Rk2FMBCRnX+l6/TVYzQ==
+
+"@next/[email protected]":
+  version "14.1.0"
+  resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.0.tgz#77077cd4ba8dda8f349dc7ceb6230e68ee3293cf"
+  integrity sha512-rbaIYFt2X9YZBSbH/CwGAjbBG2/MrACCVu2X0+kSykHzHnYH5FjHxwXLkcoJ10cX0aWCEynpu+rP76x0914atg==
+
+"@next/[email protected]":
+  version "14.1.0"
+  resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.0.tgz#5f0b8cf955644104621e6d7cc923cad3a4c5365a"
+  integrity sha512-o1N5TsYc8f/HpGt39OUQpQ9AKIGApd3QLueu7hXk//2xq5Z9OxmV6sQfNp8C7qYmiOlHYODOGqNNa0e9jvchGQ==
+
+"@next/[email protected]":
+  version "14.1.0"
+  resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.0.tgz#21f4de1293ac5e5a168a412b139db5d3420a89d0"
+  integrity sha512-XXIuB1DBRCFwNO6EEzCTMHT5pauwaSj4SWs7CYnME57eaReAKBXCnkUE80p/pAZcewm7hs+vGvNqDPacEXHVkw==
+
+"@next/[email protected]":
+  version "14.1.0"
+  resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.0.tgz#e561fb330466d41807123d932b365cf3d33ceba2"
+  integrity sha512-9WEbVRRAqJ3YFVqEZIxUqkiO8l1nool1LmNxygr5HWF8AcSYsEpneUDhmjUVJEzO2A04+oPtZdombzzPPkTtgg==
+
 "@nicolo-ribaudo/[email protected]":
   version "5.1.1-v1"
   resolved "https://registry.yarnpkg.com/@nicolo-ribaudo/eslint-scope-5-internals/-/eslint-scope-5-internals-5.1.1-v1.tgz#dbf733a965ca47b1973177dc0bb6c889edcfb129"
@@ -3290,6 +3340,13 @@
     "@svgr/hast-util-to-babel-ast" "^6.5.1"
     svg-parser "^2.0.4"
 
+"@swc/[email protected]":
+  version "0.5.2"
+  resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.2.tgz#85ea0c76450b61ad7d10a37050289eded783c27d"
+  integrity sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==
+  dependencies:
+    tslib "^2.4.0"
+
 "@testing-library/dom@^8.0.0":
   version "8.20.1"
   resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-8.20.1.tgz#2e52a32e46fc88369eef7eef634ac2a192decd9f"
@@ -3487,6 +3544,13 @@
   dependencies:
     undici-types "~5.26.4"
 
+"@types/node@^20":
+  version "20.11.1"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.1.tgz#6a93f94abeda166f688d3d2aca18012afbe5f850"
+  integrity sha512-DsXojJUES2M+FE8CpptJTKpg+r54moV9ZEncPstni1WHFmTcCzeFLnMFfyhCVS8XNOy/OQG+8lVxRLRrVHmV5A==
+  dependencies:
+    undici-types "~5.26.4"
+
 "@types/[email protected]":
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/@types/pako/-/pako-1.0.3.tgz#2e61c2b02020b5f44e2e5e946dfac74f4ec33c58"
@@ -3521,6 +3585,13 @@
   dependencies:
     "@types/react" "^17"
 
+"@types/react-dom@^18":
+  version "18.2.18"
+  resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.2.18.tgz#16946e6cd43971256d874bc3d0a72074bb8571dd"
+  integrity sha512-TJxDm6OfAX2KJWJdMEVTwWke5Sc/E/RlnPGvGfS0W7+6ocy2xhDVQVh/KvC2Uf7kACs+gDytdusDSdWfWkaNzw==
+  dependencies:
+    "@types/react" "*"
+
 "@types/react@*", "@types/[email protected]":
   version "18.0.15"
   resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.15.tgz#d355644c26832dc27f3e6cbf0c4f4603fc4ab7fe"
@@ -3539,6 +3610,15 @@
     "@types/scheduler" "*"
     csstype "^3.0.2"
 
+"@types/react@^18":
+  version "18.2.48"
+  resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.48.tgz#11df5664642d0bd879c1f58bc1d37205b064e8f1"
+  integrity sha512-qboRCl6Ie70DQQG9hhNREz81jqC1cs9EVNcjQ1AU+jH6NFfSAhVVbrrY/+nSF+Bsk4AOwm9Qa61InvMCyV+H3w==
+  dependencies:
+    "@types/prop-types" "*"
+    "@types/scheduler" "*"
+    csstype "^3.0.2"
+
 "@types/[email protected]":
   version "0.1.7"
   resolved "https://registry.yarnpkg.com/@types/resize-observer-browser/-/resize-observer-browser-0.1.7.tgz#294aaadf24ac6580b8fbd1fe3ab7b59fe85f9ef3"
@@ -4669,6 +4749,13 @@ builtin-modules@^3.1.0:
   resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
   integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==
 
[email protected]:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893"
+  integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==
+  dependencies:
+    streamsearch "^1.1.0"
+
 bytes-iec@^3.1.1:
   version "3.1.1"
   resolved "https://registry.yarnpkg.com/bytes-iec/-/bytes-iec-3.1.1.tgz#94cd36bf95c2c22a82002c247df8772d1d591083"
@@ -4707,6 +4794,11 @@ caniuse-lite@^1.0.30001449:
   resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001478.tgz#0ef8a1cf8b16be47a0f9fc4ecfc952232724b32a"
   integrity sha512-gMhDyXGItTHipJj2ApIvR+iVB5hd0KP3svMWWXDvZOmjzJJassGLMfxRkQCSYgGd2gtdL/ReeiyvMSFD1Ss6Mw==
 
+caniuse-lite@^1.0.30001579:
+  version "1.0.30001579"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001579.tgz#45c065216110f46d6274311a4b3fcf6278e0852a"
+  integrity sha512-u5AUVkixruKHJjw/pj9wISlcMpgFWzSrczLZbrqBSxukQixmg0SJ5sZTpvaFvxU0HoQKd4yoyAogyrAz9pzJnA==
+
 [email protected]:
   version "0.0.1"
   resolved "https://registry.yarnpkg.com/canvas-roundrect-polyfill/-/canvas-roundrect-polyfill-0.0.1.tgz#70bf107ebe2037f26d839d7f809a26f4a95f5696"
@@ -4849,6 +4941,11 @@ cli-truncate@^3.1.0:
     slice-ansi "^5.0.0"
     string-width "^5.0.0"
 
[email protected]:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1"
+  integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==
+
 cliui@^8.0.1:
   version "8.0.1"
   resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa"
@@ -6617,7 +6714,7 @@ gopd@^1.0.1:
   dependencies:
     get-intrinsic "^1.1.3"
 
-graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.9:
+graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.9:
   version "4.2.11"
   resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
   integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
@@ -8143,6 +8240,29 @@ neo-async@^2.6.2:
   resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
   integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
 
[email protected]:
+  version "14.1.0"
+  resolved "https://registry.yarnpkg.com/next/-/next-14.1.0.tgz#b31c0261ff9caa6b4a17c5af019ed77387174b69"
+  integrity sha512-wlzrsbfeSU48YQBjZhDzOwhWhGsy+uQycR8bHAOt1LY1bn3zZEcDyHQOEoN3aWzQ8LHCAJ1nqrWCc9XF2+O45Q==
+  dependencies:
+    "@next/env" "14.1.0"
+    "@swc/helpers" "0.5.2"
+    busboy "1.6.0"
+    caniuse-lite "^1.0.30001579"
+    graceful-fs "^4.2.11"
+    postcss "8.4.31"
+    styled-jsx "5.1.1"
+  optionalDependencies:
+    "@next/swc-darwin-arm64" "14.1.0"
+    "@next/swc-darwin-x64" "14.1.0"
+    "@next/swc-linux-arm64-gnu" "14.1.0"
+    "@next/swc-linux-arm64-musl" "14.1.0"
+    "@next/swc-linux-x64-gnu" "14.1.0"
+    "@next/swc-linux-x64-musl" "14.1.0"
+    "@next/swc-win32-arm64-msvc" "14.1.0"
+    "@next/swc-win32-ia32-msvc" "14.1.0"
+    "@next/swc-win32-x64-msvc" "14.1.0"
+
 [email protected]:
   version "2.6.1"
   resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
@@ -8407,6 +8527,11 @@ path-type@^4.0.0:
   resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
   integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
 
[email protected]:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz#24c554a738f42700d6961992bf5f1049672f2391"
+  integrity sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==
+
 pathe@^1.1.0, pathe@^1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/pathe/-/pathe-1.1.1.tgz#1dd31d382b974ba69809adc9a7a347e65d84829a"
@@ -8571,6 +8696,15 @@ postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
   resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
   integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
 
[email protected]:
+  version "8.4.31"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d"
+  integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==
+  dependencies:
+    nanoid "^3.3.6"
+    picocolors "^1.0.0"
+    source-map-js "^1.0.2"
+
 postcss@^8.4.32, postcss@^8.4.7:
   version "8.4.32"
   resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.32.tgz#1dac6ac51ab19adb21b8b34fd2d93a86440ef6c9"
@@ -8751,7 +8885,7 @@ randombytes@^2.1.0:
   dependencies:
     safe-buffer "^5.1.0"
 
[email protected]:
[email protected], react-dom@^18:
   version "18.2.0"
   resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
   integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
@@ -8807,7 +8941,7 @@ react-style-singleton@^2.2.1:
     invariant "^2.2.4"
     tslib "^2.0.0"
 
[email protected]:
[email protected], react@^18:
   version "18.2.0"
   resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
   integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
@@ -9441,6 +9575,11 @@ stop-iteration-iterator@^1.0.0:
   dependencies:
     internal-slot "^1.0.4"
 
+streamsearch@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
+  integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
+
 string-argv@^0.3.1:
   version "0.3.1"
   resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da"
@@ -9591,6 +9730,13 @@ [email protected]:
   resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-3.3.3.tgz#bba8daac19930169c0c9c96706749a597ae3acff"
   integrity sha512-53BiGLXAcll9maCYtZi2RCQZKa8NQQai5C4horqKyRmHj9H7QmcUyucrH+4KW/gBQbXM2AsB0axoEcFZPlfPcw==
 
[email protected]:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.1.tgz#839a1c3aaacc4e735fed0781b8619ea5d0009d1f"
+  integrity sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==
+  dependencies:
+    client-only "0.0.1"
+
 stylis@^4.1.3:
   version "4.3.0"
   resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.3.0.tgz#abe305a669fc3d8777e10eefcfc73ad861c5588c"
@@ -9857,7 +10003,7 @@ tslib@^1.8.1, tslib@^1.9.3:
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
   integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
 
-tslib@^2.0.0:
+tslib@^2.0.0, tslib@^2.4.0:
   version "2.6.2"
   resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
   integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
@@ -9922,6 +10068,11 @@ [email protected]:
   resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.4.tgz#a2a3d2756c079abda241d75f149df9d561091e78"
   integrity sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==
 
+typescript@^5:
+  version "5.3.3"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37"
+  integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==
+
 typeson-registry@^1.0.0-alpha.20:
   version "1.0.0-alpha.39"
   resolved "https://registry.yarnpkg.com/typeson-registry/-/typeson-registry-1.0.0-alpha.39.tgz#9e0f5aabd5eebfcffd65a796487541196f4b1211"