Merge branch 'master' into barnabasmolnar/mainmenu-radix

# Conflicts:
#	package.json
#	packages/excalidraw/.size-limit.json
#	packages/excalidraw/components/dropdownMenu/DropdownMenuSub.tsx
#	packages/excalidraw/components/dropdownMenu/DropdownMenuSubContent.tsx
#	packages/excalidraw/components/dropdownMenu/DropdownMenuSubItem.tsx
#	packages/excalidraw/components/dropdownMenu/DropdownMenuSubTrigger.tsx
#	packages/excalidraw/components/main-menu/MainMenu.tsx
#	packages/excalidraw/tests/excalidraw.test.tsx
#	packages/excalidraw/tests/library.test.tsx
#	src/components/Actions.tsx
#	src/components/dropdownMenu/DropdownMenu.scss
#	src/components/dropdownMenu/DropdownMenuItem.tsx
#	yarn.lock
This commit is contained in:
dwelle
2025-08-31 20:18:40 +02:00
1247 changed files with 195441 additions and 80875 deletions

39
examples/with-nextjs/.gitignore vendored Normal file
View File

@@ -0,0 +1,39 @@
# 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
# copied assets
public/**/*.woff2

View File

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

View File

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

View File

@@ -0,0 +1,26 @@
{
"name": "with-nextjs",
"version": "0.1.0",
"private": true,
"scripts": {
"build:packages": "yarn --cwd ../../ build:packages",
"build:workspace": "yarn build:packages && yarn copy:assets",
"copy:assets": "cp -r ../../packages/excalidraw/dist/prod/fonts ./public",
"dev": "yarn build:workspace && next dev -p 3005",
"build": "yarn build:workspace && next build",
"start": "next start -p 3006",
"lint": "next lint"
},
"dependencies": {
"next": "14.1",
"react": "19.0.0",
"react-dom": "19.0.0"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "19.0.10",
"@types/react-dom": "19.0.4",
"path2d-polyfill": "2.0.1",
"typescript": "^5"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

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

View File

@@ -0,0 +1,27 @@
import dynamic from "next/dynamic";
import Script from "next/script";
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>
<Script id="load-env-variables" strategy="beforeInteractive">
{`window["EXCALIDRAW_ASSET_PATH"] = window.origin;`}
</Script>
{/* @ts-expect-error - https://github.com/vercel/next.js/issues/42292 */}
<ExcalidrawWithClientOnly />
</>
);
}

View File

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

View File

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

View File

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

View File

@@ -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"]
}

View File

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

View File

@@ -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/env@14.0.4":
version "14.0.4"
resolved "https://registry.yarnpkg.com/@next/env/-/env-14.0.4.tgz#d5cda0c4a862d70ae760e58c0cd96a8899a2e49a"
integrity sha512-irQnbMLbUNQpP1wcE5NstJtbuA/69kRfzBrpAD7Gsn8zm/CY6YQYc3HQBz8QPxwISG26tIm5afvvVbu508oBeQ==
"@next/swc-darwin-arm64@14.0.4":
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/swc-darwin-x64@14.0.4":
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/swc-linux-arm64-gnu@14.0.4":
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/swc-linux-arm64-musl@14.0.4":
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/swc-linux-x64-gnu@14.0.4":
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/swc-linux-x64-musl@14.0.4":
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/swc-win32-arm64-msvc@14.0.4":
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/swc-win32-ia32-msvc@14.0.4":
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/swc-win32-x64-msvc@14.0.4":
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/helpers@0.5.2":
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==
busboy@1.6.0:
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==
client-only@0.0.1:
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==
next@14.0.4:
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"
path2d-polyfill@2.0.1:
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==
postcss@8.4.31:
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==
styled-jsx@5.1.1:
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==
watchpack@2.4.0:
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"

View File

@@ -0,0 +1,5 @@
FROM node:18-bullseye
# Vite wants to open the browser using `open`, so we
# need to install those utils.
RUN apt update -y && apt install -y xdg-utils

View File

@@ -0,0 +1,35 @@
{
// These tasks will run in order when initializing your CodeSandbox project.
"setupTasks": [
{
"name": "Install Dependencies",
"command": "yarn install"
}
],
// These tasks can be run from CodeSandbox. Running one will open a log in the app.
"tasks": {
"build": {
"name": "Build",
"command": "yarn build",
"runAtStart": false
},
"start": {
"name": "Start Example",
"command": "yarn start",
"runAtStart": true,
"preview": {
"port": 3001
}
},
"install-deps": {
"name": "Install Dependencies",
"command": "yarn install",
"restartOn": {
"files": ["yarn.lock"],
"branch": false,
"resume": false
}
}
}
}

View File

@@ -0,0 +1,2 @@
# copied assets
public/**/*.woff2

View File

@@ -0,0 +1,74 @@
import React from "react";
import type * as TExcalidraw from "@excalidraw/excalidraw";
import type { ExcalidrawImperativeAPI } from "@excalidraw/excalidraw/types";
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,
excalidrawLib,
}: {
excalidrawAPI: ExcalidrawImperativeAPI;
excalidrawLib: typeof TExcalidraw;
}) => {
const { Button, MIME_TYPES } = excalidrawLib;
return (
<>
<Button
onSelect={() => alert("General Kenobi!")}
style={{ marginLeft: "1rem", width: "auto" }}
title="Hello there!"
>
Hit me
</Button>
<Button
className="custom-element"
onSelect={() => {
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`);
}}
title="Comments!"
>
{COMMENT_SVG}
</Button>
</>
);
};
export default CustomFooter;

View File

@@ -0,0 +1,92 @@
.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%;
}
}
.app-title {
margin-block-start: 0.83em;
margin-block-end: 0.83em;
}
}
.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 {
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 .selected-shape-actions {
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;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,30 @@
import React from "react";
import type * as TExcalidraw from "@excalidraw/excalidraw";
import type { ExcalidrawImperativeAPI } from "@excalidraw/excalidraw/types";
import CustomFooter from "./CustomFooter";
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;

View File

@@ -0,0 +1,66 @@
.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;
}

View File

@@ -0,0 +1,32 @@
import React, { useState } from "react";
import "./ExampleSidebar.scss";
export default function Sidebar({ children }: { children: React.ReactNode }) {
const [open, setOpen] = 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>
</>
);
}

View File

@@ -0,0 +1,31 @@
<!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";
window.EXCALIDRAW_ASSET_PATH =
"https://esm.sh/@excalidraw/excalidraw@0.18.0/dist/prod/";
</script>
</head>
<body>
<noscript> You need to enable JavaScript to run this app. </noscript>
<div id="root"></div>
<script type="module">
import * as ExcalidrawLib from "@excalidraw/excalidraw";
console.log(ExcalidrawLib);
window.ExcalidrawLib = ExcalidrawLib;
</script>
<script type="module" src="index.tsx"></script>
</body>
</html>

View File

@@ -0,0 +1,29 @@
import React, { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "@excalidraw/excalidraw/index.css";
import type * as TExcalidraw from "@excalidraw/excalidraw";
import App from "./components/ExampleApp";
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>,
);

View File

@@ -0,0 +1,994 @@
import type { ExcalidrawElementSkeleton } from "@excalidraw/excalidraw/data/transform";
import type { FileId } from "@excalidraw/excalidraw/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: 5 },
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",
},
],
],
};

View File

@@ -0,0 +1,22 @@
{
"name": "with-script-in-browser",
"version": "1.0.0",
"private": true,
"dependencies": {
"react": "19.0.0",
"react-dom": "19.0.0",
"@excalidraw/excalidraw": "*",
"browser-fs-access": "0.29.1"
},
"devDependencies": {
"vite": "5.0.12",
"typescript": "^5"
},
"scripts": {
"start": "vite",
"build": "vite build",
"preview": "vite preview --port 5002",
"build:preview": "yarn build && yarn preview",
"build:packages": "yarn --cwd ../../ build:packages"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View File

@@ -0,0 +1,9 @@
{
"compilerOptions": {
"module": "ES2022",
"moduleResolution": "Bundler",
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"jsx": "react-jsx",
"skipLibCheck": true
}
}

View File

@@ -0,0 +1,145 @@
import { MIME_TYPES } from "@excalidraw/excalidraw";
import { fileOpen as _fileOpen } from "browser-fs-access";
import { unstable_batchedUpdates } from "react-dom";
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 Error("Request Aborted"));
}
};
},
}) 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);
};

View File

@@ -0,0 +1,5 @@
{
"outputDirectory": "dist",
"installCommand": "yarn install",
"buildCommand": "yarn build:packages && yarn build"
}

View File

@@ -0,0 +1,19 @@
import { defineConfig } from "vite";
// https://vitejs.dev/config/
export default defineConfig({
server: {
port: 3001,
// open the browser
open: true,
},
publicDir: "public",
optimizeDeps: {
esbuildOptions: {
// Bumping to 2022 due to "Arbitrary module namespace identifier names" not being
// supported in Vite's default browser target https://github.com/vitejs/vite/issues/13556
target: "es2022",
treeShaking: true,
},
},
});