Merge branch 'master' into mrazator/delta-based-sync
|
@ -1,6 +1,21 @@
|
|||
{
|
||||
"extends": ["@excalidraw/eslint-config", "react-app"],
|
||||
"rules": {
|
||||
"import/order": [
|
||||
"warn",
|
||||
{
|
||||
"groups": ["builtin", "external", "internal", "parent", "sibling", "index", "object", "type"],
|
||||
"pathGroups": [
|
||||
{
|
||||
"pattern": "@excalidraw/**",
|
||||
"group": "external",
|
||||
"position": "after"
|
||||
}
|
||||
],
|
||||
"newlines-between": "always-and-inside-groups",
|
||||
"warnOnUnassignedImports": true
|
||||
}
|
||||
],
|
||||
"import/no-anonymous-default-export": "off",
|
||||
"no-restricted-globals": "off",
|
||||
"@typescript-eslint/consistent-type-imports": [
|
||||
|
|
1
.gitignore
vendored
|
@ -25,5 +25,4 @@ packages/excalidraw/types
|
|||
coverage
|
||||
dev-dist
|
||||
html
|
||||
examples/**/bundle.*
|
||||
meta*.json
|
10
README.md
|
@ -87,13 +87,11 @@ We'll be adding these features as drop-in plugins for the npm package in the fut
|
|||
|
||||
**Note:** following instructions are for installing the Excalidraw [npm package](https://www.npmjs.com/package/@excalidraw/excalidraw) when integrating Excalidraw into your own app. To run the repository locally for development, please refer to our [Development Guide](https://docs.excalidraw.com/docs/introduction/development).
|
||||
|
||||
```
|
||||
Use `npm` or `yarn` to install the package.
|
||||
|
||||
```bash
|
||||
npm install react react-dom @excalidraw/excalidraw
|
||||
```
|
||||
|
||||
or via yarn
|
||||
|
||||
```
|
||||
# or
|
||||
yarn add react react-dom @excalidraw/excalidraw
|
||||
```
|
||||
|
||||
|
|
|
@ -8,15 +8,15 @@
|
|||
import { FONT_FAMILY } from "@excalidraw/excalidraw";
|
||||
```
|
||||
|
||||
`FONT_FAMILY` contains all the font families used in `Excalidraw` as explained below
|
||||
`FONT_FAMILY` contains all the font families used in `Excalidraw`. The default families are the following:
|
||||
|
||||
| Font Family | Description |
|
||||
| ----------- | ---------------------- |
|
||||
| `Virgil` | The `Hand-drawn` font |
|
||||
| `Helvetica` | The `Normal` Font |
|
||||
| `Cascadia` | The `Code` Font |
|
||||
| `Excalifont` | The `Hand-drawn` font |
|
||||
| `Nunito` | The `Normal` Font |
|
||||
| `Comic Shanns` | The `Code` Font |
|
||||
|
||||
Defaults to `FONT_FAMILY.Virgil` unless passed in `initialData.appState.currentItemFontFamily`.
|
||||
Pre-selected family is `FONT_FAMILY.Excalifont`, unless it's overriden with `initialData.appState.currentItemFontFamily`.
|
||||
|
||||
### THEME
|
||||
|
||||
|
|
|
@ -65,7 +65,7 @@ You can use this function to update the scene with the sceneData. It accepts the
|
|||
| `elements` | [`ImportedDataState["elements"]`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/types.ts#L38) | The `elements` to be updated in the scene |
|
||||
| `appState` | [`ImportedDataState["appState"]`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/types.ts#L39) | The `appState` to be updated in the scene. |
|
||||
| `collaborators` | <code>Map<string, <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L37">Collaborator></a></code> | The list of collaborators to be updated in the scene. |
|
||||
| `storeAction` | `StoreAction` | Implies if the change should be captured by the `store`. Captured changes are emmitted and listened to by other components, such as `History` for undo / redo purposes. Defaults to `StoreAction.CAPTURE`. |
|
||||
| `captureUpdate` | [`CaptureUpdateAction`](https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/store.ts#L40) | Controls which updates should be captured by the `Store`. Captured updates are emmitted and listened to by other components, such as `History` for undo / redo purposes. |
|
||||
|
||||
```jsx live
|
||||
function App() {
|
||||
|
@ -105,6 +105,7 @@ function App() {
|
|||
appState: {
|
||||
viewBackgroundColor: "#edf2ff",
|
||||
},
|
||||
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
||||
};
|
||||
excalidrawAPI.updateScene(sceneData);
|
||||
};
|
||||
|
@ -121,6 +122,18 @@ function App() {
|
|||
}
|
||||
```
|
||||
|
||||
#### captureUpdate
|
||||
|
||||
You can use the `captureUpdate` to influence undo / redo behaviour.
|
||||
|
||||
> **NOTE**: Some updates are not observed by the store / history - i.e. updates to `collaborators` object or parts of `AppState` which are not observed (not `ObservedAppState`). Such updates will never make it to the undo / redo stacks, regardless of the passed `captureUpdate` value.
|
||||
|
||||
| | `captureUpdate` value | Notes |
|
||||
| --- | --- | --- |
|
||||
| _Immediately undoable_ | `CaptureUpdateAction.IMMEDIATELY` | Use for updates which should be captured. Should be used for most of the local updates. These updates will _immediately_ make it to the local undo / redo stacks. |
|
||||
| _Eventually undoable_ | `CaptureUpdateAction.EVENTUALLY` | Use for updates which should not be captured immediately - likely exceptions which are part of some async multi-step process. Otherwise, all such updates would end up being captured with the next `CaptureUpdateAction.IMMEDIATELY` - triggered either by the next `updateScene` or internally by the editor. These updates will _eventually_ make it to the local undo / redo stacks. |
|
||||
| _Never undoable_ | `CaptureUpdateAction.NEVER` | Use for updates which should never be recorded, such as remote updates or scene initialization. These updates will _never_ make it to the local undo / redo stacks. |
|
||||
|
||||
### updateLibrary
|
||||
|
||||
<pre>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
All `props` are _optional_.
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| --- | --- | --- | --- |
|
||||
| [`initialData`](/docs/@excalidraw/excalidraw/api/props/initialdata) | `object` | `null` | <code>Promise<object | null></code> | `null` | The initial data with which app loads. |
|
||||
| [`excalidrawAPI`](/docs/@excalidraw/excalidraw/api/props/excalidraw-api) | `function` | \_ | Callback triggered with the excalidraw api once rendered |
|
||||
| [`isCollaborating`](#iscollaborating) | `boolean` | \_ | This indicates if the app is in `collaboration` mode |
|
||||
|
@ -13,7 +13,7 @@ All `props` are _optional_.
|
|||
| [`onScrollChange`](#onscrollchange) | `function` | \_ | This prop if passed gets triggered when scrolling the canvas. |
|
||||
| [`onPaste`](#onpaste) | `function` | \_ | Callback to be triggered if passed when something is pasted into the scene |
|
||||
| [`onLibraryChange`](#onlibrarychange) | `function` | \_ | The callback if supplied is triggered when the library is updated and receives the library items. |
|
||||
| [`generateLinkForSelection`](#generateLinkForSelection) | `function` | \_ | Allows you to override `url` generation when linking to Excalidraw elements. |
|
||||
| [`generateLinkForSelection`](#generatelinkforselection) | `function` | \_ | Allows you to override `url` generation when linking to Excalidraw elements. |
|
||||
| [`onLinkOpen`](#onlinkopen) | `function` | \_ | The callback if supplied is triggered when any link is opened. |
|
||||
| [`langCode`](#langcode) | `string` | `en` | Language code string to be used in Excalidraw |
|
||||
| [`renderTopRightUI`](/docs/@excalidraw/excalidraw/api/props/render-props#rendertoprightui) | `function` | \_ | Render function that renders custom UI in top right corner |
|
||||
|
@ -29,7 +29,7 @@ All `props` are _optional_.
|
|||
| [`handleKeyboardGlobally`](#handlekeyboardglobally) | `boolean` | `false` | Indicates whether to bind the keyboard events to document. |
|
||||
| [`autoFocus`](#autofocus) | `boolean` | `false` | Indicates whether to focus the Excalidraw component on page load |
|
||||
| [`generateIdForFile`](#generateidforfile) | `function` | \_ | Allows you to override `id` generation for files added on canvas |
|
||||
| [`validateEmbeddable`](#validateEmbeddable) | string[] | `boolean | RegExp | RegExp[] | ((link: string) => boolean | undefined)` | \_ | use for custom src url validation |
|
||||
| [`validateEmbeddable`](#validateembeddable) | `string[]` \| `boolean` \| `RegExp` \| `RegExp[]` \| <code>((link: string) => boolean | undefined)</code> | \_ | use for custom src url validation |
|
||||
| [`renderEmbeddable`](/docs/@excalidraw/excalidraw/api/props/render-props#renderEmbeddable) | `function` | \_ | Render function that can override the built-in `<iframe>` |
|
||||
|
||||
### Storing custom data on Excalidraw elements
|
||||
|
|
|
@ -31,7 +31,7 @@ You can pass `null` / `undefined` if not applicable.
|
|||
restoreElements(
|
||||
elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114">ImportedDataState["elements"]</a>,<br/>
|
||||
localElements: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114">ExcalidrawElement[]</a> | null | undefined): <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114">ExcalidrawElement[]</a>,<br/>
|
||||
opts: { refreshDimensions?: boolean, repairBindings?: boolean }<br/>
|
||||
opts: { refreshDimensions?: boolean, repairBindings?: boolean, normalizeIndices?: boolean }<br/>
|
||||
)
|
||||
</pre>
|
||||
|
||||
|
@ -51,8 +51,9 @@ The extra optional parameter to configure restored elements. It has the followin
|
|||
|
||||
| Prop | Type | Description|
|
||||
| --- | --- | ------|
|
||||
| `refreshDimensions` | `boolean` | Indicates whether we should also `recalculate` text element dimensions. Since this is a potentially costly operation, you may want to disable it if you restore elements in tight loops, such as during collaboration. |
|
||||
| `repairBindings` |`boolean` | Indicates whether the `bindings` for the elements should be repaired. This is to make sure there are no containers with non existent bound text element id and no bound text elements with non existent container id. |
|
||||
| `refreshDimensions` | `boolean` | Indicates whether we should also _recalculate_ text element dimensions. Since this is a potentially costly operation, you may want to disable it if you restore elements in tight loops, such as during collaboration. |
|
||||
| `repairBindings` |`boolean` | Indicates whether the _bindings_ for the elements should be repaired. This is to make sure there are no containers with non existent bound text element id and no bound text elements with non existent container id. |
|
||||
| `normalizeIndices` |`boolean` | Indicates whether _fractional indices_ for the elements should be normalized. This is to prevent possible issues caused by using stale (too old, too long) indices. |
|
||||
|
||||
**_How to use_**
|
||||
|
||||
|
@ -73,7 +74,7 @@ restore(
|
|||
data: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/types.ts#L34">ImportedDataState</a>,<br/>
|
||||
localAppState: Partial<<a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/types.ts#L95">AppState</a>> | null | undefined,<br/>
|
||||
localElements: <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/element/types.ts#L114">ExcalidrawElement[]</a> | null | undefined<br/>): <a href="https://github.com/excalidraw/excalidraw/blob/master/packages/excalidraw/data/types.ts#L4">DataState</a><br/>
|
||||
opts: { refreshDimensions?: boolean, repairBindings?: boolean }<br/>
|
||||
opts: { refreshDimensions?: boolean, repairBindings?: boolean, normalizeIndices?: boolean }<br/>
|
||||
|
||||
)
|
||||
</pre>
|
||||
|
|
|
@ -13,18 +13,18 @@ To start the example app using the `@excalidraw/excalidraw` package, follow the
|
|||
1. Install the dependencies
|
||||
|
||||
```bash
|
||||
cd packages/excalidraw && yarn
|
||||
yarn
|
||||
```
|
||||
|
||||
2. Start the example app
|
||||
|
||||
```bash
|
||||
yarn start
|
||||
yarn start:example
|
||||
```
|
||||
|
||||
[http://localhost:3001](http://localhost:3001) will open in your default browser.
|
||||
|
||||
The example is same as the [codesandbox example](https://ehlz3.csb.app/)
|
||||
|
||||
This is the same example as the [CodeSandbox](https://codesandbox.io/p/sandbox/github/excalidraw/excalidraw/tree/master/examples/with-script-in-browser) example.
|
||||
|
||||
## Releasing
|
||||
|
||||
|
|
|
@ -17,11 +17,9 @@ We strongly recommend turning it off. You can follow the steps below on how to d
|
|||
<div style={{width:'30rem'}}>
|
||||
|
||||
2. Once opened, look for **Aggressively Block Fingerprinting**
|
||||
|
||||

|
||||
|
||||
3. Switch to **Block Fingerprinting**
|
||||
|
||||

|
||||
|
||||
4. Thats all. All text elements should be fixed now 🎉
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
# Installation
|
||||
|
||||
**Excalidraw** is published to npm as a component you can directly embed in your projects.
|
||||
**Excalidraw** is exported as a component to be directly embedded in your project.
|
||||
|
||||
Using `npm`:
|
||||
Use `npm` or `yarn` to install the package.
|
||||
|
||||
```bash
|
||||
npm install react react-dom @excalidraw/excalidraw
|
||||
```
|
||||
|
||||
or `yarn`:
|
||||
|
||||
```bash
|
||||
# or
|
||||
yarn add react react-dom @excalidraw/excalidraw
|
||||
```
|
||||
|
||||
|
@ -20,24 +16,40 @@ yarn add react react-dom @excalidraw/excalidraw
|
|||
|
||||
:::
|
||||
|
||||
### Static assets
|
||||
### Self-hosting fonts
|
||||
|
||||
Excalidraw depends on assets such as localization files (if you opt to use them), fonts, and others.
|
||||
By default, Excalidraw will try to download all the used fonts from the [CDN](https://esm.run/@excalidraw/excalidraw/dist/prod).
|
||||
|
||||
By default these assets are loaded from a public CDN [`https://unpkg.com/@excalidraw/excalidraw/dist/`](https://unpkg.com/@excalidraw/excalidraw/dist), so you don't need to do anything on your end.
|
||||
|
||||
However, if you want to host these files yourself, you can find them in your `node_modules/@excalidraw/excalidraw/dist` directory, in folders `excalidraw-assets` (for production) and `excalidraw-assets-dev` (for development).
|
||||
|
||||
Copy these folders to your static assets directory, and add a `window.EXCALIDRAW_ASSET_PATH` variable in your `index.html` or `index.js` entry file pointing to your public assets path (relative). For example, if you serve your assets from the root of your hostname, you would do:
|
||||
For self-hosting purposes, you'll have to copy the content of the folder `node_modules/@excalidraw/excalidraw/dist/prod/fonts` to the path where your assets should be served from (i.e. `public/` directory in your project). In that case, you should also set `window.EXCALIDRAW_ASSET_PATH` to the very same path, i.e. `/` in case it's in the root:
|
||||
|
||||
```js
|
||||
window.EXCALIDRAW_ASSET_PATH = "/";
|
||||
```
|
||||
|
||||
or, if you serve your assets from the root of your CDN, you would do:
|
||||
|
||||
```js
|
||||
// Vanilla
|
||||
<head>
|
||||
<script>
|
||||
window.EXCALIDRAW_ASSET_PATH = "https://my.cdn.com/assets/";
|
||||
</script>
|
||||
</head>
|
||||
```
|
||||
|
||||
or, if you prefer the path to be dynamicly set based on the `location.origin`, you could do the following:
|
||||
|
||||
```jsx
|
||||
// Next.js
|
||||
<Script id="load-env-variables" strategy="beforeInteractive" >
|
||||
{ `window["EXCALIDRAW_ASSET_PATH"] = location.origin;` } // or use just "/"!
|
||||
</Script>
|
||||
```
|
||||
|
||||
### Dimensions of Excalidraw
|
||||
|
||||
Excalidraw takes _100%_ of `width` and `height` of the containing block so make sure the container in which you render Excalidraw has non zero dimensions.
|
||||
|
||||
### Demo
|
||||
## Demo
|
||||
|
||||
[Try here](https://codesandbox.io/s/excalidraw-ehlz3).
|
||||
Go to [CodeSandbox](https://codesandbox.io/p/sandbox/github/excalidraw/excalidraw/tree/master/examples/with-script-in-browser) example.
|
||||
|
|
|
@ -128,11 +128,10 @@ If you are using `pages router` then importing the wrapper dynamically would wor
|
|||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
{/* Link should be updated to point to the latest! */}
|
||||
Here is a [source code](https://github.com/excalidraw/excalidraw/tree/master/examples/with-nextjs) for the example with app and pages router. You you can try it out [here](https://excalidraw-package-example-with-nextjs.vercel.app/).
|
||||
|
||||
Here is a [source code](https://github.com/excalidraw/excalidraw/tree/master/examples/excalidraw/with-nextjs) for the example with app and pages router. You you can try it out [here](https://excalidraw-package-example-with-nextjs-gh6smrdnq-excalidraw.vercel.app/).
|
||||
|
||||
|
||||
The `types` are available at `@excalidraw/excalidraw/types`, you can view [example for typescript](https://codesandbox.io/s/excalidraw-types-9h2dm)
|
||||
The `types` are available at `@excalidraw/excalidraw/types`, check [CodeSandbox](https://codesandbox.io/p/sandbox/github/excalidraw/excalidraw/tree/master/examples/with-script-in-browser) example for details.
|
||||
|
||||
### Preact
|
||||
|
||||
|
@ -157,27 +156,9 @@ Since Vite removes env variables by default, you can update the vite config to e
|
|||
|
||||
## Browser
|
||||
|
||||
To use it in a browser directly:
|
||||
To use it Excalidraw in a browser directly, use the following setup :point_down:
|
||||
|
||||
For development use :point_down:
|
||||
|
||||
```js
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://unpkg.com/@excalidraw/excalidraw/dist/excalidraw.development.js"
|
||||
></script>
|
||||
```
|
||||
|
||||
For production use :point_down:
|
||||
|
||||
```js
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://unpkg.com/@excalidraw/excalidraw/dist/excalidraw.production.min.js"
|
||||
></script>
|
||||
```
|
||||
|
||||
You will need to make sure `react`, `react-dom` is available as shown in the below example. For prod please use the production versions of `react`, `react-dom`.
|
||||
> **Note**: We rely on import maps to de-duplicate `react`, `react-dom` and `react/jsx-runtime` versions.
|
||||
|
||||
import Tabs from "@theme/Tabs";
|
||||
import TabItem from "@theme/TabItem";
|
||||
|
@ -191,13 +172,23 @@ import TabItem from "@theme/TabItem";
|
|||
<head>
|
||||
<title>Excalidraw in browser</title>
|
||||
<meta charset="UTF-8" />
|
||||
<script src="https://unpkg.com/react@18.2.0/umd/react.development.js"></script>
|
||||
<script src="https://unpkg.com/react-dom@18.2.0/umd/react-dom.development.js"></script>
|
||||
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="https://unpkg.com/@excalidraw/excalidraw/dist/excalidraw.development.js"
|
||||
></script>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://esm.sh/@excalidraw/excalidraw@0.18.0/dist/dev/index.css"
|
||||
/>
|
||||
<link rel="stylesheet" href="./index.css" />
|
||||
<script>
|
||||
window.EXCALIDRAW_ASSET_PATH = "https://esm.sh/@excalidraw/excalidraw@0.18.0/dist/prod/";
|
||||
</script>
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"react": "https://esm.sh/react@19.0.0",
|
||||
"react/jsx-runtime": "https://esm.sh/react@19.0.0/jsx-runtime",
|
||||
"react-dom": "https://esm.sh/react-dom@19.0.0"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -214,6 +205,14 @@ import TabItem from "@theme/TabItem";
|
|||
<TabItem value="js" label="Javascript">
|
||||
|
||||
```js showLineNumbers
|
||||
// See https://www.npmjs.com/package/@excalidraw/excalidraw documentation.
|
||||
import * as ExcalidrawLib from 'https://esm.sh/@excalidraw/excalidraw@0.18.0/dist/dev/index.js?external=react,react-dom';
|
||||
import React from "https://esm.sh/react@19.0.0";
|
||||
import ReactDOM from "https://esm.sh/react-dom@19.0.0"
|
||||
|
||||
window.ExcalidrawLib = ExcalidrawLib;
|
||||
console.log("Excalidraw library", ExcalidrawLib);
|
||||
|
||||
const App = () => {
|
||||
return React.createElement(
|
||||
React.Fragment,
|
||||
|
@ -236,4 +235,4 @@ root.render(React.createElement(App));
|
|||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
You can try it out [here](https://codesandbox.io/p/sandbox/excalidraw-in-browser-tlqom?file=%2Findex.html%3A1%2C10).
|
||||
You can try it out [here](https://jsfiddle.net/vfn6dm14/3/).
|
||||
|
|
|
@ -149,6 +149,29 @@ const config = {
|
|||
systemvars: true,
|
||||
},
|
||||
],
|
||||
function () {
|
||||
return {
|
||||
name: "disable-fully-specified-error",
|
||||
configureWebpack() {
|
||||
return {
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.m?js$/,
|
||||
resolve: {
|
||||
fullySpecified: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
optimization: {
|
||||
// disable terser minification
|
||||
minimize: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
"@docusaurus/core": "2.2.0",
|
||||
"@docusaurus/preset-classic": "2.2.0",
|
||||
"@docusaurus/theme-live-codeblock": "2.2.0",
|
||||
"@excalidraw/excalidraw": "0.17.6",
|
||||
"@excalidraw/excalidraw": "0.18.0",
|
||||
"@mdx-js/react": "^1.6.22",
|
||||
"clsx": "^1.2.1",
|
||||
"docusaurus-plugin-sass": "0.2.3",
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from "react";
|
||||
import clsx from "clsx";
|
||||
import React from "react";
|
||||
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
const FeatureList = [
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from "react";
|
||||
import clsx from "clsx";
|
||||
import React from "react";
|
||||
|
||||
import styles from "./styles.module.css";
|
||||
|
||||
type FeatureItem = {
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import React from "react";
|
||||
import clsx from "clsx";
|
||||
import Layout from "@theme/Layout";
|
||||
import Link from "@docusaurus/Link";
|
||||
import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
|
||||
import styles from "./index.module.css";
|
||||
import HomepageFeatures from "@site/src/components/Homepage";
|
||||
import Layout from "@theme/Layout";
|
||||
import clsx from "clsx";
|
||||
import React from "react";
|
||||
|
||||
import styles from "./index.module.css";
|
||||
|
||||
function HomepageHeader() {
|
||||
const { siteConfig } = useDocusaurusContext();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Import the original mapper
|
||||
import MDXComponents from "@theme-original/MDXComponents";
|
||||
import Highlight from "@site/src/components/Highlight";
|
||||
import MDXComponents from "@theme-original/MDXComponents";
|
||||
|
||||
export default {
|
||||
// Re-use the default mapping
|
||||
|
|
|
@ -3,11 +3,18 @@ import ExecutionEnvironment from "@docusaurus/ExecutionEnvironment";
|
|||
import initialData from "@site/src/initialData";
|
||||
import { useColorMode } from "@docusaurus/theme-common";
|
||||
|
||||
import "@excalidraw/excalidraw/index.css";
|
||||
|
||||
let ExcalidrawComp = {};
|
||||
if (ExecutionEnvironment.canUseDOM) {
|
||||
ExcalidrawComp = require("@excalidraw/excalidraw");
|
||||
}
|
||||
const Excalidraw = React.forwardRef((props, ref) => {
|
||||
if (!window.EXCALIDRAW_ASSET_PATH) {
|
||||
window.EXCALIDRAW_ASSET_PATH =
|
||||
"https://esm.sh/@excalidraw/excalidraw@0.18.0/dist/prod/";
|
||||
}
|
||||
|
||||
const { colorMode } = useColorMode();
|
||||
return <ExcalidrawComp.Excalidraw theme={colorMode} {...props} ref={ref} />;
|
||||
});
|
||||
|
|
1436
dev-docs/yarn.lock
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"name": "examples",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"@excalidraw/excalidraw": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5"
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"extends": "../../tsconfig"
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
"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.12",
|
||||
"typescript": "^5"
|
||||
},
|
||||
"scripts": {
|
||||
"build:workspace": "yarn workspace @excalidraw/excalidraw run build:esm && yarn copy:assets",
|
||||
"copy:assets": "cp -r ../../../packages/excalidraw/dist/prod/fonts ./public",
|
||||
"start": "yarn build:workspace && vite",
|
||||
"build": "yarn build:workspace && vite build",
|
||||
"build:preview": "yarn build && vite preview --port 5002"
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"outputDirectory": "dist",
|
||||
"installCommand": "yarn install"
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
import { defineConfig } from "vite";
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
server: {
|
||||
port: 3001,
|
||||
// open the browser
|
||||
open: true,
|
||||
},
|
||||
publicDir: "public",
|
||||
});
|
|
@ -1,313 +0,0 @@
|
|||
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@esbuild/aix-ppc64@0.19.11":
|
||||
version "0.19.11"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.19.11.tgz#2acd20be6d4f0458bc8c784103495ff24f13b1d3"
|
||||
integrity sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==
|
||||
|
||||
"@esbuild/android-arm64@0.19.11":
|
||||
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/android-arm@0.19.11":
|
||||
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/android-x64@0.19.11":
|
||||
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/darwin-arm64@0.19.11":
|
||||
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/darwin-x64@0.19.11":
|
||||
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/freebsd-arm64@0.19.11":
|
||||
version "0.19.11"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.11.tgz#d478b4195aa3ca44160272dab85ef8baf4175b4a"
|
||||
integrity sha512-lhoSp5K6bxKRNdXUtHoNc5HhbXVCS8V0iZmDvyWvYq9S5WSfTIHU2UGjcGt7UeS6iEYp9eeymIl5mJBn0yiuxA==
|
||||
|
||||
"@esbuild/freebsd-x64@0.19.11":
|
||||
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/linux-arm64@0.19.11":
|
||||
version "0.19.11"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.19.11.tgz#58ad4ff11685fcc735d7ff4ca759ab18fcfe4545"
|
||||
integrity sha512-LneLg3ypEeveBSMuoa0kwMpCGmpu8XQUh+mL8XXwoYZ6Be2qBnVtcDI5azSvh7vioMDhoJFZzp9GWp9IWpYoUg==
|
||||
|
||||
"@esbuild/linux-arm@0.19.11":
|
||||
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/linux-ia32@0.19.11":
|
||||
version "0.19.11"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.19.11.tgz#cbae1f313209affc74b80f4390c4c35c6ab83fa4"
|
||||
integrity sha512-caHy++CsD8Bgq2V5CodbJjFPEiDPq8JJmBdeyZ8GWVQMjRD0sU548nNdwPNvKjVpamYYVL40AORekgfIubwHoA==
|
||||
|
||||
"@esbuild/linux-loong64@0.19.11":
|
||||
version "0.19.11"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.19.11.tgz#5f32aead1c3ec8f4cccdb7ed08b166224d4e9121"
|
||||
integrity sha512-ppZSSLVpPrwHccvC6nQVZaSHlFsvCQyjnvirnVjbKSHuE5N24Yl8F3UwYUUR1UEPaFObGD2tSvVKbvR+uT1Nrg==
|
||||
|
||||
"@esbuild/linux-mips64el@0.19.11":
|
||||
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/linux-ppc64@0.19.11":
|
||||
version "0.19.11"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.19.11.tgz#9c5725a94e6ec15b93195e5a6afb821628afd912"
|
||||
integrity sha512-MHrZYLeCG8vXblMetWyttkdVRjQlQUb/oMgBNurVEnhj4YWOr4G5lmBfZjHYQHHN0g6yDmCAQRR8MUHldvvRDA==
|
||||
|
||||
"@esbuild/linux-riscv64@0.19.11":
|
||||
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/linux-s390x@0.19.11":
|
||||
version "0.19.11"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.19.11.tgz#4ad8567df48f7dd4c71ec5b1753b6f37561a65a8"
|
||||
integrity sha512-A5xdUoyWJHMMlcSMcPGVLzYzpcY8QP1RtYzX5/bS4dvjBGVxdhuiYyFwp7z74ocV7WDc0n1harxmpq2ePOjI0Q==
|
||||
|
||||
"@esbuild/linux-x64@0.19.11":
|
||||
version "0.19.11"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.19.11.tgz#b7390c4d5184f203ebe7ddaedf073df82a658766"
|
||||
integrity sha512-grbyMlVCvJSfxFQUndw5mCtWs5LO1gUlwP4CDi4iJBbVpZcqLVT29FxgGuBJGSzyOxotFG4LoO5X+M1350zmPA==
|
||||
|
||||
"@esbuild/netbsd-x64@0.19.11":
|
||||
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/openbsd-x64@0.19.11":
|
||||
version "0.19.11"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.19.11.tgz#17388c76e2f01125bf831a68c03a7ffccb65d1a2"
|
||||
integrity sha512-ysyOGZuTp6SNKPE11INDUeFVVQFrhcNDVUgSQVDzqsqX38DjhPEPATpid04LCoUr2WXhQTEZ8ct/EgJCUDpyNw==
|
||||
|
||||
"@esbuild/sunos-x64@0.19.11":
|
||||
version "0.19.11"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.19.11.tgz#e320636f00bb9f4fdf3a80e548cb743370d41767"
|
||||
integrity sha512-Hf+Sad9nVwvtxy4DXCZQqLpgmRTQqyFyhT3bZ4F2XlJCjxGmRFF0Shwn9rzhOYRB61w9VMXUkxlBy56dk9JJiQ==
|
||||
|
||||
"@esbuild/win32-arm64@0.19.11":
|
||||
version "0.19.11"
|
||||
resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.19.11.tgz#c778b45a496e90b6fc373e2a2bb072f1441fe0ee"
|
||||
integrity sha512-0P58Sbi0LctOMOQbpEOvOL44Ne0sqbS0XWHMvvrg6NE5jQ1xguCSSw9jQeUk2lfrXYsKDdOe6K+oZiwKPilYPQ==
|
||||
|
||||
"@esbuild/win32-ia32@0.19.11":
|
||||
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/win32-x64@0.19.11":
|
||||
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/rollup-android-arm-eabi@4.9.5":
|
||||
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/rollup-android-arm64@4.9.5":
|
||||
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/rollup-darwin-arm64@4.9.5":
|
||||
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/rollup-darwin-x64@4.9.5":
|
||||
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/rollup-linux-arm-gnueabihf@4.9.5":
|
||||
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/rollup-linux-arm64-gnu@4.9.5":
|
||||
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/rollup-linux-arm64-musl@4.9.5":
|
||||
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/rollup-linux-riscv64-gnu@4.9.5":
|
||||
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/rollup-linux-x64-gnu@4.9.5":
|
||||
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/rollup-linux-x64-musl@4.9.5":
|
||||
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/rollup-win32-arm64-msvc@4.9.5":
|
||||
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/rollup-win32-ia32-msvc@4.9.5":
|
||||
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/rollup-win32-x64-msvc@4.9.5":
|
||||
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/estree@1.0.5":
|
||||
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"
|
||||
|
||||
react-dom@18.2.0:
|
||||
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.2.0:
|
||||
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==
|
||||
|
||||
vite@5.0.6:
|
||||
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"
|
|
@ -4,22 +4,21 @@
|
|||
"private": true,
|
||||
"scripts": {
|
||||
"build:workspace": "yarn workspace @excalidraw/excalidraw run build:esm && yarn copy:assets",
|
||||
"copy:assets": "cp -r ../../../packages/excalidraw/dist/prod/fonts ./public",
|
||||
"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": {
|
||||
"@excalidraw/excalidraw": "*",
|
||||
"next": "14.1",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0"
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20",
|
||||
"@types/react": "18.2.0",
|
||||
"@types/react-dom": "18.2.0",
|
||||
"@types/react": "19.0.10",
|
||||
"@types/react-dom": "19.0.4",
|
||||
"path2d-polyfill": "2.0.1",
|
||||
"typescript": "^5"
|
||||
}
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 197 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
@ -1,5 +1,6 @@
|
|||
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
|
|
@ -1,10 +1,11 @@
|
|||
"use client";
|
||||
import * as excalidrawLib from "@excalidraw/excalidraw";
|
||||
import { Excalidraw } from "@excalidraw/excalidraw";
|
||||
import App from "../../components/ExampleApp";
|
||||
|
||||
import "@excalidraw/excalidraw/index.css";
|
||||
|
||||
import App from "../../with-script-in-browser/components/ExampleApp";
|
||||
|
||||
const ExcalidrawWrapper: React.FC = () => {
|
||||
return (
|
||||
<>
|
|
@ -1,4 +1,5 @@
|
|||
import dynamic from "next/dynamic";
|
||||
|
||||
import "../common.scss";
|
||||
|
||||
// Since client components get prerenderd on server as well hence importing the excalidraw stuff dynamically
|
5
examples/with-script-in-browser/.codesandbox/Dockerfile
Normal 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
|
35
examples/with-script-in-browser/.codesandbox/tasks.json
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
import React from "react";
|
||||
|
||||
import type * as TExcalidraw from "@excalidraw/excalidraw";
|
||||
import type { ExcalidrawImperativeAPI } from "@excalidraw/excalidraw/dist/excalidraw/types";
|
||||
import type { ExcalidrawImperativeAPI } from "@excalidraw/excalidraw/types";
|
||||
|
||||
const COMMENT_SVG = (
|
||||
<svg
|
|
@ -1,3 +1,4 @@
|
|||
import { nanoid } from "nanoid";
|
||||
import React, {
|
||||
useEffect,
|
||||
useState,
|
||||
|
@ -6,13 +7,24 @@ import React, {
|
|||
Children,
|
||||
cloneElement,
|
||||
} from "react";
|
||||
import ExampleSidebar from "./sidebar/ExampleSidebar";
|
||||
|
||||
import type * as TExcalidraw from "@excalidraw/excalidraw";
|
||||
import type { ImportedLibraryData } from "@excalidraw/excalidraw/data/types";
|
||||
import type {
|
||||
NonDeletedExcalidrawElement,
|
||||
Theme,
|
||||
} from "@excalidraw/excalidraw/element/types";
|
||||
import type {
|
||||
AppState,
|
||||
BinaryFileData,
|
||||
ExcalidrawImperativeAPI,
|
||||
ExcalidrawInitialDataState,
|
||||
Gesture,
|
||||
LibraryItems,
|
||||
PointerDownState as ExcalidrawPointerDownState,
|
||||
} from "@excalidraw/excalidraw/types";
|
||||
|
||||
import { nanoid } from "nanoid";
|
||||
|
||||
import type { ResolvablePromise } from "../utils";
|
||||
import initialData from "../initialData";
|
||||
import {
|
||||
resolvablePromise,
|
||||
distance2d,
|
||||
|
@ -23,25 +35,12 @@ import {
|
|||
|
||||
import CustomFooter from "./CustomFooter";
|
||||
import MobileFooter from "./MobileFooter";
|
||||
import initialData from "../initialData";
|
||||
|
||||
import type {
|
||||
AppState,
|
||||
BinaryFileData,
|
||||
ExcalidrawImperativeAPI,
|
||||
ExcalidrawInitialDataState,
|
||||
Gesture,
|
||||
LibraryItems,
|
||||
PointerDownState as ExcalidrawPointerDownState,
|
||||
} 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";
|
||||
import ExampleSidebar from "./sidebar/ExampleSidebar";
|
||||
|
||||
import "./ExampleApp.scss";
|
||||
|
||||
import type { ResolvablePromise } from "../utils";
|
||||
|
||||
type Comment = {
|
||||
x: number;
|
||||
y: number;
|
|
@ -1,6 +1,9 @@
|
|||
import type { ExcalidrawImperativeAPI } from "@excalidraw/excalidraw/dist/excalidraw/types";
|
||||
import CustomFooter from "./CustomFooter";
|
||||
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,
|
|
@ -1,4 +1,5 @@
|
|||
import { useState } from "react";
|
||||
import React, { useState } from "react";
|
||||
|
||||
import "./ExampleSidebar.scss";
|
||||
|
||||
export default function Sidebar({ children }: { children: React.ReactNode }) {
|
|
@ -11,17 +11,15 @@
|
|||
<title>React App</title>
|
||||
<script>
|
||||
window.name = "codesandbox";
|
||||
window.EXCALIDRAW_ASSET_PATH = window.origin;
|
||||
window.EXCALIDRAW_ASSET_PATH =
|
||||
"https://esm.sh/@excalidraw/excalidraw@0.18.0/dist/prod/";
|
||||
</script>
|
||||
<link rel="stylesheet" href="/dist/browser/dev/index.css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<noscript> You need to enable JavaScript to run this app. </noscript>
|
||||
<div id="root"></div>
|
||||
|
||||
<!-- 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 "@excalidraw/excalidraw";
|
||||
|
|
@ -1,10 +1,11 @@
|
|||
import App from "../components/ExampleApp";
|
||||
import React, { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
|
||||
import "@excalidraw/excalidraw/index.css";
|
||||
|
||||
import type * as TExcalidraw from "@excalidraw/excalidraw";
|
||||
|
||||
import "@excalidraw/excalidraw/index.css";
|
||||
import App from "./components/ExampleApp";
|
||||
|
||||
declare global {
|
||||
interface Window {
|
21
examples/with-script-in-browser/package.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"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",
|
||||
"build:preview": "yarn build && vite preview --port 5002",
|
||||
"build:package": "yarn workspace @excalidraw/excalidraw run build:esm"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 197 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
9
examples/with-script-in-browser/tsconfig.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"module": "ES2022",
|
||||
"moduleResolution": "Bundler",
|
||||
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
||||
"jsx": "react-jsx",
|
||||
"skipLibCheck": true
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
import { unstable_batchedUpdates } from "react-dom";
|
||||
import { fileOpen as _fileOpen } from "browser-fs-access";
|
||||
import { MIME_TYPES } from "@excalidraw/excalidraw";
|
||||
import { AbortError } from "../../packages/excalidraw/errors";
|
||||
import { fileOpen as _fileOpen } from "browser-fs-access";
|
||||
import { unstable_batchedUpdates } from "react-dom";
|
||||
|
||||
type FILE_EXTENSION = Exclude<keyof typeof MIME_TYPES, "binary">;
|
||||
|
||||
|
@ -85,7 +84,7 @@ export const fileOpen = <M extends boolean | undefined = false>(opts: {
|
|||
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());
|
||||
rejectPromise(new Error("Request Aborted"));
|
||||
}
|
||||
};
|
||||
},
|
5
examples/with-script-in-browser/vercel.json
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"outputDirectory": "dist",
|
||||
"installCommand": "yarn install",
|
||||
"buildCommand": "yarn build:package && yarn build"
|
||||
}
|
19
examples/with-script-in-browser/vite.config.mts
Normal 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,
|
||||
},
|
||||
},
|
||||
});
|
|
@ -1,42 +1,31 @@
|
|||
import polyfill from "../packages/excalidraw/polyfill";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { trackEvent } from "../packages/excalidraw/analytics";
|
||||
import { getDefaultAppState } from "../packages/excalidraw/appState";
|
||||
import { ErrorDialog } from "../packages/excalidraw/components/ErrorDialog";
|
||||
import { TopErrorBoundary } from "./components/TopErrorBoundary";
|
||||
import Slider from "rc-slider";
|
||||
|
||||
import "rc-slider/assets/index.css";
|
||||
|
||||
import {
|
||||
Excalidraw,
|
||||
LiveCollaborationTrigger,
|
||||
TTDDialogTrigger,
|
||||
CaptureUpdateAction,
|
||||
reconcileElements,
|
||||
} from "@excalidraw/excalidraw";
|
||||
import { trackEvent } from "@excalidraw/excalidraw/analytics";
|
||||
import { getDefaultAppState } from "@excalidraw/excalidraw/appState";
|
||||
import {
|
||||
CommandPalette,
|
||||
DEFAULT_CATEGORIES,
|
||||
} from "@excalidraw/excalidraw/components/CommandPalette/CommandPalette";
|
||||
import { ErrorDialog } from "@excalidraw/excalidraw/components/ErrorDialog";
|
||||
import { OverwriteConfirmDialog } from "@excalidraw/excalidraw/components/OverwriteConfirm/OverwriteConfirm";
|
||||
import { openConfirmModal } from "@excalidraw/excalidraw/components/OverwriteConfirm/OverwriteConfirmState";
|
||||
import { ShareableLinkDialog } from "@excalidraw/excalidraw/components/ShareableLinkDialog";
|
||||
import Trans from "@excalidraw/excalidraw/components/Trans";
|
||||
import {
|
||||
APP_NAME,
|
||||
EVENT,
|
||||
THEME,
|
||||
TITLE_TIMEOUT,
|
||||
VERSION_TIMEOUT,
|
||||
} from "../packages/excalidraw/constants";
|
||||
import { loadFromBlob } from "../packages/excalidraw/data/blob";
|
||||
import type {
|
||||
FileId,
|
||||
NonDeletedExcalidrawElement,
|
||||
OrderedExcalidrawElement,
|
||||
SceneElementsMap,
|
||||
} from "../packages/excalidraw/element/types";
|
||||
import { useCallbackRefState } from "../packages/excalidraw/hooks/useCallbackRefState";
|
||||
import { t } from "../packages/excalidraw/i18n";
|
||||
import {
|
||||
Excalidraw,
|
||||
LiveCollaborationTrigger,
|
||||
TTDDialogTrigger,
|
||||
StoreAction,
|
||||
reconcileElements,
|
||||
newElementWith,
|
||||
} from "../packages/excalidraw";
|
||||
import type {
|
||||
AppState,
|
||||
ExcalidrawImperativeAPI,
|
||||
BinaryFiles,
|
||||
ExcalidrawInitialDataState,
|
||||
UIAppState,
|
||||
} from "../packages/excalidraw/types";
|
||||
import type { ResolvablePromise } from "../packages/excalidraw/utils";
|
||||
import {
|
||||
debounce,
|
||||
getVersion,
|
||||
getFrame,
|
||||
|
@ -44,81 +33,15 @@ import {
|
|||
preventUnload,
|
||||
resolvablePromise,
|
||||
isRunningInIframe,
|
||||
isDevEnv,
|
||||
assertNever,
|
||||
} from "../packages/excalidraw/utils";
|
||||
import {
|
||||
FIREBASE_STORAGE_PREFIXES,
|
||||
isExcalidrawPlusSignedUser,
|
||||
STORAGE_KEYS,
|
||||
SYNC_BROWSER_TABS_TIMEOUT,
|
||||
} from "./app_constants";
|
||||
import type { CollabAPI } from "./collab/Collab";
|
||||
import Collab, {
|
||||
collabAPIAtom,
|
||||
isCollaboratingAtom,
|
||||
isOfflineAtom,
|
||||
syncApiAtom,
|
||||
} from "./collab/Collab";
|
||||
import {
|
||||
exportToBackend,
|
||||
getCollaborationLinkData,
|
||||
isCollaborationLink,
|
||||
loadScene,
|
||||
} from "./data";
|
||||
import {
|
||||
importFromLocalStorage,
|
||||
importUsernameFromLocalStorage,
|
||||
} from "./data/localStorage";
|
||||
import CustomStats from "./CustomStats";
|
||||
import type { RestoredDataState } from "../packages/excalidraw/data/restore";
|
||||
import { restore, restoreAppState } from "../packages/excalidraw/data/restore";
|
||||
import {
|
||||
ExportToExcalidrawPlus,
|
||||
exportToExcalidrawPlus,
|
||||
} from "./components/ExportToExcalidrawPlus";
|
||||
import { updateStaleImageStatuses } from "./data/FileManager";
|
||||
import { isInitializedImageElement } from "../packages/excalidraw/element/typeChecks";
|
||||
import { loadFilesFromFirebase } from "./data/firebase";
|
||||
import {
|
||||
LibraryIndexedDBAdapter,
|
||||
LibraryLocalStorageMigrationAdapter,
|
||||
LocalData,
|
||||
} from "./data/LocalData";
|
||||
import { isBrowserStorageStateNewer } from "./data/tabSync";
|
||||
import clsx from "clsx";
|
||||
import {
|
||||
parseLibraryTokensFromUrl,
|
||||
useHandleLibrary,
|
||||
} from "../packages/excalidraw/data/library";
|
||||
import { AppMainMenu } from "./components/AppMainMenu";
|
||||
import { AppWelcomeScreen } from "./components/AppWelcomeScreen";
|
||||
import { AppFooter } from "./components/AppFooter";
|
||||
import {
|
||||
Provider,
|
||||
useAtom,
|
||||
useAtomValue,
|
||||
useAtomWithInitialValue,
|
||||
appJotaiStore,
|
||||
} from "./app-jotai";
|
||||
} from "@excalidraw/common";
|
||||
import polyfill from "@excalidraw/excalidraw/polyfill";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { loadFromBlob } from "@excalidraw/excalidraw/data/blob";
|
||||
import { useCallbackRefState } from "@excalidraw/excalidraw/hooks/useCallbackRefState";
|
||||
import { t } from "@excalidraw/excalidraw/i18n";
|
||||
|
||||
import "./index.scss";
|
||||
import type { ResolutionType } from "../packages/excalidraw/utility-types";
|
||||
import { ShareableLinkDialog } from "../packages/excalidraw/components/ShareableLinkDialog";
|
||||
import { openConfirmModal } from "../packages/excalidraw/components/OverwriteConfirm/OverwriteConfirmState";
|
||||
import { OverwriteConfirmDialog } from "../packages/excalidraw/components/OverwriteConfirm/OverwriteConfirm";
|
||||
import Trans from "../packages/excalidraw/components/Trans";
|
||||
import { ShareDialog, shareDialogStateAtom } from "./share/ShareDialog";
|
||||
import CollabError, { collabErrorIndicatorAtom } from "./collab/CollabError";
|
||||
import type { RemoteExcalidrawElement } from "../packages/excalidraw/data/reconcile";
|
||||
import type {
|
||||
DurableStoreIncrement,
|
||||
EphemeralStoreIncrement,
|
||||
} from "../packages/excalidraw/store";
|
||||
import { StoreDelta, StoreIncrement } from "../packages/excalidraw/store";
|
||||
import {
|
||||
CommandPalette,
|
||||
DEFAULT_CATEGORIES,
|
||||
} from "../packages/excalidraw/components/CommandPalette/CommandPalette";
|
||||
import {
|
||||
GithubIcon,
|
||||
XBrandIcon,
|
||||
|
@ -128,7 +51,87 @@ import {
|
|||
exportToPlus,
|
||||
share,
|
||||
youtubeIcon,
|
||||
} from "../packages/excalidraw/components/icons";
|
||||
} from "@excalidraw/excalidraw/components/icons";
|
||||
import { isElementLink } from "@excalidraw/element/elementLink";
|
||||
import { restore, restoreAppState } from "@excalidraw/excalidraw/data/restore";
|
||||
import { newElementWith } from "@excalidraw/element/mutateElement";
|
||||
import { isInitializedImageElement } from "@excalidraw/element/typeChecks";
|
||||
import clsx from "clsx";
|
||||
import {
|
||||
parseLibraryTokensFromUrl,
|
||||
useHandleLibrary,
|
||||
} from "@excalidraw/excalidraw/data/library";
|
||||
import { StoreDelta, DurableStoreIncrement, EphemeralStoreIncrement, StoreIncrement } from "@excalidraw/excalidraw/store";
|
||||
|
||||
import type { RemoteExcalidrawElement } from "@excalidraw/excalidraw/data/reconcile";
|
||||
import type { RestoredDataState } from "@excalidraw/excalidraw/data/restore";
|
||||
import type {
|
||||
FileId,
|
||||
NonDeletedExcalidrawElement,
|
||||
OrderedExcalidrawElement,
|
||||
SceneElementsMap,
|
||||
} from "@excalidraw/element/types";
|
||||
import type {
|
||||
AppState,
|
||||
ExcalidrawImperativeAPI,
|
||||
BinaryFiles,
|
||||
ExcalidrawInitialDataState,
|
||||
UIAppState,
|
||||
} from "@excalidraw/excalidraw/types";
|
||||
import type { ResolutionType } from "@excalidraw/common/utility-types";
|
||||
import type { ResolvablePromise } from "@excalidraw/common/utils";
|
||||
|
||||
import CustomStats from "./CustomStats";
|
||||
import {
|
||||
Provider,
|
||||
useAtom,
|
||||
useAtomValue,
|
||||
useAtomWithInitialValue,
|
||||
appJotaiStore,
|
||||
} from "./app-jotai";
|
||||
import {
|
||||
FIREBASE_STORAGE_PREFIXES,
|
||||
isExcalidrawPlusSignedUser,
|
||||
STORAGE_KEYS,
|
||||
SYNC_BROWSER_TABS_TIMEOUT,
|
||||
} from "./app_constants";
|
||||
import Collab, {
|
||||
collabAPIAtom,
|
||||
isCollaboratingAtom,
|
||||
isOfflineAtom,
|
||||
syncApiAtom,
|
||||
} from "./collab/Collab";
|
||||
import { AppFooter } from "./components/AppFooter";
|
||||
import { AppMainMenu } from "./components/AppMainMenu";
|
||||
import { AppWelcomeScreen } from "./components/AppWelcomeScreen";
|
||||
import {
|
||||
ExportToExcalidrawPlus,
|
||||
exportToExcalidrawPlus,
|
||||
} from "./components/ExportToExcalidrawPlus";
|
||||
import { TopErrorBoundary } from "./components/TopErrorBoundary";
|
||||
|
||||
import {
|
||||
exportToBackend,
|
||||
getCollaborationLinkData,
|
||||
isCollaborationLink,
|
||||
loadScene,
|
||||
} from "./data";
|
||||
|
||||
import { updateStaleImageStatuses } from "./data/FileManager";
|
||||
import {
|
||||
importFromLocalStorage,
|
||||
importUsernameFromLocalStorage,
|
||||
} from "./data/localStorage";
|
||||
|
||||
import { loadFilesFromFirebase } from "./data/firebase";
|
||||
import {
|
||||
LibraryIndexedDBAdapter,
|
||||
LibraryLocalStorageMigrationAdapter,
|
||||
LocalData,
|
||||
} from "./data/LocalData";
|
||||
import { isBrowserStorageStateNewer } from "./data/tabSync";
|
||||
import { ShareDialog, shareDialogStateAtom } from "./share/ShareDialog";
|
||||
import CollabError, { collabErrorIndicatorAtom } from "./collab/CollabError";
|
||||
import { useHandleAppTheme } from "./useHandleAppTheme";
|
||||
import { getPreferredLanguage } from "./app-language/language-detector";
|
||||
import { useAppLangCode } from "./app-language/language-state";
|
||||
|
@ -139,10 +142,10 @@ import DebugCanvas, {
|
|||
} from "./components/DebugCanvas";
|
||||
import { AIComponents } from "./components/AI";
|
||||
import { ExcalidrawPlusIframeExport } from "./ExcalidrawPlusIframeExport";
|
||||
import { isElementLink } from "../packages/excalidraw/element/elementLink";
|
||||
|
||||
import Slider from "rc-slider";
|
||||
import "rc-slider/assets/index.css";
|
||||
import "./index.scss";
|
||||
|
||||
import type { CollabAPI } from "./collab/Collab";
|
||||
|
||||
polyfill();
|
||||
|
||||
|
@ -417,7 +420,7 @@ const ExcalidrawWrapper = () => {
|
|||
const [, forceRefresh] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (import.meta.env.DEV) {
|
||||
if (isDevEnv()) {
|
||||
const debugState = loadSavedDebugState();
|
||||
|
||||
if (debugState.enabled && !window.visualDebug) {
|
||||
|
@ -526,7 +529,7 @@ const ExcalidrawWrapper = () => {
|
|||
excalidrawAPI.updateScene({
|
||||
...data.scene,
|
||||
...restore(data.scene, null, null, { repairBindings: true }),
|
||||
storeAction: StoreAction.CAPTURE,
|
||||
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -553,7 +556,7 @@ const ExcalidrawWrapper = () => {
|
|||
setLangCode(getPreferredLanguage());
|
||||
excalidrawAPI.updateScene({
|
||||
...localDataState,
|
||||
storeAction: StoreAction.UPDATE,
|
||||
captureUpdate: CaptureUpdateAction.NEVER,
|
||||
});
|
||||
LibraryIndexedDBAdapter.load().then((data) => {
|
||||
if (data) {
|
||||
|
@ -685,7 +688,7 @@ const ExcalidrawWrapper = () => {
|
|||
if (didChange) {
|
||||
excalidrawAPI.updateScene({
|
||||
elements,
|
||||
storeAction: StoreAction.UPDATE,
|
||||
captureUpdate: CaptureUpdateAction.NEVER,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -898,7 +901,7 @@ const ExcalidrawWrapper = () => {
|
|||
viewModeEnabled: value !== acknowledgedDeltas.length,
|
||||
},
|
||||
elements: Array.from(nextElements.values()),
|
||||
storeAction: StoreAction.UPDATE,
|
||||
captureUpdate: CaptureUpdateAction.NEVER,
|
||||
});
|
||||
},
|
||||
0,
|
||||
|
|
|
@ -1,15 +1,21 @@
|
|||
import { Stats } from "@excalidraw/excalidraw";
|
||||
import { copyTextToSystemClipboard } from "@excalidraw/excalidraw/clipboard";
|
||||
import {
|
||||
DEFAULT_VERSION,
|
||||
debounce,
|
||||
getVersion,
|
||||
nFormatter,
|
||||
} from "@excalidraw/common";
|
||||
import { t } from "@excalidraw/excalidraw/i18n";
|
||||
import { useEffect, useState } from "react";
|
||||
import { debounce, getVersion, nFormatter } from "../packages/excalidraw/utils";
|
||||
|
||||
import type { NonDeletedExcalidrawElement } from "@excalidraw/element/types";
|
||||
import type { UIAppState } from "@excalidraw/excalidraw/types";
|
||||
|
||||
import {
|
||||
getElementsStorageSize,
|
||||
getTotalStorageSize,
|
||||
} from "./data/localStorage";
|
||||
import { DEFAULT_VERSION } from "../packages/excalidraw/constants";
|
||||
import { t } from "../packages/excalidraw/i18n";
|
||||
import { copyTextToSystemClipboard } from "../packages/excalidraw/clipboard";
|
||||
import type { NonDeletedExcalidrawElement } from "../packages/excalidraw/element/types";
|
||||
import type { UIAppState } from "../packages/excalidraw/types";
|
||||
import { Stats } from "../packages/excalidraw";
|
||||
|
||||
type StorageSizes = { scene: number; total: number };
|
||||
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
import { base64urlToString } from "@excalidraw/excalidraw/data/encode";
|
||||
import { ExcalidrawError } from "@excalidraw/excalidraw/errors";
|
||||
import { useLayoutEffect, useRef } from "react";
|
||||
import { STORAGE_KEYS } from "./app_constants";
|
||||
import { LocalData } from "./data/LocalData";
|
||||
|
||||
import type {
|
||||
FileId,
|
||||
OrderedExcalidrawElement,
|
||||
} from "../packages/excalidraw/element/types";
|
||||
import type { AppState, BinaryFileData } from "../packages/excalidraw/types";
|
||||
import { ExcalidrawError } from "../packages/excalidraw/errors";
|
||||
import { base64urlToString } from "../packages/excalidraw/data/encode";
|
||||
} from "@excalidraw/element/types";
|
||||
import type { AppState, BinaryFileData } from "@excalidraw/excalidraw/types";
|
||||
|
||||
import { STORAGE_KEYS } from "./app_constants";
|
||||
import { LocalData } from "./data/LocalData";
|
||||
|
||||
const EVENT_REQUEST_SCENE = "REQUEST_SCENE";
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { useI18n, languages } from "@excalidraw/excalidraw/i18n";
|
||||
import React from "react";
|
||||
import { useI18n, languages } from "../../packages/excalidraw/i18n";
|
||||
|
||||
import { useSetAtom } from "../app-jotai";
|
||||
|
||||
import { appLangCodeAtom } from "./language-state";
|
||||
|
||||
export const LanguageList = ({ style }: { style?: React.CSSProperties }) => {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { defaultLang, languages } from "@excalidraw/excalidraw";
|
||||
import LanguageDetector from "i18next-browser-languagedetector";
|
||||
import { defaultLang, languages } from "../../packages/excalidraw";
|
||||
|
||||
export const languageDetector = new LanguageDetector();
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import { useEffect } from "react";
|
||||
|
||||
import { atom, useAtom } from "../app-jotai";
|
||||
|
||||
import { getPreferredLanguage, languageDetector } from "./language-detector";
|
||||
|
||||
export const appLangCodeAtom = atom(getPreferredLanguage());
|
||||
|
|
|
@ -1,33 +1,58 @@
|
|||
import {
|
||||
CaptureUpdateAction,
|
||||
getSceneVersion,
|
||||
restoreElements,
|
||||
zoomToFitBounds,
|
||||
reconcileElements,
|
||||
} from "@excalidraw/excalidraw";
|
||||
import { ErrorDialog } from "@excalidraw/excalidraw/components/ErrorDialog";
|
||||
import { APP_NAME, EVENT } from "@excalidraw/common";
|
||||
import {
|
||||
IDLE_THRESHOLD,
|
||||
ACTIVE_THRESHOLD,
|
||||
UserIdleState,
|
||||
assertNever,
|
||||
isDevEnv,
|
||||
isTestEnv,
|
||||
preventUnload,
|
||||
resolvablePromise,
|
||||
throttleRAF,
|
||||
} from "@excalidraw/common";
|
||||
import { decryptData } from "@excalidraw/excalidraw/data/encryption";
|
||||
import { getVisibleSceneBounds } from "@excalidraw/element/bounds";
|
||||
import { newElementWith } from "@excalidraw/element/mutateElement";
|
||||
import {
|
||||
isImageElement,
|
||||
isInitializedImageElement,
|
||||
} from "@excalidraw/element/typeChecks";
|
||||
import { AbortError } from "@excalidraw/excalidraw/errors";
|
||||
import { t } from "@excalidraw/excalidraw/i18n";
|
||||
import { withBatchedUpdates } from "@excalidraw/excalidraw/reactUtils";
|
||||
|
||||
import throttle from "lodash.throttle";
|
||||
import { PureComponent } from "react";
|
||||
|
||||
import type {
|
||||
BinaryFileData,
|
||||
ExcalidrawImperativeAPI,
|
||||
SocketId,
|
||||
} from "../../packages/excalidraw/types";
|
||||
import { ErrorDialog } from "../../packages/excalidraw/components/ErrorDialog";
|
||||
import { APP_NAME, ENV, EVENT } from "../../packages/excalidraw/constants";
|
||||
import type { ImportedDataState } from "../../packages/excalidraw/data/types";
|
||||
ReconciledExcalidrawElement,
|
||||
RemoteExcalidrawElement,
|
||||
} from "@excalidraw/excalidraw/data/reconcile";
|
||||
import type { ImportedDataState } from "@excalidraw/excalidraw/data/types";
|
||||
import type {
|
||||
ExcalidrawElement,
|
||||
FileId,
|
||||
InitializedExcalidrawImageElement,
|
||||
OrderedExcalidrawElement,
|
||||
} from "../../packages/excalidraw/element/types";
|
||||
import {
|
||||
StoreAction,
|
||||
getSceneVersion,
|
||||
restoreElements,
|
||||
zoomToFitBounds,
|
||||
reconcileElements,
|
||||
} from "../../packages/excalidraw";
|
||||
import type { Collaborator, Gesture } from "../../packages/excalidraw/types";
|
||||
import {
|
||||
assertNever,
|
||||
preventUnload,
|
||||
resolvablePromise,
|
||||
throttleRAF,
|
||||
} from "../../packages/excalidraw/utils";
|
||||
} from "@excalidraw/element/types";
|
||||
import type {
|
||||
BinaryFileData,
|
||||
ExcalidrawImperativeAPI,
|
||||
SocketId,
|
||||
Collaborator,
|
||||
Gesture,
|
||||
} from "@excalidraw/excalidraw/types";
|
||||
import type { Mutable, ValueOf } from "@excalidraw/common/utility-types";
|
||||
|
||||
import { appJotaiStore, atom } from "../app-jotai";
|
||||
import {
|
||||
CURSOR_SYNC_TIMEOUT,
|
||||
FILE_UPLOAD_MAX_BYTES,
|
||||
|
@ -38,15 +63,17 @@ import {
|
|||
SYNC_FULL_SCENE_INTERVAL_MS,
|
||||
WS_EVENTS,
|
||||
} from "../app_constants";
|
||||
import type {
|
||||
SocketUpdateDataSource,
|
||||
SyncableExcalidrawElement,
|
||||
} from "../data";
|
||||
import {
|
||||
generateCollaborationLinkData,
|
||||
getCollaborationLink,
|
||||
getSyncableElements,
|
||||
} from "../data";
|
||||
import {
|
||||
encodeFilesForUpload,
|
||||
FileManager,
|
||||
updateStaleImageStatuses,
|
||||
} from "../data/FileManager";
|
||||
import { LocalData, SyncIndexedDBAdapter } from "../data/LocalData";
|
||||
import {
|
||||
isSavedToFirebase,
|
||||
loadFilesFromFirebase,
|
||||
|
@ -58,37 +85,15 @@ import {
|
|||
importUsernameFromLocalStorage,
|
||||
saveUsernameToLocalStorage,
|
||||
} from "../data/localStorage";
|
||||
import Portal from "./Portal";
|
||||
import { t } from "../../packages/excalidraw/i18n";
|
||||
import { UserIdleState } from "../../packages/excalidraw/types";
|
||||
import {
|
||||
IDLE_THRESHOLD,
|
||||
ACTIVE_THRESHOLD,
|
||||
} from "../../packages/excalidraw/constants";
|
||||
import {
|
||||
encodeFilesForUpload,
|
||||
FileManager,
|
||||
updateStaleImageStatuses,
|
||||
} from "../data/FileManager";
|
||||
import { AbortError } from "../../packages/excalidraw/errors";
|
||||
import {
|
||||
isImageElement,
|
||||
isInitializedImageElement,
|
||||
} from "../../packages/excalidraw/element/typeChecks";
|
||||
import { newElementWith } from "../../packages/excalidraw/element/mutateElement";
|
||||
import { decryptData } from "../../packages/excalidraw/data/encryption";
|
||||
import { resetBrowserStateVersions } from "../data/tabSync";
|
||||
import { LocalData, SyncIndexedDBAdapter } from "../data/LocalData";
|
||||
import { appJotaiStore, atom } from "../app-jotai";
|
||||
import type { Mutable, ValueOf } from "../../packages/excalidraw/utility-types";
|
||||
import { getVisibleSceneBounds } from "../../packages/excalidraw/element/bounds";
|
||||
import { withBatchedUpdates } from "../../packages/excalidraw/reactUtils";
|
||||
|
||||
import { collabErrorIndicatorAtom } from "./CollabError";
|
||||
import Portal from "./Portal";
|
||||
|
||||
import type {
|
||||
ReconciledExcalidrawElement,
|
||||
RemoteExcalidrawElement,
|
||||
} from "../../packages/excalidraw/data/reconcile";
|
||||
import { SyncClient } from "../../packages/excalidraw/sync/client";
|
||||
SocketUpdateDataSource,
|
||||
SyncableExcalidrawElement,
|
||||
} from "../data";
|
||||
|
||||
export const syncApiAtom = atom<SyncClient | null>(null);
|
||||
export const collabAPIAtom = atom<CollabAPI | null>(null);
|
||||
|
@ -243,7 +248,7 @@ class Collab extends PureComponent<CollabProps, CollabState> {
|
|||
},
|
||||
);
|
||||
|
||||
if (import.meta.env.MODE === ENV.TEST || import.meta.env.DEV) {
|
||||
if (isTestEnv() || isDevEnv()) {
|
||||
window.collab = window.collab || ({} as Window["collab"]);
|
||||
Object.defineProperties(window, {
|
||||
collab: {
|
||||
|
@ -393,7 +398,7 @@ class Collab extends PureComponent<CollabProps, CollabState> {
|
|||
|
||||
this.excalidrawAPI.updateScene({
|
||||
elements,
|
||||
storeAction: StoreAction.UPDATE,
|
||||
captureUpdate: CaptureUpdateAction.NEVER,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -544,7 +549,7 @@ class Collab extends PureComponent<CollabProps, CollabState> {
|
|||
// to database even if deleted before creating the room.
|
||||
this.excalidrawAPI.updateScene({
|
||||
elements,
|
||||
storeAction: StoreAction.UPDATE,
|
||||
captureUpdate: CaptureUpdateAction.NEVER,
|
||||
});
|
||||
|
||||
this.saveCollabRoomToFirebase(getSyncableElements(elements));
|
||||
|
@ -782,7 +787,7 @@ class Collab extends PureComponent<CollabProps, CollabState> {
|
|||
) => {
|
||||
this.excalidrawAPI.updateScene({
|
||||
elements,
|
||||
storeAction: StoreAction.UPDATE,
|
||||
captureUpdate: CaptureUpdateAction.NEVER,
|
||||
});
|
||||
|
||||
this.loadImageFiles();
|
||||
|
@ -1018,7 +1023,7 @@ declare global {
|
|||
}
|
||||
}
|
||||
|
||||
if (import.meta.env.MODE === ENV.TEST || import.meta.env.DEV) {
|
||||
if (isTestEnv() || isDevEnv()) {
|
||||
window.collab = window.collab || ({} as Window["collab"]);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { Tooltip } from "../../packages/excalidraw/components/Tooltip";
|
||||
import { warning } from "../../packages/excalidraw/components/icons";
|
||||
import { Tooltip } from "@excalidraw/excalidraw/components/Tooltip";
|
||||
import { warning } from "@excalidraw/excalidraw/components/icons";
|
||||
import clsx from "clsx";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
import { atom } from "../app-jotai";
|
||||
|
||||
import "./CollabError.scss";
|
||||
|
@ -19,16 +20,16 @@ export const collabErrorIndicatorAtom = atom<ErrorIndicator>({
|
|||
|
||||
const CollabError = ({ collabError }: { collabError: ErrorIndicator }) => {
|
||||
const [isAnimating, setIsAnimating] = useState(false);
|
||||
const clearAnimationRef = useRef<string | number | NodeJS.Timeout>();
|
||||
const clearAnimationRef = useRef<string | number>(0);
|
||||
|
||||
useEffect(() => {
|
||||
setIsAnimating(true);
|
||||
clearAnimationRef.current = setTimeout(() => {
|
||||
clearAnimationRef.current = window.setTimeout(() => {
|
||||
setIsAnimating(false);
|
||||
}, 1000);
|
||||
|
||||
return () => {
|
||||
clearTimeout(clearAnimationRef.current);
|
||||
window.clearTimeout(clearAnimationRef.current);
|
||||
};
|
||||
}, [collabError.message, collabError.nonce]);
|
||||
|
||||
|
|
|
@ -1,25 +1,26 @@
|
|||
import { CaptureUpdateAction } from "@excalidraw/excalidraw";
|
||||
import { trackEvent } from "@excalidraw/excalidraw/analytics";
|
||||
import { encryptData } from "@excalidraw/excalidraw/data/encryption";
|
||||
import { newElementWith } from "@excalidraw/element/mutateElement";
|
||||
import throttle from "lodash.throttle";
|
||||
|
||||
import type { UserIdleState } from "@excalidraw/common";
|
||||
import type { OrderedExcalidrawElement } from "@excalidraw/element/types";
|
||||
import type {
|
||||
OnUserFollowedPayload,
|
||||
SocketId,
|
||||
} from "@excalidraw/excalidraw/types";
|
||||
|
||||
import { WS_EVENTS, FILE_UPLOAD_TIMEOUT, WS_SUBTYPES } from "../app_constants";
|
||||
import { isSyncableElement } from "../data";
|
||||
|
||||
import type {
|
||||
SocketUpdateData,
|
||||
SocketUpdateDataSource,
|
||||
SyncableExcalidrawElement,
|
||||
} from "../data";
|
||||
import { isSyncableElement } from "../data";
|
||||
|
||||
import type { TCollabClass } from "./Collab";
|
||||
|
||||
import type { OrderedExcalidrawElement } from "../../packages/excalidraw/element/types";
|
||||
import { WS_EVENTS, FILE_UPLOAD_TIMEOUT, WS_SUBTYPES } from "../app_constants";
|
||||
import type {
|
||||
OnUserFollowedPayload,
|
||||
SocketId,
|
||||
UserIdleState,
|
||||
} from "../../packages/excalidraw/types";
|
||||
import { trackEvent } from "../../packages/excalidraw/analytics";
|
||||
import throttle from "lodash.throttle";
|
||||
import { newElementWith } from "../../packages/excalidraw/element/mutateElement";
|
||||
import { encryptData } from "../../packages/excalidraw/data/encryption";
|
||||
import type { Socket } from "socket.io-client";
|
||||
import { StoreAction } from "../../packages/excalidraw";
|
||||
|
||||
class Portal {
|
||||
collab: TCollabClass;
|
||||
|
@ -133,7 +134,7 @@ class Portal {
|
|||
if (isChanged) {
|
||||
this.collab.excalidrawAPI.updateScene({
|
||||
elements: newElements,
|
||||
storeAction: StoreAction.UPDATE,
|
||||
captureUpdate: CaptureUpdateAction.NEVER,
|
||||
});
|
||||
}
|
||||
}, FILE_UPLOAD_TIMEOUT);
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import type { ExcalidrawImperativeAPI } from "../../packages/excalidraw/types";
|
||||
import {
|
||||
DiagramToCodePlugin,
|
||||
exportToBlob,
|
||||
getTextFromElements,
|
||||
MIME_TYPES,
|
||||
TTDDialog,
|
||||
} from "../../packages/excalidraw";
|
||||
import { getDataURL } from "../../packages/excalidraw/data/blob";
|
||||
import { safelyParseJSON } from "../../packages/excalidraw/utils";
|
||||
} from "@excalidraw/excalidraw";
|
||||
import { getDataURL } from "@excalidraw/excalidraw/data/blob";
|
||||
import { safelyParseJSON } from "@excalidraw/common";
|
||||
|
||||
import type { ExcalidrawImperativeAPI } from "@excalidraw/excalidraw/types";
|
||||
|
||||
export const AIComponents = ({
|
||||
excalidrawAPI,
|
||||
|
@ -83,7 +84,6 @@ export const AIComponents = ({
|
|||
}
|
||||
|
||||
try {
|
||||
// @ts-expect-error
|
||||
const { html } = await response.json();
|
||||
|
||||
if (!html) {
|
||||
|
@ -141,11 +141,9 @@ export const AIComponents = ({
|
|||
};
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
throw new Error(json.message || "Generation failed...");
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
const generatedResponse = json.generatedResponse;
|
||||
if (!generatedResponse) {
|
||||
throw new Error("Generation failed...");
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import { Footer } from "@excalidraw/excalidraw/index";
|
||||
import React from "react";
|
||||
import { Footer } from "../../packages/excalidraw/index";
|
||||
|
||||
import { isExcalidrawPlusSignedUser } from "../app_constants";
|
||||
|
||||
import { DebugFooter, isVisualDebuggerEnabled } from "./DebugCanvas";
|
||||
import { EncryptedIcon } from "./EncryptedIcon";
|
||||
import { ExcalidrawPlusAppLink } from "./ExcalidrawPlusAppLink";
|
||||
import { isExcalidrawPlusSignedUser } from "../app_constants";
|
||||
import { DebugFooter, isVisualDebuggerEnabled } from "./DebugCanvas";
|
||||
|
||||
export const AppFooter = React.memo(
|
||||
({ onChange }: { onChange: () => void }) => {
|
||||
|
|
|
@ -1,13 +1,18 @@
|
|||
import React from "react";
|
||||
import {
|
||||
loginIcon,
|
||||
ExcalLogo,
|
||||
eyeIcon,
|
||||
} from "../../packages/excalidraw/components/icons";
|
||||
import type { Theme } from "../../packages/excalidraw/element/types";
|
||||
import { MainMenu } from "../../packages/excalidraw/index";
|
||||
import { isExcalidrawPlusSignedUser } from "../app_constants";
|
||||
} from "@excalidraw/excalidraw/components/icons";
|
||||
import { MainMenu } from "@excalidraw/excalidraw/index";
|
||||
import React from "react";
|
||||
|
||||
import { isDevEnv } from "@excalidraw/common";
|
||||
|
||||
import type { Theme } from "@excalidraw/element/types";
|
||||
|
||||
import { LanguageList } from "../app-language/LanguageList";
|
||||
import { isExcalidrawPlusSignedUser } from "../app_constants";
|
||||
|
||||
import { saveDebugState } from "./DebugCanvas";
|
||||
|
||||
export const AppMainMenu: React.FC<{
|
||||
|
@ -54,7 +59,7 @@ export const AppMainMenu: React.FC<{
|
|||
>
|
||||
{isExcalidrawPlusSignedUser ? "Sign in" : "Sign up"}
|
||||
</MainMenu.ItemLink>
|
||||
{import.meta.env.DEV && (
|
||||
{isDevEnv() && (
|
||||
<MainMenu.Item
|
||||
icon={eyeIcon}
|
||||
onClick={() => {
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { loginIcon } from "@excalidraw/excalidraw/components/icons";
|
||||
import { POINTER_EVENTS } from "@excalidraw/common";
|
||||
import { useI18n } from "@excalidraw/excalidraw/i18n";
|
||||
import { WelcomeScreen } from "@excalidraw/excalidraw/index";
|
||||
import React from "react";
|
||||
import { loginIcon } from "../../packages/excalidraw/components/icons";
|
||||
import { useI18n } from "../../packages/excalidraw/i18n";
|
||||
import { WelcomeScreen } from "../../packages/excalidraw/index";
|
||||
|
||||
import { isExcalidrawPlusSignedUser } from "../app_constants";
|
||||
import { POINTER_EVENTS } from "../../packages/excalidraw/constants";
|
||||
|
||||
export const AppWelcomeScreen: React.FC<{
|
||||
onCollabDialogOpen: () => any;
|
||||
|
|
|
@ -1,22 +1,28 @@
|
|||
import { forwardRef, useCallback, useImperativeHandle, useRef } from "react";
|
||||
import { type AppState } from "../../packages/excalidraw/types";
|
||||
import { throttleRAF } from "../../packages/excalidraw/utils";
|
||||
import {
|
||||
bootstrapCanvas,
|
||||
getNormalizedCanvasDimensions,
|
||||
} from "../../packages/excalidraw/renderer/helpers";
|
||||
import type { DebugElement } from "../../packages/excalidraw/visualdebug";
|
||||
import {
|
||||
ArrowheadArrowIcon,
|
||||
CloseIcon,
|
||||
TrashIcon,
|
||||
} from "../../packages/excalidraw/components/icons";
|
||||
import { STORAGE_KEYS } from "../app_constants";
|
||||
} from "@excalidraw/excalidraw/components/icons";
|
||||
import {
|
||||
bootstrapCanvas,
|
||||
getNormalizedCanvasDimensions,
|
||||
} from "@excalidraw/excalidraw/renderer/helpers";
|
||||
import { type AppState } from "@excalidraw/excalidraw/types";
|
||||
import { throttleRAF } from "@excalidraw/common";
|
||||
import { useCallback, useImperativeHandle, useRef } from "react";
|
||||
|
||||
import {
|
||||
isLineSegment,
|
||||
type GlobalPoint,
|
||||
type LineSegment,
|
||||
} from "../../packages/math";
|
||||
} from "@excalidraw/math";
|
||||
import { isCurve } from "@excalidraw/math/curve";
|
||||
|
||||
import type { DebugElement } from "@excalidraw/excalidraw/visualdebug";
|
||||
|
||||
import type { Curve } from "@excalidraw/math";
|
||||
|
||||
import { STORAGE_KEYS } from "../app_constants";
|
||||
|
||||
const renderLine = (
|
||||
context: CanvasRenderingContext2D,
|
||||
|
@ -33,6 +39,28 @@ const renderLine = (
|
|||
context.restore();
|
||||
};
|
||||
|
||||
const renderCubicBezier = (
|
||||
context: CanvasRenderingContext2D,
|
||||
zoom: number,
|
||||
[start, control1, control2, end]: Curve<GlobalPoint>,
|
||||
color: string,
|
||||
) => {
|
||||
context.save();
|
||||
context.strokeStyle = color;
|
||||
context.beginPath();
|
||||
context.moveTo(start[0] * zoom, start[1] * zoom);
|
||||
context.bezierCurveTo(
|
||||
control1[0] * zoom,
|
||||
control1[1] * zoom,
|
||||
control2[0] * zoom,
|
||||
control2[1] * zoom,
|
||||
end[0] * zoom,
|
||||
end[1] * zoom,
|
||||
);
|
||||
context.stroke();
|
||||
context.restore();
|
||||
};
|
||||
|
||||
const renderOrigin = (context: CanvasRenderingContext2D, zoom: number) => {
|
||||
context.strokeStyle = "#888";
|
||||
context.save();
|
||||
|
@ -60,6 +88,16 @@ const render = (
|
|||
el.color,
|
||||
);
|
||||
break;
|
||||
case isCurve(el.data):
|
||||
renderCubicBezier(
|
||||
context,
|
||||
appState.zoom.value,
|
||||
el.data as Curve<GlobalPoint>,
|
||||
el.color,
|
||||
);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown element type ${JSON.stringify(el)}`);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -276,36 +314,35 @@ export const DebugFooter = ({ onChange }: { onChange: () => void }) => {
|
|||
interface DebugCanvasProps {
|
||||
appState: AppState;
|
||||
scale: number;
|
||||
ref?: React.Ref<HTMLCanvasElement>;
|
||||
}
|
||||
|
||||
const DebugCanvas = forwardRef<HTMLCanvasElement, DebugCanvasProps>(
|
||||
({ appState, scale }, ref) => {
|
||||
const { width, height } = appState;
|
||||
const DebugCanvas = ({ appState, scale, ref }: DebugCanvasProps) => {
|
||||
const { width, height } = appState;
|
||||
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
useImperativeHandle<HTMLCanvasElement | null, HTMLCanvasElement | null>(
|
||||
ref,
|
||||
() => canvasRef.current,
|
||||
[canvasRef],
|
||||
);
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
useImperativeHandle<HTMLCanvasElement | null, HTMLCanvasElement | null>(
|
||||
ref,
|
||||
() => canvasRef.current,
|
||||
[canvasRef],
|
||||
);
|
||||
|
||||
return (
|
||||
<canvas
|
||||
style={{
|
||||
width,
|
||||
height,
|
||||
position: "absolute",
|
||||
zIndex: 2,
|
||||
pointerEvents: "none",
|
||||
}}
|
||||
width={width * scale}
|
||||
height={height * scale}
|
||||
ref={canvasRef}
|
||||
>
|
||||
Debug Canvas
|
||||
</canvas>
|
||||
);
|
||||
},
|
||||
);
|
||||
return (
|
||||
<canvas
|
||||
style={{
|
||||
width,
|
||||
height,
|
||||
position: "absolute",
|
||||
zIndex: 2,
|
||||
pointerEvents: "none",
|
||||
}}
|
||||
width={width * scale}
|
||||
height={height * scale}
|
||||
ref={canvasRef}
|
||||
>
|
||||
Debug Canvas
|
||||
</canvas>
|
||||
);
|
||||
};
|
||||
|
||||
export default DebugCanvas;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { shield } from "../../packages/excalidraw/components/icons";
|
||||
import { Tooltip } from "../../packages/excalidraw/components/Tooltip";
|
||||
import { useI18n } from "../../packages/excalidraw/i18n";
|
||||
import { Tooltip } from "@excalidraw/excalidraw/components/Tooltip";
|
||||
import { shield } from "@excalidraw/excalidraw/components/icons";
|
||||
import { useI18n } from "@excalidraw/excalidraw/i18n";
|
||||
|
||||
export const EncryptedIcon = () => {
|
||||
const { t } = useI18n();
|
||||
|
|
|
@ -1,30 +1,33 @@
|
|||
import React from "react";
|
||||
import { Card } from "../../packages/excalidraw/components/Card";
|
||||
import { ToolButton } from "../../packages/excalidraw/components/ToolButton";
|
||||
import { serializeAsJSON } from "../../packages/excalidraw/data/json";
|
||||
import { loadFirebaseStorage, saveFilesToFirebase } from "../data/firebase";
|
||||
import { uploadBytes, ref } from "firebase/storage";
|
||||
import { nanoid } from "nanoid";
|
||||
|
||||
import { trackEvent } from "@excalidraw/excalidraw/analytics";
|
||||
import { Card } from "@excalidraw/excalidraw/components/Card";
|
||||
import { ExcalidrawLogo } from "@excalidraw/excalidraw/components/ExcalidrawLogo";
|
||||
import { ToolButton } from "@excalidraw/excalidraw/components/ToolButton";
|
||||
import { MIME_TYPES, getFrame } from "@excalidraw/common";
|
||||
import {
|
||||
encryptData,
|
||||
generateEncryptionKey,
|
||||
} from "@excalidraw/excalidraw/data/encryption";
|
||||
import { serializeAsJSON } from "@excalidraw/excalidraw/data/json";
|
||||
import { isInitializedImageElement } from "@excalidraw/element/typeChecks";
|
||||
import { useI18n } from "@excalidraw/excalidraw/i18n";
|
||||
|
||||
import type {
|
||||
FileId,
|
||||
NonDeletedExcalidrawElement,
|
||||
} from "../../packages/excalidraw/element/types";
|
||||
} from "@excalidraw/element/types";
|
||||
import type {
|
||||
AppState,
|
||||
BinaryFileData,
|
||||
BinaryFiles,
|
||||
} from "../../packages/excalidraw/types";
|
||||
import { nanoid } from "nanoid";
|
||||
import { useI18n } from "../../packages/excalidraw/i18n";
|
||||
import {
|
||||
encryptData,
|
||||
generateEncryptionKey,
|
||||
} from "../../packages/excalidraw/data/encryption";
|
||||
import { isInitializedImageElement } from "../../packages/excalidraw/element/typeChecks";
|
||||
} from "@excalidraw/excalidraw/types";
|
||||
|
||||
import { FILE_UPLOAD_MAX_BYTES } from "../app_constants";
|
||||
import { encodeFilesForUpload } from "../data/FileManager";
|
||||
import { MIME_TYPES } from "../../packages/excalidraw/constants";
|
||||
import { trackEvent } from "../../packages/excalidraw/analytics";
|
||||
import { getFrame } from "../../packages/excalidraw/utils";
|
||||
import { ExcalidrawLogo } from "../../packages/excalidraw/components/ExcalidrawLogo";
|
||||
import { loadFirebaseStorage, saveFilesToFirebase } from "../data/firebase";
|
||||
|
||||
export const exportToExcalidrawPlus = async (
|
||||
elements: readonly NonDeletedExcalidrawElement[],
|
||||
|
@ -32,7 +35,7 @@ export const exportToExcalidrawPlus = async (
|
|||
files: BinaryFiles,
|
||||
name: string,
|
||||
) => {
|
||||
const firebase = await loadFirebaseStorage();
|
||||
const storage = await loadFirebaseStorage();
|
||||
|
||||
const id = `${nanoid(12)}`;
|
||||
|
||||
|
@ -49,15 +52,13 @@ export const exportToExcalidrawPlus = async (
|
|||
},
|
||||
);
|
||||
|
||||
await firebase
|
||||
.storage()
|
||||
.ref(`/migrations/scenes/${id}`)
|
||||
.put(blob, {
|
||||
customMetadata: {
|
||||
data: JSON.stringify({ version: 2, name }),
|
||||
created: Date.now().toString(),
|
||||
},
|
||||
});
|
||||
const storageRef = ref(storage, `/migrations/scenes/${id}`);
|
||||
await uploadBytes(storageRef, blob, {
|
||||
customMetadata: {
|
||||
data: JSON.stringify({ version: 2, name }),
|
||||
created: Date.now().toString(),
|
||||
},
|
||||
});
|
||||
|
||||
const filesMap = new Map<FileId, BinaryFileData>();
|
||||
for (const element of elements) {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { THEME } from "@excalidraw/common";
|
||||
import oc from "open-color";
|
||||
import React from "react";
|
||||
import { THEME } from "../../packages/excalidraw/constants";
|
||||
import type { Theme } from "../../packages/excalidraw/element/types";
|
||||
|
||||
import type { Theme } from "@excalidraw/element/types";
|
||||
|
||||
// https://github.com/tholman/github-corners
|
||||
export const GitHubCorner = React.memo(
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from "react";
|
||||
import Trans from "@excalidraw/excalidraw/components/Trans";
|
||||
import { t } from "@excalidraw/excalidraw/i18n";
|
||||
import * as Sentry from "@sentry/browser";
|
||||
import { t } from "../../packages/excalidraw/i18n";
|
||||
import Trans from "../../packages/excalidraw/components/Trans";
|
||||
import React from "react";
|
||||
|
||||
interface TopErrorBoundaryState {
|
||||
hasError: boolean;
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
import { StoreAction } from "../../packages/excalidraw";
|
||||
import { compressData } from "../../packages/excalidraw/data/encode";
|
||||
import { newElementWith } from "../../packages/excalidraw/element/mutateElement";
|
||||
import { isInitializedImageElement } from "../../packages/excalidraw/element/typeChecks";
|
||||
import { CaptureUpdateAction } from "@excalidraw/excalidraw";
|
||||
import { compressData } from "@excalidraw/excalidraw/data/encode";
|
||||
import { newElementWith } from "@excalidraw/element/mutateElement";
|
||||
import { isInitializedImageElement } from "@excalidraw/element/typeChecks";
|
||||
import { t } from "@excalidraw/excalidraw/i18n";
|
||||
|
||||
import type {
|
||||
ExcalidrawElement,
|
||||
ExcalidrawImageElement,
|
||||
FileId,
|
||||
InitializedExcalidrawImageElement,
|
||||
} from "../../packages/excalidraw/element/types";
|
||||
import { t } from "../../packages/excalidraw/i18n";
|
||||
} from "@excalidraw/element/types";
|
||||
import type {
|
||||
BinaryFileData,
|
||||
BinaryFileMetadata,
|
||||
ExcalidrawImperativeAPI,
|
||||
BinaryFiles,
|
||||
} from "../../packages/excalidraw/types";
|
||||
} from "@excalidraw/excalidraw/types";
|
||||
|
||||
type FileVersion = Required<BinaryFileData>["version"];
|
||||
|
||||
|
@ -268,6 +269,6 @@ export const updateStaleImageStatuses = (params: {
|
|||
}
|
||||
return element;
|
||||
}),
|
||||
storeAction: StoreAction.UPDATE,
|
||||
captureUpdate: CaptureUpdateAction.NEVER,
|
||||
});
|
||||
};
|
||||
|
|
|
@ -10,6 +10,13 @@
|
|||
* (localStorage, indexedDB).
|
||||
*/
|
||||
|
||||
import { clearAppStateForLocalStorage } from "@excalidraw/excalidraw/appState";
|
||||
import {
|
||||
CANVAS_SEARCH_TAB,
|
||||
DEFAULT_SIDEBAR,
|
||||
debounce,
|
||||
} from "@excalidraw/common";
|
||||
import { clearElementsForLocalStorage } from "@excalidraw/element";
|
||||
import {
|
||||
createStore,
|
||||
entries,
|
||||
|
@ -19,33 +26,24 @@ import {
|
|||
setMany,
|
||||
get,
|
||||
} from "idb-keyval";
|
||||
import { clearAppStateForLocalStorage } from "../../packages/excalidraw/appState";
|
||||
import {
|
||||
CANVAS_SEARCH_TAB,
|
||||
DEFAULT_SIDEBAR,
|
||||
} from "../../packages/excalidraw/constants";
|
||||
import type { LibraryPersistedData } from "../../packages/excalidraw/data/library";
|
||||
import type { ImportedDataState } from "../../packages/excalidraw/data/types";
|
||||
import { clearElementsForLocalStorage } from "../../packages/excalidraw/element";
|
||||
import type {
|
||||
ExcalidrawElement,
|
||||
FileId,
|
||||
} from "../../packages/excalidraw/element/types";
|
||||
|
||||
import { StoreDelta } from "@excalidraw/excalidraw/store";
|
||||
|
||||
import type { LibraryPersistedData } from "@excalidraw/excalidraw/data/library";
|
||||
import type { ImportedDataState } from "@excalidraw/excalidraw/data/types";
|
||||
import type { ExcalidrawElement, FileId } from "@excalidraw/element/types";
|
||||
import type {
|
||||
AppState,
|
||||
BinaryFileData,
|
||||
BinaryFiles,
|
||||
} from "../../packages/excalidraw/types";
|
||||
import type {
|
||||
DTO,
|
||||
MaybePromise,
|
||||
} from "../../packages/excalidraw/utility-types";
|
||||
import { debounce } from "../../packages/excalidraw/utils";
|
||||
} from "@excalidraw/excalidraw/types";
|
||||
import type { DTO, MaybePromise } from "@excalidraw/common/utility-types";
|
||||
|
||||
import { SAVE_TO_LOCAL_STORAGE_TIMEOUT, STORAGE_KEYS } from "../app_constants";
|
||||
|
||||
import { FileManager } from "./FileManager";
|
||||
import { Locker } from "./Locker";
|
||||
import { updateBrowserStateVersion } from "./tabSync";
|
||||
import { StoreDelta } from "../../packages/excalidraw/store";
|
||||
|
||||
const filesStore = createStore("files-db", "files-store");
|
||||
|
||||
|
|
|
@ -1,30 +1,42 @@
|
|||
import { reconcileElements } from "../../packages/excalidraw";
|
||||
import { reconcileElements } from "@excalidraw/excalidraw";
|
||||
import { MIME_TYPES } from "@excalidraw/common";
|
||||
import { decompressData } from "@excalidraw/excalidraw/data/encode";
|
||||
import {
|
||||
encryptData,
|
||||
decryptData,
|
||||
} from "@excalidraw/excalidraw/data/encryption";
|
||||
import { restoreElements } from "@excalidraw/excalidraw/data/restore";
|
||||
import { getSceneVersion } from "@excalidraw/element";
|
||||
import { initializeApp } from "firebase/app";
|
||||
import {
|
||||
getFirestore,
|
||||
doc,
|
||||
getDoc,
|
||||
runTransaction,
|
||||
Bytes,
|
||||
} from "firebase/firestore";
|
||||
import { getStorage, ref, uploadBytes } from "firebase/storage";
|
||||
|
||||
import type { RemoteExcalidrawElement } from "@excalidraw/excalidraw/data/reconcile";
|
||||
import type {
|
||||
ExcalidrawElement,
|
||||
FileId,
|
||||
OrderedExcalidrawElement,
|
||||
} from "../../packages/excalidraw/element/types";
|
||||
import { getSceneVersion } from "../../packages/excalidraw/element";
|
||||
import type Portal from "../collab/Portal";
|
||||
import { restoreElements } from "../../packages/excalidraw/data/restore";
|
||||
} from "@excalidraw/element/types";
|
||||
import type {
|
||||
AppState,
|
||||
BinaryFileData,
|
||||
BinaryFileMetadata,
|
||||
DataURL,
|
||||
} from "../../packages/excalidraw/types";
|
||||
} from "@excalidraw/excalidraw/types";
|
||||
|
||||
import { FILE_CACHE_MAX_AGE_SEC } from "../app_constants";
|
||||
import { decompressData } from "../../packages/excalidraw/data/encode";
|
||||
import {
|
||||
encryptData,
|
||||
decryptData,
|
||||
} from "../../packages/excalidraw/data/encryption";
|
||||
import { MIME_TYPES } from "../../packages/excalidraw/constants";
|
||||
import type { SyncableExcalidrawElement } from ".";
|
||||
|
||||
import { getSyncableElements } from ".";
|
||||
import type { ResolutionType } from "../../packages/excalidraw/utility-types";
|
||||
|
||||
import type { SyncableExcalidrawElement } from ".";
|
||||
import type Portal from "../collab/Portal";
|
||||
import type { Socket } from "socket.io-client";
|
||||
import type { RemoteExcalidrawElement } from "../../packages/excalidraw/data/reconcile";
|
||||
|
||||
// private
|
||||
// -----------------------------------------------------------------------------
|
||||
|
@ -41,80 +53,42 @@ try {
|
|||
FIREBASE_CONFIG = {};
|
||||
}
|
||||
|
||||
let firebasePromise: Promise<typeof import("firebase/app").default> | null =
|
||||
null;
|
||||
let firestorePromise: Promise<any> | null | true = null;
|
||||
let firebaseStoragePromise: Promise<any> | null | true = null;
|
||||
let firebaseApp: ReturnType<typeof initializeApp> | null = null;
|
||||
let firestore: ReturnType<typeof getFirestore> | null = null;
|
||||
let firebaseStorage: ReturnType<typeof getStorage> | null = null;
|
||||
|
||||
let isFirebaseInitialized = false;
|
||||
|
||||
const _loadFirebase = async () => {
|
||||
const firebase = (
|
||||
await import(/* webpackChunkName: "firebase" */ "firebase/app")
|
||||
).default;
|
||||
|
||||
if (!isFirebaseInitialized) {
|
||||
try {
|
||||
firebase.initializeApp(FIREBASE_CONFIG);
|
||||
} catch (error: any) {
|
||||
// trying initialize again throws. Usually this is harmless, and happens
|
||||
// mainly in dev (HMR)
|
||||
if (error.code === "app/duplicate-app") {
|
||||
console.warn(error.name, error.code);
|
||||
} else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
isFirebaseInitialized = true;
|
||||
const _initializeFirebase = () => {
|
||||
if (!firebaseApp) {
|
||||
firebaseApp = initializeApp(FIREBASE_CONFIG);
|
||||
}
|
||||
|
||||
return firebase;
|
||||
return firebaseApp;
|
||||
};
|
||||
|
||||
const _getFirebase = async (): Promise<
|
||||
typeof import("firebase/app").default
|
||||
> => {
|
||||
if (!firebasePromise) {
|
||||
firebasePromise = _loadFirebase();
|
||||
const _getFirestore = () => {
|
||||
if (!firestore) {
|
||||
firestore = getFirestore(_initializeFirebase());
|
||||
}
|
||||
return firebasePromise;
|
||||
return firestore;
|
||||
};
|
||||
|
||||
const _getStorage = () => {
|
||||
if (!firebaseStorage) {
|
||||
firebaseStorage = getStorage(_initializeFirebase());
|
||||
}
|
||||
return firebaseStorage;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const loadFirestore = async () => {
|
||||
const firebase = await _getFirebase();
|
||||
if (!firestorePromise) {
|
||||
firestorePromise = import(
|
||||
/* webpackChunkName: "firestore" */ "firebase/firestore"
|
||||
);
|
||||
}
|
||||
if (firestorePromise !== true) {
|
||||
await firestorePromise;
|
||||
firestorePromise = true;
|
||||
}
|
||||
return firebase;
|
||||
};
|
||||
|
||||
export const loadFirebaseStorage = async () => {
|
||||
const firebase = await _getFirebase();
|
||||
if (!firebaseStoragePromise) {
|
||||
firebaseStoragePromise = import(
|
||||
/* webpackChunkName: "storage" */ "firebase/storage"
|
||||
);
|
||||
}
|
||||
if (firebaseStoragePromise !== true) {
|
||||
await firebaseStoragePromise;
|
||||
firebaseStoragePromise = true;
|
||||
}
|
||||
return firebase;
|
||||
return _getStorage();
|
||||
};
|
||||
|
||||
interface FirebaseStoredScene {
|
||||
type FirebaseStoredScene = {
|
||||
sceneVersion: number;
|
||||
iv: firebase.default.firestore.Blob;
|
||||
ciphertext: firebase.default.firestore.Blob;
|
||||
}
|
||||
iv: Bytes;
|
||||
ciphertext: Bytes;
|
||||
};
|
||||
|
||||
const encryptElements = async (
|
||||
key: string,
|
||||
|
@ -175,7 +149,7 @@ export const saveFilesToFirebase = async ({
|
|||
prefix: string;
|
||||
files: { id: FileId; buffer: Uint8Array }[];
|
||||
}) => {
|
||||
const firebase = await loadFirebaseStorage();
|
||||
const storage = await loadFirebaseStorage();
|
||||
|
||||
const erroredFiles: FileId[] = [];
|
||||
const savedFiles: FileId[] = [];
|
||||
|
@ -183,17 +157,10 @@ export const saveFilesToFirebase = async ({
|
|||
await Promise.all(
|
||||
files.map(async ({ id, buffer }) => {
|
||||
try {
|
||||
await firebase
|
||||
.storage()
|
||||
.ref(`${prefix}/${id}`)
|
||||
.put(
|
||||
new Blob([buffer], {
|
||||
type: MIME_TYPES.binary,
|
||||
}),
|
||||
{
|
||||
cacheControl: `public, max-age=${FILE_CACHE_MAX_AGE_SEC}`,
|
||||
},
|
||||
);
|
||||
const storageRef = ref(storage, `${prefix}/${id}`);
|
||||
await uploadBytes(storageRef, buffer, {
|
||||
cacheControl: `public, max-age=${FILE_CACHE_MAX_AGE_SEC}`,
|
||||
});
|
||||
savedFiles.push(id);
|
||||
} catch (error: any) {
|
||||
erroredFiles.push(id);
|
||||
|
@ -205,7 +172,6 @@ export const saveFilesToFirebase = async ({
|
|||
};
|
||||
|
||||
const createFirebaseSceneDocument = async (
|
||||
firebase: ResolutionType<typeof loadFirestore>,
|
||||
elements: readonly SyncableExcalidrawElement[],
|
||||
roomKey: string,
|
||||
) => {
|
||||
|
@ -213,10 +179,8 @@ const createFirebaseSceneDocument = async (
|
|||
const { ciphertext, iv } = await encryptElements(roomKey, elements);
|
||||
return {
|
||||
sceneVersion,
|
||||
ciphertext: firebase.firestore.Blob.fromUint8Array(
|
||||
new Uint8Array(ciphertext),
|
||||
),
|
||||
iv: firebase.firestore.Blob.fromUint8Array(iv),
|
||||
ciphertext: Bytes.fromUint8Array(new Uint8Array(ciphertext)),
|
||||
iv: Bytes.fromUint8Array(iv),
|
||||
} as FirebaseStoredScene;
|
||||
};
|
||||
|
||||
|
@ -236,20 +200,14 @@ export const saveToFirebase = async (
|
|||
return null;
|
||||
}
|
||||
|
||||
const firebase = await loadFirestore();
|
||||
const firestore = firebase.firestore();
|
||||
const firestore = _getFirestore();
|
||||
const docRef = doc(firestore, "scenes", roomId);
|
||||
|
||||
const docRef = firestore.collection("scenes").doc(roomId);
|
||||
|
||||
const storedScene = await firestore.runTransaction(async (transaction) => {
|
||||
const storedScene = await runTransaction(firestore, async (transaction) => {
|
||||
const snapshot = await transaction.get(docRef);
|
||||
|
||||
if (!snapshot.exists) {
|
||||
const storedScene = await createFirebaseSceneDocument(
|
||||
firebase,
|
||||
elements,
|
||||
roomKey,
|
||||
);
|
||||
if (!snapshot.exists()) {
|
||||
const storedScene = await createFirebaseSceneDocument(elements, roomKey);
|
||||
|
||||
transaction.set(docRef, storedScene);
|
||||
|
||||
|
@ -269,7 +227,6 @@ export const saveToFirebase = async (
|
|||
);
|
||||
|
||||
const storedScene = await createFirebaseSceneDocument(
|
||||
firebase,
|
||||
reconciledElements,
|
||||
roomKey,
|
||||
);
|
||||
|
@ -294,15 +251,13 @@ export const loadFromFirebase = async (
|
|||
roomKey: string,
|
||||
socket: Socket | null,
|
||||
): Promise<readonly SyncableExcalidrawElement[] | null> => {
|
||||
const firebase = await loadFirestore();
|
||||
const db = firebase.firestore();
|
||||
|
||||
const docRef = db.collection("scenes").doc(roomId);
|
||||
const doc = await docRef.get();
|
||||
if (!doc.exists) {
|
||||
const firestore = _getFirestore();
|
||||
const docRef = doc(firestore, "scenes", roomId);
|
||||
const docSnap = await getDoc(docRef);
|
||||
if (!docSnap.exists()) {
|
||||
return null;
|
||||
}
|
||||
const storedScene = doc.data() as FirebaseStoredScene;
|
||||
const storedScene = docSnap.data() as FirebaseStoredScene;
|
||||
const elements = getSyncableElements(
|
||||
restoreElements(await decryptElements(storedScene, roomKey), null),
|
||||
);
|
||||
|
|
|
@ -1,42 +1,46 @@
|
|||
import {
|
||||
compressData,
|
||||
decompressData,
|
||||
} from "../../packages/excalidraw/data/encode";
|
||||
} from "@excalidraw/excalidraw/data/encode";
|
||||
import {
|
||||
decryptData,
|
||||
generateEncryptionKey,
|
||||
IV_LENGTH_BYTES,
|
||||
} from "../../packages/excalidraw/data/encryption";
|
||||
import { serializeAsJSON } from "../../packages/excalidraw/data/json";
|
||||
import { restore } from "../../packages/excalidraw/data/restore";
|
||||
import type { ImportedDataState } from "../../packages/excalidraw/data/types";
|
||||
import type { SceneBounds } from "../../packages/excalidraw/element/bounds";
|
||||
import { isInvisiblySmallElement } from "../../packages/excalidraw/element/sizeHelpers";
|
||||
import { isInitializedImageElement } from "../../packages/excalidraw/element/typeChecks";
|
||||
} from "@excalidraw/excalidraw/data/encryption";
|
||||
import { serializeAsJSON } from "@excalidraw/excalidraw/data/json";
|
||||
import { restore } from "@excalidraw/excalidraw/data/restore";
|
||||
import { isInvisiblySmallElement } from "@excalidraw/element/sizeHelpers";
|
||||
import { isInitializedImageElement } from "@excalidraw/element/typeChecks";
|
||||
import { t } from "@excalidraw/excalidraw/i18n";
|
||||
import { bytesToHexString } from "@excalidraw/common";
|
||||
|
||||
import type { UserIdleState } from "@excalidraw/common";
|
||||
import type { ImportedDataState } from "@excalidraw/excalidraw/data/types";
|
||||
import type { SceneBounds } from "@excalidraw/element/bounds";
|
||||
import type {
|
||||
ExcalidrawElement,
|
||||
FileId,
|
||||
OrderedExcalidrawElement,
|
||||
} from "../../packages/excalidraw/element/types";
|
||||
import { t } from "../../packages/excalidraw/i18n";
|
||||
} from "@excalidraw/element/types";
|
||||
import type {
|
||||
AppState,
|
||||
BinaryFileData,
|
||||
BinaryFiles,
|
||||
SocketId,
|
||||
UserIdleState,
|
||||
} from "../../packages/excalidraw/types";
|
||||
import type { MakeBrand } from "../../packages/excalidraw/utility-types";
|
||||
import { bytesToHexString } from "../../packages/excalidraw/utils";
|
||||
import type { WS_SUBTYPES } from "../app_constants";
|
||||
} from "@excalidraw/excalidraw/types";
|
||||
import type { MakeBrand } from "@excalidraw/common/utility-types";
|
||||
|
||||
import {
|
||||
DELETED_ELEMENT_TIMEOUT,
|
||||
FILE_UPLOAD_MAX_BYTES,
|
||||
ROOM_ID_BYTES,
|
||||
} from "../app_constants";
|
||||
|
||||
import { encodeFilesForUpload } from "./FileManager";
|
||||
import { saveFilesToFirebase } from "./firebase";
|
||||
|
||||
import type { WS_SUBTYPES } from "../app_constants";
|
||||
|
||||
export type SyncableExcalidrawElement = OrderedExcalidrawElement &
|
||||
MakeBrand<"SyncableExcalidrawElement">;
|
||||
|
||||
|
@ -309,23 +313,19 @@ export const exportToBackend = async (
|
|||
body: payload.buffer,
|
||||
});
|
||||
const json = await response.json();
|
||||
// @ts-expect-error
|
||||
if (json.id) {
|
||||
const url = new URL(window.location.href);
|
||||
// We need to store the key (and less importantly the id) as hash instead
|
||||
// of queryParam in order to never send it to the server
|
||||
// @ts-expect-error
|
||||
url.hash = `json=${json.id},${encryptionKey}`;
|
||||
const urlString = url.toString();
|
||||
|
||||
await saveFilesToFirebase({
|
||||
// @ts-expect-error
|
||||
prefix: `/files/shareLinks/${json.id}`,
|
||||
files: filesToUpload,
|
||||
});
|
||||
|
||||
return { url: urlString, errorMessage: null };
|
||||
// @ts-expect-error
|
||||
} else if (json.error_class === "RequestTooLargeError") {
|
||||
return {
|
||||
url: null,
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import type { ExcalidrawElement } from "../../packages/excalidraw/element/types";
|
||||
import type { AppState } from "../../packages/excalidraw/types";
|
||||
import {
|
||||
clearAppStateForLocalStorage,
|
||||
getDefaultAppState,
|
||||
} from "../../packages/excalidraw/appState";
|
||||
import { clearElementsForLocalStorage } from "../../packages/excalidraw/element";
|
||||
} from "@excalidraw/excalidraw/appState";
|
||||
import { clearElementsForLocalStorage } from "@excalidraw/element";
|
||||
|
||||
import type { ExcalidrawElement } from "@excalidraw/element/types";
|
||||
import type { AppState } from "@excalidraw/excalidraw/types";
|
||||
|
||||
import { STORAGE_KEYS } from "../app_constants";
|
||||
|
||||
export const saveUsernameToLocalStorage = (username: string) => {
|
||||
|
|
3
excalidraw-app/global.d.ts
vendored
|
@ -1,3 +1,6 @@
|
|||
import "@excalidraw/excalidraw/global";
|
||||
import "@excalidraw/excalidraw/css";
|
||||
|
||||
interface Window {
|
||||
__EXCALIDRAW_SHA__: string | undefined;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import ExcalidrawApp from "./App";
|
||||
import { registerSW } from "virtual:pwa-register";
|
||||
|
||||
import "../excalidraw-app/sentry";
|
||||
|
||||
import ExcalidrawApp from "./App";
|
||||
|
||||
window.__EXCALIDRAW_SHA__ = import.meta.env.VITE_APP_GIT_SHA;
|
||||
const rootElement = document.getElementById("root")!;
|
||||
const root = createRoot(rootElement);
|
||||
|
|
|
@ -27,15 +27,15 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@excalidraw/random-username": "1.0.0",
|
||||
"@sentry/browser": "6.2.5",
|
||||
"@sentry/integrations": "6.2.5",
|
||||
"firebase": "8.3.3",
|
||||
"@sentry/browser": "9.0.1",
|
||||
"callsites": "4.2.0",
|
||||
"firebase": "11.3.1",
|
||||
"i18next-browser-languagedetector": "6.1.4",
|
||||
"idb-keyval": "6.0.3",
|
||||
"jotai": "2.11.0",
|
||||
"rc-slider": "11.1.7",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react": "19.0.0",
|
||||
"react-dom": "19.0.0",
|
||||
"socket.io-client": "4.7.2",
|
||||
"vite-plugin-html": "3.2.2"
|
||||
},
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import * as Sentry from "@sentry/browser";
|
||||
import * as SentryIntegrations from "@sentry/integrations";
|
||||
import callsites from "callsites";
|
||||
|
||||
const SentryEnvHostnameMap: { [key: string]: string } = {
|
||||
"excalidraw.com": "production",
|
||||
"staging.excalidraw.com": "staging",
|
||||
"vercel.app": "staging",
|
||||
};
|
||||
|
||||
|
@ -23,9 +24,13 @@ Sentry.init({
|
|||
release: import.meta.env.VITE_APP_GIT_SHA,
|
||||
ignoreErrors: [
|
||||
"undefined is not an object (evaluating 'window.__pad.performLoop')", // Only happens on Safari, but spams our servers. Doesn't break anything
|
||||
"InvalidStateError: Failed to execute 'transaction' on 'IDBDatabase': The database connection is closing.", // Not much we can do about the IndexedDB closing error
|
||||
/(Failed to fetch|(fetch|loading) dynamically imported module)/i, // This is happening when a service worker tries to load an old asset
|
||||
/QuotaExceededError: (The quota has been exceeded|.*setItem.*Storage)/i, // localStorage quota exceeded
|
||||
"Internal error opening backing store for indexedDB.open", // Private mode and disabled indexedDB
|
||||
],
|
||||
integrations: [
|
||||
new SentryIntegrations.CaptureConsole({
|
||||
Sentry.captureConsoleIntegration({
|
||||
levels: ["error"],
|
||||
}),
|
||||
],
|
||||
|
@ -33,6 +38,44 @@ Sentry.init({
|
|||
if (event.request?.url) {
|
||||
event.request.url = event.request.url.replace(/#.*$/, "");
|
||||
}
|
||||
|
||||
if (!event.exception) {
|
||||
event.exception = {
|
||||
values: [
|
||||
{
|
||||
type: "ConsoleError",
|
||||
value: event.message ?? "Unknown error",
|
||||
stacktrace: {
|
||||
frames: callsites()
|
||||
.slice(1)
|
||||
.filter(
|
||||
(frame) =>
|
||||
frame.getFileName() &&
|
||||
!frame.getFileName()?.includes("@sentry_browser.js"),
|
||||
)
|
||||
.map((frame) => ({
|
||||
filename: frame.getFileName() ?? undefined,
|
||||
function: frame.getFunctionName() ?? undefined,
|
||||
in_app: !(
|
||||
frame.getFileName()?.includes("node_modules") ?? false
|
||||
),
|
||||
lineno: frame.getLineNumber() ?? undefined,
|
||||
colno: frame.getColumnNumber() ?? undefined,
|
||||
})),
|
||||
},
|
||||
mechanism: {
|
||||
type: "instrument",
|
||||
handled: true,
|
||||
data: {
|
||||
function: "console.error",
|
||||
handler: "Sentry.beforeSend",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
return event;
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
import { useEffect, useRef, useState } from "react";
|
||||
import { copyTextToSystemClipboard } from "../../packages/excalidraw/clipboard";
|
||||
import { trackEvent } from "../../packages/excalidraw/analytics";
|
||||
import { getFrame } from "../../packages/excalidraw/utils";
|
||||
import { useI18n } from "../../packages/excalidraw/i18n";
|
||||
import { KEYS } from "../../packages/excalidraw/keys";
|
||||
import { Dialog } from "../../packages/excalidraw/components/Dialog";
|
||||
import { trackEvent } from "@excalidraw/excalidraw/analytics";
|
||||
import { copyTextToSystemClipboard } from "@excalidraw/excalidraw/clipboard";
|
||||
import { Dialog } from "@excalidraw/excalidraw/components/Dialog";
|
||||
import { FilledButton } from "@excalidraw/excalidraw/components/FilledButton";
|
||||
import { TextField } from "@excalidraw/excalidraw/components/TextField";
|
||||
import {
|
||||
copyIcon,
|
||||
LinkIcon,
|
||||
|
@ -13,17 +11,20 @@ import {
|
|||
share,
|
||||
shareIOS,
|
||||
shareWindows,
|
||||
} from "../../packages/excalidraw/components/icons";
|
||||
import { TextField } from "../../packages/excalidraw/components/TextField";
|
||||
import { FilledButton } from "../../packages/excalidraw/components/FilledButton";
|
||||
import type { CollabAPI } from "../collab/Collab";
|
||||
import { activeRoomLinkAtom } from "../collab/Collab";
|
||||
import { useUIAppState } from "../../packages/excalidraw/context/ui-appState";
|
||||
import { useCopyStatus } from "../../packages/excalidraw/hooks/useCopiedIndicator";
|
||||
} from "@excalidraw/excalidraw/components/icons";
|
||||
import { useUIAppState } from "@excalidraw/excalidraw/context/ui-appState";
|
||||
import { useCopyStatus } from "@excalidraw/excalidraw/hooks/useCopiedIndicator";
|
||||
import { useI18n } from "@excalidraw/excalidraw/i18n";
|
||||
import { KEYS, getFrame } from "@excalidraw/common";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
import { atom, useAtom, useAtomValue } from "../app-jotai";
|
||||
import { activeRoomLinkAtom } from "../collab/Collab";
|
||||
|
||||
import "./ShareDialog.scss";
|
||||
|
||||
import type { CollabAPI } from "../collab/Collab";
|
||||
|
||||
type OnExportToBackend = () => void;
|
||||
type ShareDialogType = "share" | "collaborationOnly";
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import { defaultLang } from "../../packages/excalidraw/i18n";
|
||||
import { UI } from "../../packages/excalidraw/tests/helpers/ui";
|
||||
import { defaultLang } from "@excalidraw/excalidraw/i18n";
|
||||
import { UI } from "@excalidraw/excalidraw/tests/helpers/ui";
|
||||
import {
|
||||
screen,
|
||||
fireEvent,
|
||||
waitFor,
|
||||
render,
|
||||
} from "../../packages/excalidraw/tests/test-utils";
|
||||
} from "@excalidraw/excalidraw/tests/test-utils";
|
||||
|
||||
import ExcalidrawApp from "../App";
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import ExcalidrawApp from "../App";
|
||||
import { UI } from "@excalidraw/excalidraw/tests/helpers/ui";
|
||||
import {
|
||||
mockBoundingClientRect,
|
||||
render,
|
||||
restoreOriginalGetBoundingClientRect,
|
||||
} from "../../packages/excalidraw/tests/test-utils";
|
||||
} from "@excalidraw/excalidraw/tests/test-utils";
|
||||
|
||||
import { UI } from "../../packages/excalidraw/tests/helpers/ui";
|
||||
import ExcalidrawApp from "../App";
|
||||
|
||||
describe("Test MobileMenu", () => {
|
||||
const { h } = window;
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
import { vi } from "vitest";
|
||||
import {
|
||||
act,
|
||||
render,
|
||||
waitFor,
|
||||
} from "../../packages/excalidraw/tests/test-utils";
|
||||
import ExcalidrawApp from "../App";
|
||||
import { API } from "../../packages/excalidraw/tests/helpers/api";
|
||||
import { syncInvalidIndices } from "../../packages/excalidraw/fractionalIndex";
|
||||
import { CaptureUpdateAction, newElementWith } from "@excalidraw/excalidraw";
|
||||
import {
|
||||
createRedoAction,
|
||||
createUndoAction,
|
||||
} from "../../packages/excalidraw/actions/actionHistory";
|
||||
import { StoreAction, newElementWith } from "../../packages/excalidraw";
|
||||
} from "@excalidraw/excalidraw/actions/actionHistory";
|
||||
import { syncInvalidIndices } from "@excalidraw/element/fractionalIndex";
|
||||
import { API } from "@excalidraw/excalidraw/tests/helpers/api";
|
||||
import { act, render, waitFor } from "@excalidraw/excalidraw/tests/test-utils";
|
||||
import { vi } from "vitest";
|
||||
|
||||
import ExcalidrawApp from "../App";
|
||||
|
||||
const { h } = window;
|
||||
|
||||
|
@ -89,7 +86,7 @@ describe("collaboration", () => {
|
|||
|
||||
API.updateScene({
|
||||
elements: syncInvalidIndices([rect1, rect2]),
|
||||
storeAction: StoreAction.CAPTURE,
|
||||
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
||||
});
|
||||
|
||||
API.updateScene({
|
||||
|
@ -97,7 +94,7 @@ describe("collaboration", () => {
|
|||
rect1,
|
||||
newElementWith(h.elements[1], { isDeleted: true }),
|
||||
]),
|
||||
storeAction: StoreAction.CAPTURE,
|
||||
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
|
@ -144,7 +141,7 @@ describe("collaboration", () => {
|
|||
// simulate force deleting the element remotely
|
||||
API.updateScene({
|
||||
elements: syncInvalidIndices([rect1]),
|
||||
storeAction: StoreAction.UPDATE,
|
||||
captureUpdate: CaptureUpdateAction.NEVER,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
|
@ -182,7 +179,7 @@ describe("collaboration", () => {
|
|||
h.elements[0],
|
||||
newElementWith(h.elements[1], { x: 100 }),
|
||||
]),
|
||||
storeAction: StoreAction.CAPTURE,
|
||||
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
|
@ -217,7 +214,7 @@ describe("collaboration", () => {
|
|||
// simulate force deleting the element remotely
|
||||
API.updateScene({
|
||||
elements: syncInvalidIndices([rect1]),
|
||||
storeAction: StoreAction.UPDATE,
|
||||
captureUpdate: CaptureUpdateAction.NEVER,
|
||||
});
|
||||
|
||||
// snapshot was correctly updated and marked the element as deleted
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { THEME } from "@excalidraw/excalidraw";
|
||||
import { EVENT, CODES, KEYS } from "@excalidraw/common";
|
||||
import { useEffect, useLayoutEffect, useState } from "react";
|
||||
import { THEME } from "../packages/excalidraw";
|
||||
import { EVENT } from "../packages/excalidraw/constants";
|
||||
import type { Theme } from "../packages/excalidraw/element/types";
|
||||
import { CODES, KEYS } from "../packages/excalidraw/keys";
|
||||
|
||||
import type { Theme } from "@excalidraw/element/types";
|
||||
|
||||
import { STORAGE_KEYS } from "./app_constants";
|
||||
|
||||
const getDarkThemeMediaQuery = (): MediaQueryList | undefined =>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import path from "path";
|
||||
import { defineConfig, loadEnv } from "vite";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import svgrPlugin from "vite-plugin-svgr";
|
||||
|
@ -7,7 +8,6 @@ import checker from "vite-plugin-checker";
|
|||
import { createHtmlPlugin } from "vite-plugin-html";
|
||||
import Sitemap from "vite-plugin-sitemap";
|
||||
import { woff2BrowserPlugin } from "../scripts/woff2/woff2-vite-plugins";
|
||||
|
||||
export default defineConfig(({ mode }) => {
|
||||
// To load .env variables
|
||||
const envVars = loadEnv(mode, `../`);
|
||||
|
@ -21,6 +21,50 @@ export default defineConfig(({ mode }) => {
|
|||
// We need to specify the envDir since now there are no
|
||||
//more located in parallel with the vite.config.ts file but in parent dir
|
||||
envDir: "../",
|
||||
resolve: {
|
||||
alias: [
|
||||
{
|
||||
find: /^@excalidraw\/common$/,
|
||||
replacement: path.resolve(__dirname, "../packages/common/src/index.ts"),
|
||||
},
|
||||
{
|
||||
find: /^@excalidraw\/common\/(.*?)/,
|
||||
replacement: path.resolve(__dirname, "../packages/common/src/$1"),
|
||||
},
|
||||
{
|
||||
find: /^@excalidraw\/element$/,
|
||||
replacement: path.resolve(__dirname, "../packages/element/src/index.ts"),
|
||||
},
|
||||
{
|
||||
find: /^@excalidraw\/element\/(.*?)/,
|
||||
replacement: path.resolve(__dirname, "../packages/element/src/$1"),
|
||||
},
|
||||
{
|
||||
find: /^@excalidraw\/excalidraw$/,
|
||||
replacement: path.resolve(__dirname, "../packages/excalidraw/index.tsx"),
|
||||
},
|
||||
{
|
||||
find: /^@excalidraw\/excalidraw\/(.*?)/,
|
||||
replacement: path.resolve(__dirname, "../packages/excalidraw/$1"),
|
||||
},
|
||||
{
|
||||
find: /^@excalidraw\/math$/,
|
||||
replacement: path.resolve(__dirname, "../packages/math/src/index.ts"),
|
||||
},
|
||||
{
|
||||
find: /^@excalidraw\/math\/(.*?)/,
|
||||
replacement: path.resolve(__dirname, "../packages/math/src/$1"),
|
||||
},
|
||||
{
|
||||
find: /^@excalidraw\/utils$/,
|
||||
replacement: path.resolve(__dirname, "../packages/utils/src/index.ts"),
|
||||
},
|
||||
{
|
||||
find: /^@excalidraw\/utils\/(.*?)/,
|
||||
replacement: path.resolve(__dirname, "../packages/utils/src/$1"),
|
||||
},
|
||||
],
|
||||
},
|
||||
build: {
|
||||
outDir: "build",
|
||||
rollupOptions: {
|
||||
|
|
21
package.json
|
@ -5,26 +5,26 @@
|
|||
"workspaces": [
|
||||
"excalidraw-app",
|
||||
"packages/*",
|
||||
"examples/excalidraw",
|
||||
"examples/excalidraw/*"
|
||||
"examples/*"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-private-property-in-object": "7.21.11",
|
||||
"@babel/preset-env": "7.26.9",
|
||||
"@excalidraw/eslint-config": "1.0.3",
|
||||
"@excalidraw/prettier-config": "1.0.2",
|
||||
"@types/chai": "4.3.0",
|
||||
"@types/jest": "27.4.0",
|
||||
"@types/lodash.throttle": "4.1.7",
|
||||
"@types/react": "18.2.0",
|
||||
"@types/react-dom": "18.2.0",
|
||||
"@types/react": "19.0.10",
|
||||
"@types/react-dom": "19.0.4",
|
||||
"@types/socket.io-client": "3.0.0",
|
||||
"@vitejs/plugin-react": "3.1.0",
|
||||
"@vitest/coverage-v8": "2.0.5",
|
||||
"@vitest/coverage-v8": "3.0.7",
|
||||
"@vitest/ui": "2.0.5",
|
||||
"chai": "4.3.6",
|
||||
"dotenv": "16.0.1",
|
||||
"eslint-config-prettier": "8.5.0",
|
||||
"eslint-config-react-app": "7.0.1",
|
||||
"eslint-plugin-import": "2.31.0",
|
||||
"eslint-plugin-prettier": "3.3.1",
|
||||
"http-server": "14.1.1",
|
||||
"husky": "7.0.4",
|
||||
|
@ -37,9 +37,9 @@
|
|||
"vite": "5.0.12",
|
||||
"vite-plugin-checker": "0.7.2",
|
||||
"vite-plugin-ejs": "1.7.0",
|
||||
"vite-plugin-pwa": "0.17.4",
|
||||
"vite-plugin-pwa": "0.21.1",
|
||||
"vite-plugin-svgr": "4.2.0",
|
||||
"vitest": "2.0.5",
|
||||
"vitest": "3.0.6",
|
||||
"vitest-canvas-mock": "0.3.3"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -51,11 +51,13 @@
|
|||
"build-node": "node ./scripts/build-node.js",
|
||||
"build:app:docker": "yarn --cwd ./excalidraw-app build:app:docker",
|
||||
"build:app": "yarn --cwd ./excalidraw-app build:app",
|
||||
"build:package": "yarn --cwd ./packages/excalidraw build:esm",
|
||||
"build:version": "yarn --cwd ./excalidraw-app build:version",
|
||||
"build": "yarn --cwd ./excalidraw-app build",
|
||||
"build:preview": "yarn --cwd ./excalidraw-app build:preview",
|
||||
"start": "yarn --cwd ./excalidraw-app start",
|
||||
"start:production": "yarn --cwd ./excalidraw-app start:production",
|
||||
"start:example": "yarn build:package && yarn --cwd ./examples/with-script-in-browser start",
|
||||
"test:all": "yarn test:typecheck && yarn test:code && yarn test:other && yarn test:app --watch=false",
|
||||
"test:app": "vitest",
|
||||
"test:code": "eslint --max-warnings=0 --ext .js,.ts,.tsx .",
|
||||
|
@ -76,12 +78,11 @@
|
|||
"autorelease": "node scripts/autorelease.js",
|
||||
"prerelease:excalidraw": "node scripts/prerelease.js",
|
||||
"release:excalidraw": "node scripts/release.js",
|
||||
"rm:build": "rm -rf excalidraw-app/{build,dist,dev-dist} && rm -rf packages/*/{dist,build} && rm -rf examples/*/*/{build,dist}",
|
||||
"rm:build": "rm -rf excalidraw-app/{build,dist,dev-dist} && rm -rf packages/*/{dist,build} && rm -rf examples/*/{build,dist}",
|
||||
"rm:node_modules": "rm -rf node_modules && rm -rf excalidraw-app/node_modules && rm -rf packages/*/node_modules",
|
||||
"clean-install": "yarn rm:node_modules && yarn install"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "18.2.0",
|
||||
"strip-ansi": "6.0.1"
|
||||
}
|
||||
}
|
||||
|
|
3
packages/common/.eslintrc.json
Normal file
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"extends": ["../eslintrc.base.json"]
|
||||
}
|
19
packages/common/README.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
# @excalidraw/common
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install @excalidraw/common
|
||||
```
|
||||
|
||||
If you prefer Yarn over npm, use this command to install the Excalidraw utils package:
|
||||
|
||||
```bash
|
||||
yarn add @excalidraw/common
|
||||
```
|
||||
|
||||
With PNPM, similarly install the package with this command:
|
||||
|
||||
```bash
|
||||
pnpm add @excalidraw/common
|
||||
```
|
3
packages/common/global.d.ts
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
/// <reference types="vite/client" />
|
||||
import "@excalidraw/excalidraw/global";
|
||||
import "@excalidraw/excalidraw/css";
|