diff --git a/.env.development b/.env.development index 72b67ecea..d67b137d1 100644 --- a/.env.development +++ b/.env.development @@ -1,24 +1,39 @@ -REACT_APP_BACKEND_V2_GET_URL=https://json-dev.excalidraw.com/api/v2/ -REACT_APP_BACKEND_V2_POST_URL=https://json-dev.excalidraw.com/api/v2/post/ +VITE_APP_BACKEND_V2_GET_URL=https://json-dev.excalidraw.com/api/v2/ +VITE_APP_BACKEND_V2_POST_URL=https://json-dev.excalidraw.com/api/v2/post/ -REACT_APP_LIBRARY_URL=https://libraries.excalidraw.com -REACT_APP_LIBRARY_BACKEND=https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries +VITE_APP_LIBRARY_URL=https://libraries.excalidraw.com +VITE_APP_LIBRARY_BACKEND=https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries # collaboration WebSocket server (https://github.com/excalidraw/excalidraw-room) -REACT_APP_WS_SERVER_URL=http://localhost:3002 +VITE_APP_WS_SERVER_URL=http://localhost:3002 # set this only if using the collaboration workflow we use on excalidraw.com -REACT_APP_PORTAL_URL= +VITE_APP_PORTAL_URL= -REACT_APP_FIREBASE_CONFIG='{"apiKey":"AIzaSyCMkxA60XIW8KbqMYL7edC4qT5l4qHX2h8","authDomain":"excalidraw-oss-dev.firebaseapp.com","projectId":"excalidraw-oss-dev","storageBucket":"excalidraw-oss-dev.appspot.com","messagingSenderId":"664559512677","appId":"1:664559512677:web:a385181f2928d328a7aa8c"}' +VITE_APP_FIREBASE_CONFIG='{"apiKey":"AIzaSyCMkxA60XIW8KbqMYL7edC4qT5l4qHX2h8","authDomain":"excalidraw-oss-dev.firebaseapp.com","projectId":"excalidraw-oss-dev","storageBucket":"excalidraw-oss-dev.appspot.com","messagingSenderId":"664559512677","appId":"1:664559512677:web:a385181f2928d328a7aa8c"}' # put these in your .env.local, or make sure you don't commit! # must be lowercase `true` when turned on # # whether to enable Service Workers in development -REACT_APP_DEV_ENABLE_SW= +VITE_APP_DEV_ENABLE_SW= # whether to disable live reload / HMR. Usuaully what you want to do when # debugging Service Workers. -REACT_APP_DEV_DISABLE_LIVE_RELOAD= +VITE_APP_DEV_DISABLE_LIVE_RELOAD= +VITE_APP_DISABLE_TRACKING=true FAST_REFRESH=false + +# The port the run the dev server +VITE_APP_PORT=3000 + +#Debug flags + +# To enable bounding box for text containers +VITE_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX= + +# Set this flag to false if you want to open the overlay by default +VITE_APP_COLLAPSE_OVERLAY=true + +# Set this flag to false to disable eslint +VITE_APP_ENABLE_ESLINT=true diff --git a/.env.production b/.env.production index 183db7ea2..e3ece6df3 100644 --- a/.env.production +++ b/.env.production @@ -1,17 +1,15 @@ REACT_APP_BACKEND_V2_GET_URL=https://json.excalidraw.com/api/v2/ REACT_APP_BACKEND_V2_POST_URL=https://json.excalidraw.com/api/v2/post/ -REACT_APP_LIBRARY_URL=https://libraries.excalidraw.com -REACT_APP_LIBRARY_BACKEND=https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries +VITE_APP_LIBRARY_URL=https://libraries.excalidraw.com +VITE_APP_LIBRARY_BACKEND=https://us-central1-excalidraw-room-persistence.cloudfunctions.net/libraries -REACT_APP_PORTAL_URL=https://portal.excalidraw.com +VITE_APP_PORTAL_URL=https://portal.excalidraw.com # Fill to set socket server URL used for collaboration. -# Meant for forks only: excalidraw.com uses custom REACT_APP_PORTAL_URL flow -REACT_APP_WS_SERVER_URL= +# Meant for forks only: excalidraw.com uses custom VITE_APP_PORTAL_URL flow +VITE_APP_WS_SERVER_URL= -REACT_APP_FIREBASE_CONFIG='{"apiKey":"AIzaSyAd15pYlMci_xIp9ko6wkEsDzAAA0Dn0RU","authDomain":"excalidraw-room-persistence.firebaseapp.com","databaseURL":"https://excalidraw-room-persistence.firebaseio.com","projectId":"excalidraw-room-persistence","storageBucket":"excalidraw-room-persistence.appspot.com","messagingSenderId":"654800341332","appId":"1:654800341332:web:4a692de832b55bd57ce0c1"}' +VITE_APP_FIREBASE_CONFIG='{"apiKey":"AIzaSyAd15pYlMci_xIp9ko6wkEsDzAAA0Dn0RU","authDomain":"excalidraw-room-persistence.firebaseapp.com","databaseURL":"https://excalidraw-room-persistence.firebaseio.com","projectId":"excalidraw-room-persistence","storageBucket":"excalidraw-room-persistence.appspot.com","messagingSenderId":"654800341332","appId":"1:654800341332:web:4a692de832b55bd57ce0c1"}' -# production-only vars -REACT_APP_GOOGLE_ANALYTICS_ID=UA-387204-13 - -REACT_APP_PLUS_APP=https://app.excalidraw.com +VITE_APP_PLUS_APP=https://app.excalidraw.com +VITE_APP_DISABLE_TRACKING= diff --git a/.github/workflows/autorelease-excalidraw.yml b/.github/workflows/autorelease-excalidraw.yml index ad0a0a7e9..4eaeb11f1 100644 --- a/.github/workflows/autorelease-excalidraw.yml +++ b/.github/workflows/autorelease-excalidraw.yml @@ -12,10 +12,10 @@ jobs: - uses: actions/checkout@v2 with: fetch-depth: 2 - - name: Setup Node.js 14.x + - name: Setup Node.js 18.x uses: actions/setup-node@v2 with: - node-version: 14.x + node-version: 18.x - name: Set up publish access run: | npm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN} diff --git a/.github/workflows/autorelease-preview.yml b/.github/workflows/autorelease-preview.yml index 8fe7f40b5..bcd501880 100644 --- a/.github/workflows/autorelease-preview.yml +++ b/.github/workflows/autorelease-preview.yml @@ -32,10 +32,10 @@ jobs: with: ref: ${{ steps.sha.outputs.result }} fetch-depth: 2 - - name: Setup Node.js 14.x + - name: Setup Node.js 18.x uses: actions/setup-node@v2 with: - node-version: 14.x + node-version: 18.x - name: Set up publish access run: | npm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 77d2ef4d2..d42f8f632 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -9,10 +9,10 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Setup Node.js 14.x + - name: Setup Node.js 18.x uses: actions/setup-node@v2 with: - node-version: 14.x + node-version: 18.x - name: Install and lint run: | diff --git a/.github/workflows/locales-coverage.yml b/.github/workflows/locales-coverage.yml index 924dc9e97..822af06e1 100644 --- a/.github/workflows/locales-coverage.yml +++ b/.github/workflows/locales-coverage.yml @@ -14,10 +14,10 @@ jobs: with: token: ${{ secrets.PUSH_TRANSLATIONS_COVERAGE_PAT }} - - name: Setup Node.js 14.x + - name: Setup Node.js 18.x uses: actions/setup-node@v2 with: - node-version: 14.x + node-version: 18.x - name: Create report file run: | diff --git a/.github/workflows/semantic-pr-title.yml b/.github/workflows/semantic-pr-title.yml index 8980fc68e..969d23640 100644 --- a/.github/workflows/semantic-pr-title.yml +++ b/.github/workflows/semantic-pr-title.yml @@ -1,7 +1,7 @@ name: Semantic PR title on: - pull_request_target: + pull_request: types: - opened - edited diff --git a/.github/workflows/sentry-production.yml b/.github/workflows/sentry-production.yml index 6f53f91eb..cea4cf63d 100644 --- a/.github/workflows/sentry-production.yml +++ b/.github/workflows/sentry-production.yml @@ -10,10 +10,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Setup Node.js 14.x + - name: Setup Node.js 18.x uses: actions/setup-node@v2 with: - node-version: 14.x + node-version: 18.x - name: Install and build run: | yarn --frozen-lockfile diff --git a/.github/workflows/size-limit.yml b/.github/workflows/size-limit.yml new file mode 100644 index 000000000..8ced8ee03 --- /dev/null +++ b/.github/workflows/size-limit.yml @@ -0,0 +1,30 @@ +name: "Bundle Size check @excalidraw/excalidraw" +on: + pull_request: + branches: + - master +jobs: + size: + runs-on: ubuntu-latest + env: + CI_JOB_NUMBER: 1 + steps: + - name: Checkout repository + uses: actions/checkout@v3 + - name: Setup Node.js 18.x + uses: actions/setup-node@v3 + with: + node-version: 18.x + - name: Install + run: yarn --frozen-lockfile + - name: Install in src/packages/excalidraw + run: yarn --frozen-lockfile + working-directory: src/packages/excalidraw + env: + CI: true + - uses: andresz1/size-limit-action@v1 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + build_script: build:umd + skip_step: install + directory: src/packages/excalidraw diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b64ea4735..5c4584e82 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,10 +7,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Setup Node.js 14.x + - name: Setup Node.js 18.x uses: actions/setup-node@v2 with: - node-version: 14.x + node-version: 18.x - name: Install and test run: | yarn --frozen-lockfile diff --git a/.gitignore b/.gitignore index 4a3f6f367..6e430f4ed 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,6 @@ src/packages/excalidraw/types src/packages/excalidraw/example/public/bundle.js src/packages/excalidraw/example/public/excalidraw-assets-dev src/packages/excalidraw/example/public/excalidraw.development.js +coverage +dev-dist +html diff --git a/.husky/pre-commit b/.husky/pre-commit index 521508d8e..ab2a5ac5f 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,2 +1,2 @@ #!/bin/sh -yarn lint-staged +# yarn lint-staged diff --git a/.npmrc b/.npmrc index cffe8cdef..1b78f1c6f 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,2 @@ save-exact=true +legacy-peer-deps=true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b3a5c325c..509908e5d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,63 +1,3 @@ # Contributing -## Setup - -### Option 1 - Manual - -1. Fork and clone the repo -1. Run `yarn` to install dependencies -1. Create a branch for your PR with `git checkout -b your-branch-name` - -> To keep `master` branch pointing to remote repository and make pull requests from branches on your fork. To do this, run: -> -> ```sh -> git remote add upstream https://github.com/excalidraw/excalidraw.git -> git fetch upstream -> git branch --set-upstream-to=upstream/master master -> ``` - -### Option 2 - CodeSandbox - -1. Go to https://codesandbox.io/s/github/excalidraw/excalidraw -1. Connect your GitHub account -1. Go to Git tab on left side -1. Tap on `Fork Sandbox` -1. Write your code -1. Commit and PR automatically - -## Pull Request Guidelines - -Don't worry if you get any of the below wrong, or if you don't know how. We'll gladly help out. - -### Title - -Make sure the title starts with a semantic prefix: - -- **feat**: A new feature -- **fix**: A bug fix -- **docs**: Documentation only changes -- **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) -- **refactor**: A code change that neither fixes a bug nor adds a feature -- **perf**: A code change that improves performance -- **test**: Adding missing tests or correcting existing tests -- **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm) -- **ci**: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs) -- **chore**: Other changes that don't modify src or test files -- **revert**: Reverts a previous commit - -### Changelog - -Add a brief description of your pull request to the changelog located here: [`src/packages/excalidraw/CHANGELOG.md`](src/packages/excalidraw/CHANGELOG.md) - -Notes: - -- Make sure to prepend to the section corresponding with the semantic prefix you selected in the title -- Link to your pull request - this will require updating the CHANGELOG _after_ creating the pull request - -### Testing - -Once you submit your pull request it will automatically be tested. Be sure to check the results of the test and fix any issues that arise. - -It's also a good idea to consider if your change should include additional tests. This is highly recommended for new features or bug-fixes. For example, it's good practice to create a test for each bug you fix which ensures that we don't regress the code in the future. - -Finally - always manually test your changes using the convenient staging environment deployed for each pull request. As much as local development attempts to replicate production, there can still be subtle differences in behavior. For larger features consider testing your change in multiple browsers as well. +Head over to the [docs](https://docs.excalidraw.com/docs/introduction/contributing) diff --git a/Dockerfile b/Dockerfile index f295f7f6a..a044f40f6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,9 +1,9 @@ -FROM node:14-alpine AS build +FROM node:18 AS build WORKDIR /opt/node_app COPY package.json yarn.lock ./ -RUN yarn --ignore-optional +RUN yarn --ignore-optional --network-timeout 600000 ARG NODE_ENV=production diff --git a/README.md b/README.md index 45fec41ba..48529165e 100644 --- a/README.md +++ b/README.md @@ -1,201 +1,126 @@ -
- - Excalidraw logo: Sketch handrawn like diagrams. - -

Virtual whiteboard for sketching hand-drawn like diagrams.
Collaborative and end-to-end encrypted.

-

- - Follow Excalidraw on Twitter - - - - -

-

Ask questions or hang out on our discord.gg/UexuTaE.

+ + + + Excalidraw + + + +

+ Excalidraw Editor | + Blog | + Documentation | + Excalidraw+ +

+ +
+

+ An open source virtual hand-drawn style whiteboard.
+ Collaborative and end-to-end encrypted.
+
+

-## Try it now +
+

+ + Excalidraw is released under the MIT license. + + + PRs welcome! + + + Chat on Discord + + + Follow Excalidraw on Twitter + +

-Go to [excalidraw.com](https://excalidraw.com) to start sketching. +
+
+ + Product showcase + +
+

+ Create beautiful hand-drawn like diagrams, wireframes, or whatever you like. +

+
+
+
-Read the latest news and updates on our [blog](https://blog.excalidraw.com). A good start is to see all the updates of [One Year of Excalidraw](https://blog.excalidraw.com/one-year-of-excalidraw/). +## Features -## Supporting Excalidraw +The Excalidraw editor (npm package) supports: -If you like the project, you can become a sponsor at [Open Collective](https://opencollective.com/excalidraw). +- 💯 Free & open-source. +- 🎨 Infinite, canvas-based whiteboard. +- ✍️ Hand-drawn like style. +- 🌓 Dark mode. +- 🏗️ Customizable. +- 📷 Image support. +- 😀 Shape libraries support. +- 👅 Localization (i18n) support. +- 🖼️ Export to PNG, SVG & clipboard. +- 💾 Open format - export drawings as an `.excalidraw` json file. +- ⚒️ Wide range of tools - rectangle, circle, diamond, arrow, line, free-draw, eraser... +- ➡️ Arrow-binding & labeled arrows. +- 🔙 Undo / Redo. +- 🔍 Zoom and panning support. -[](https://opencollective.com/excalidraw/tiers/sponsors/0/website) [](https://opencollective.com/excalidraw/tiers/sponsors/1/website) [](https://opencollective.com/excalidraw/tiers/sponsors/2/website) [](https://opencollective.com/excalidraw/tiers/sponsors/3/website) [](https://opencollective.com/excalidraw/tiers/sponsors/4/website) [](https://opencollective.com/excalidraw/tiers/sponsors/5/website) [](https://opencollective.com/excalidraw/tiers/sponsors/6/website) [](https://opencollective.com/excalidraw/tiers/sponsors/7/website) [](https://opencollective.com/excalidraw/tiers/sponsors/8/website) [](https://opencollective.com/excalidraw/tiers/sponsors/9/website) [](https://opencollective.com/excalidraw/tiers/sponsors/10/website) +## Excalidraw.com + +The app hosted at [excalidraw.com](https://excalidraw.com) is a minimal showcase of what you can build with Excalidraw. Its [source code](https://github.com/excalidraw/excalidraw/tree/master/src/excalidraw-app) is part of this repository as well, and the app features: + +- 📡 PWA support (works offline). +- 🤼 Real-time collaboration. +- 🔒 End-to-end encryption. +- 💾 Local-first support (autosaves to the browser). +- 🔗 Shareable links (export to a readonly link you can share with others). + +We'll be adding these features as drop-in plugins for the npm package in the future. + +## Quick start + +Install the [Excalidraw npm package](https://www.npmjs.com/package/@excalidraw/excalidraw): + +``` +npm install react react-dom @excalidraw/excalidraw +``` + +or via yarn + +``` +yarn add react react-dom @excalidraw/excalidraw +``` + +Don't forget to check out our [Documentation](https://docs.excalidraw.com)! + +## Contributing + +- Missing something or found a bug? [Report here](https://github.com/excalidraw/excalidraw/issues). +- Want to contribute? Check out our [contribution guide](https://docs.excalidraw.com/docs/introduction/contributing) or let us know on [Discord](https://discord.gg/UexuTaE). +- Want to help with translations? See the [translation guide](https://docs.excalidraw.com/docs/introduction/contributing#translating). + +## Integrations + +- [VScode extension](https://marketplace.visualstudio.com/items?itemName=pomdtr.excalidraw-editor) +- [npm package](https://www.npmjs.com/package/@excalidraw/excalidraw) + +## Who's integrating Excalidraw + +[Google Cloud](https://googlecloudcheatsheet.withgoogle.com/architecture) • [Meta](https://meta.com/) • [CodeSandbox](https://codesandbox.io/) • [Obsidian Excalidraw](https://github.com/zsviczian/obsidian-excalidraw-plugin) • [Replit](https://replit.com/) • [Slite](https://slite.com/) • [Notion](https://notion.so/) • [HackerRank](https://www.hackerrank.com/) • and many others + +## Sponsors & support + +If you like the project, you can become a sponsor at [Open Collective](https://opencollective.com/excalidraw) or use [Excalidraw+](https://plus.excalidraw.com/). + +## Thank you for supporting Excalidraw + +[](https://opencollective.com/excalidraw/tiers/sponsors/0/website) [](https://opencollective.com/excalidraw/tiers/sponsors/1/website) [](https://opencollective.com/excalidraw/tiers/sponsors/2/website) [](https://opencollective.com/excalidraw/tiers/sponsors/3/website) [](https://opencollective.com/excalidraw/tiers/sponsors/4/website) [](https://opencollective.com/excalidraw/tiers/sponsors/5/website) [](https://opencollective.com/excalidraw/tiers/sponsors/6/website) [](https://opencollective.com/excalidraw/tiers/sponsors/7/website) [](https://opencollective.com/excalidraw/tiers/sponsors/8/website) [](https://opencollective.com/excalidraw/tiers/sponsors/9/website) [](https://opencollective.com/excalidraw/tiers/sponsors/10/website) Last but not least, we're thankful to these companies for offering their services for free: [![Vercel](./.github/assets/vercel.svg)](https://vercel.com) [![Sentry](./.github/assets/sentry.svg)](https://sentry.io) [![Crowdin](./.github/assets/crowdin.svg)](https://crowdin.com) - -## Who's integrating Excalidraw - -[Google Cloud](https://googlecloudcheatsheet.withgoogle.com/architecture) • [Meta](https://meta.com/) • [CodeSandbox](https://codesandbox.io/) • [Obsidian Excalidraw](https://github.com/zsviczian/obsidian-excalidraw-plugin) • [Replit](https://replit.com/) • [Slite](https://slite.com/) • [Notion](https://notion.so/) • [HackerRank](https://www.hackerrank.com/) • - -## Documentation - -### Shortcuts - -You can almost do anything with shortcuts. Click on the help icon on the bottom right corner to see them all. - -### Curved lines and arrows - -Choose line or arrow and click click click instead of drag. - -### Charts - -You can easily create charts by copy pasting data from Excel or just plain comma separated text. - -### Translating - -To translate Excalidraw into other languages, please visit [our Crowdin page](https://crowdin.com/project/excalidraw). To add a new language, [open an issue](https://github.com/excalidraw/excalidraw/issues/new) so we can get things set up on our end first. - -Translations will be available on the app if they exceed a certain threshold of completion (currently 85%). - -### Create a collaboration session manually - -In order to create a session manually, you just need to generate a link of this form: - -``` -https://excalidraw.com/#room=[0-9a-f]{20},[a-zA-Z0-9_-]{22} -``` - -#### Example - -``` -https://excalidraw.com/#room=91bd46ae3aa84dff9d20,pfLqgEoY1c2ioq8LmGwsFA -``` - -The first set of digits is the room. This is visible from the server that’s going to dispatch messages to everyone that knows this number. - -The second set of digits is the encryption key. The Excalidraw server doesn’t know about it. This is what all the participants use to encrypt/decrypt the messages. - -> Note: Please ensure that the encryption key is 22 characters long. - -## Shape libraries - -Find a growing list of libraries containing assets for your drawings at [libraries.excalidraw.com](https://libraries.excalidraw.com). - -## Embedding Excalidraw in your App? - -Try out [`@excalidraw/excalidraw`](https://www.npmjs.com/package/@excalidraw/excalidraw). This package allows you to easily embed Excalidraw as a React component into your apps. - -## Development - -### Code Sandbox - -- Go to https://codesandbox.io/p/github/excalidraw/excalidraw - - You may need to sign in with GitHub and reload the page -- You can start coding instantly, and even send PRs from there! - -### Local Installation - -These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. - -#### Requirements - -- [Node.js](https://nodejs.org/en/) -- [Yarn](https://yarnpkg.com/getting-started/install) (v1 or v2.4.2+) -- [Git](https://git-scm.com/downloads) - -#### Clone the repo - -```bash -git clone https://github.com/excalidraw/excalidraw.git -``` - -#### Install the dependencies - -```bash -yarn -``` - -#### Start the server - -```bash -yarn start -``` - -Now you can open [http://localhost:3000](http://localhost:3000) and start coding in your favorite code editor. - -#### Collaboration - -For collaboration, you will need to set up [collab server](https://github.com/excalidraw/excalidraw-room) in local. - -#### Commands - -##### Install the dependencies - -``` -yarn -``` - -##### Run the project - -``` -yarn start -``` - -##### Reformat all files with Prettier - -``` -yarn fix -``` - -##### Run tests - -``` -yarn test -``` - -##### Update test snapshots - -``` -yarn test:update -``` - -##### Test for formatting with Prettier - -``` -yarn test:code -``` - -#### Docker Compose - -You can use docker-compose to work on Excalidraw locally if you don't want to setup a Node.js env. - -```sh -docker-compose up --build -d -``` - -### Self-hosting - -We publish a Docker image with the Excalidraw client at [excalidraw/excalidraw](https://hub.docker.com/r/excalidraw/excalidraw). You can use it to self-host your own client under your own domain, on Kubernetes, AWS ECS, etc. - -```sh -docker build -t excalidraw/excalidraw . -docker run --rm -dit --name excalidraw -p 5000:80 excalidraw/excalidraw:latest -``` - -The Docker image is free of analytics and other tracking libraries. - -**At the moment, self-hosting your own instance doesn't support sharing or collaboration features.** - -We are working towards providing a full-fledged solution for self-hosting your own Excalidraw. - -## Contributing - -Pull requests are welcome. For major changes, please [open an issue](https://github.com/excalidraw/excalidraw/issues/new) first to discuss what you would like to change. - -## Notable used tools - -- [Create React App](https://github.com/facebook/create-react-app) -- [Rough.js](https://roughjs.com) -- [TypeScript](https://www.typescriptlang.org) -- [Vercel](https://vercel.com) - -And the main source of inspiration for starting the project is the awesome [Zwibbler](https://zwibbler.com/demo/) app. diff --git a/dev-docs/docs/@excalidraw/excalidraw/api/api-intro.mdx b/dev-docs/docs/@excalidraw/excalidraw/api/api-intro.mdx new file mode 100644 index 000000000..aee7f3bfb --- /dev/null +++ b/dev-docs/docs/@excalidraw/excalidraw/api/api-intro.mdx @@ -0,0 +1,11 @@ +--- +slug: /@excalidraw/excalidraw/api +--- + +# API + +Currently the **API** is divided into 3 broad categories 👇 + +- [Props](/docs/@excalidraw/excalidraw/api/props) - The `props` you can pass to the `Excalidraw` component. +- [Children components](/docs/@excalidraw/excalidraw/api/children-components) - Official components you can use to customize the UI. +- [Utils](/docs/@excalidraw/excalidraw/api/utils) - Utilities and helpers you can use to export, restore and more. diff --git a/dev-docs/docs/@excalidraw/excalidraw/api/children-components/children-components-intro.mdx b/dev-docs/docs/@excalidraw/excalidraw/api/children-components/children-components-intro.mdx new file mode 100644 index 000000000..706adb594 --- /dev/null +++ b/dev-docs/docs/@excalidraw/excalidraw/api/children-components/children-components-intro.mdx @@ -0,0 +1,21 @@ +--- +sidebar_label: Children Components +slug: /@excalidraw/excalidraw/api/children-components +--- + +# `` children + +We expose several components you can render as children of the `` component to customize the UI. + +:::info + +We have only recently started migrating to this type of component API. Some UI components are still using render props, and some UI customization isn't supported yet (such as the toolbar or the element properties panel). Stay tuned for more updates! + +::: + +Below are the currently supported components: + +- [MainMenu](/docs/@excalidraw/excalidraw/api/children-components/main-menu) +- [WelcomeScreen](/docs/@excalidraw/excalidraw/api/children-components/welcome-screen) +- [Footer](/docs/@excalidraw/excalidraw/api/children-components/footer) +- [LiveCollaborationTrigger](/docs/@excalidraw/excalidraw/api/children-components/live-collaboration-trigger) diff --git a/dev-docs/docs/@excalidraw/excalidraw/api/children-components/footer.mdx b/dev-docs/docs/@excalidraw/excalidraw/api/children-components/footer.mdx new file mode 100644 index 000000000..cdd5ea5a4 --- /dev/null +++ b/dev-docs/docs/@excalidraw/excalidraw/api/children-components/footer.mdx @@ -0,0 +1,68 @@ +# Footer + +Earlier we were using `renderFooter` prop to render custom footer which was removed in [#5970](https://github.com/excalidraw/excalidraw/pull/5970). Now you can pass a `Footer` component instead to render the custom UI for footer. + +You will need to import the `Footer` component from the package and wrap your component with the Footer component. The `Footer` should a valid React Node. + +**Usage** + +```jsx live +function App() { + return ( +
+ +
+ +
+
+
+ ); +} +``` + +This will only for `Desktop` devices. + +For `mobile` you will need to render it inside the [MainMenu](#mainmenu). You can use the [`useDevice`](#useDevice) hook to check the type of device, this will be available only inside the `children` of `Excalidraw` component. + +Open the `Menu` in the below playground and you will see the `custom footer` rendered. + +```jsx live noInline +const MobileFooter = ({}) => { + const device = useDevice(); + if (device.isMobile) { + return ( +
+ +
+ ); + } + return null; +}; + +const App = () => ( +
+ + + Item1 + Item 2 + + + +
+); + +// Need to render when code is span across multiple components +// in Live Code blocks editor +render(); +``` \ No newline at end of file diff --git a/dev-docs/docs/@excalidraw/excalidraw/api/children-components/live-collaboration-trigger.mdx b/dev-docs/docs/@excalidraw/excalidraw/api/children-components/live-collaboration-trigger.mdx new file mode 100644 index 000000000..ef74d0e65 --- /dev/null +++ b/dev-docs/docs/@excalidraw/excalidraw/api/children-components/live-collaboration-trigger.mdx @@ -0,0 +1,62 @@ +# LiveCollaborationTrigger + +If you implement live collaboration support and want to expose the same UI button as on [excalidraw.com](https://excalidraw.com), you can render the `` component using the [renderTopRightUI](/docs/@excalidraw/excalidraw/api/props#rendertoprightui) prop. + +You'll need to supply `onSelect()` to handle opening of your collaboration dialog, but the button will display `appState.collaborators` count provided you have supplied it. + +| Prop | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `onSelect` | `function` | Yes | | Handler called when the user clicks on the button | +| `isCollaborating` | `boolean` | Yes | false | Whether live collaboration session is in effect. Modifies button style. | + +```tsx live +function App() { + const [excalidrawAPI, setExcalidrawAPI] = useState(null); + const [isCollaborating, setIsCollaborating] = useState(false); + return ( +
+

+ Selecting the checkbox to see the collaborator count +

+ + setExcalidrawAPI(api)} + renderTopRightUI={() => ( + { + window.alert("You clicked on collab button"); + setIsCollaborating(true); + }} + /> + )} + > +
+ ); +} +``` diff --git a/dev-docs/docs/@excalidraw/excalidraw/api/children-components/main-menu.mdx b/dev-docs/docs/@excalidraw/excalidraw/api/children-components/main-menu.mdx new file mode 100644 index 000000000..2494df108 --- /dev/null +++ b/dev-docs/docs/@excalidraw/excalidraw/api/children-components/main-menu.mdx @@ -0,0 +1,167 @@ +# MainMenu + +By default Excalidraw will render the `MainMenu` with default options. If you want to customise the `MainMenu`, you can pass the `MainMenu` component with the list options. + +**Usage** + +```jsx live +function App() { + return ( +
+ + + window.alert("Item1")}> + Item1 + + window.alert("Item2")}> + Item 2 + + + +
+ ); +} +``` + +### `` + +This is the `MainMenu` component. If you render it, you will need to populate the menu with your own items as we will not render any ourselves at that point. + +| Prop | Type | Required | Default | Description | +| --- | --- | :-: | :-: | --- | +| `onSelect` | `function` | No | - | Triggered when any item is selected (via mouse). Calling `event.preventDefault()` will stop menu from closing. | + +### MainMenu.Item + +To render an item, its recommended to use `MainMenu.Item`. + +| Prop | Type | Required | Default | Description | +| --- | --- | :-: | :-: | --- | +| `onSelect` | `function` | Yes | - | Triggered when selected (via mouse). Calling `event.preventDefault()` will stop menu from closing. | +| `children` | `React.ReactNode` | Yes | - | The content of the menu item | +| `icon` | `JSX.Element` | No | - | The icon used in the menu item | +| `shortcut` | `string` | No | - | The shortcut to be shown for the menu item | + +### MainMenu.ItemLink + +To render an item as a link, its recommended to use `MainMenu.ItemLink`. + +**Usage** + +```jsx live +function App() { + return ( +
+ + + + Google + + + Excalidraw + + + +
+ ); +} +``` + +| Prop | Type | Required | Default | Description | +| --- | --- | :-: | :-: | --- | +| `onSelect` | `function` | No | - | Triggered when selected (via mouse). Calling `event.preventDefault()` will stop menu from closing. | +| `href` | `string` | Yes | - | The `href` attribute to be added to the `anchor` element. | +| `children` | `React.ReactNode` | Yes | - | The content of the menu item | +| `icon` | `JSX.Element` | No | - | The icon used in the menu item | +| `shortcut` | `string` | No | - | The shortcut to be shown for the menu item | + +### MainMenu.ItemCustom + +To render a custom item, you can use `MainMenu.ItemCustom`. + +**Usage** + +```jsx live +function App() { + return ( +
+ + + + + + + +
+ ); +} +``` + +| Prop | Type | Required | Default | Description | +| --- | --- | :-: | :-: | --- | +| `children` | `React.ReactNode` | Yes | - | The content of the menu item | + +### MainMenu.DefaultItems + +For the items which are shown in the menu in [excalidraw.com](https://excalidraw.com), you can use `MainMenu.DefaultItems` + +```jsx live +function App() { + return ( +
+ + + + + window.alert("Item1")}> + Item1 + + window.alert("Item2")}> + Item 2 + + + +
+ ); +} +``` + +Here is a [complete list](https://github.com/excalidraw/excalidraw/blob/master/src/components/mainMenu/DefaultItems.tsx) of the default items. + +### MainMenu.Group + +To Group item in the main menu, you can use `MainMenu.Group` + +```jsx live +function App() { + return ( +
+ + + + + + + + window.alert("Item1")}> + Item1 + + window.alert("Item2")}> + Item 2 + + + + +
+ ); +} +``` + +| Prop | Type | Required | Default | Description | +| --- | --- | :-: | :-: | --- | +| `children ` | `React.ReactNode` | Yes | - | The content of the `Menu Group` | diff --git a/dev-docs/docs/@excalidraw/excalidraw/api/children-components/welcome-screen.mdx b/dev-docs/docs/@excalidraw/excalidraw/api/children-components/welcome-screen.mdx new file mode 100644 index 000000000..8150508bf --- /dev/null +++ b/dev-docs/docs/@excalidraw/excalidraw/api/children-components/welcome-screen.mdx @@ -0,0 +1,140 @@ +# WelcomeScreen + +When the canvas is empty, Excalidraw can show a welcome _splash_ screen with a logo, a few quick action items, and hints explaining what some of the UI buttons do. Once the user picks a tool, or has created an element on the canvas, the welcome screen will disappear. + +You can enable this behavior by rendering a `WelcomeScreen` component like this: + +```jsx live +function App() { + return ( +
+ + + +
+ ); +} +``` + +You can also customize the welcome screen by passing children to the `WelcomeScreen` component. See below. + +## + +This is the main component. If you render it without any children, we will render the default welcome screen. + +You can customize which welcome screen subcomponents are rendered by passing them as children. + +The welcome screen consists of two main groups of subcomponents: + +1. [WelcomeScreen.Center](#welcomescreencenterlogo). +2. [WeelcomeScreen.Hints](#welcomescreenhints). + +Excalidraw logo: Sketch handrawn like diagrams. + +### Center + +`` subcomponent is the center piece of the welcome screen, containing the `logo`, `heading`, and `menu`. All three subcomponents are optional, and you can render whatever you wish into the center component. + +```jsx live +function App() { + return ( +
+ + + + + + Welcome Screen Heading! + + + + Excalidraw GitHub + + + + + + +
+ ); +} +``` + +#### Logo + +Use the `` to render a logo. By default it renders the Excalidraw logo and name. Supply `children` to customize. + +#### Heading + +Use the `` to render a heading below the logo. Supply `children` to change the default message. + +#### Menu + +`` is a wrapper component for the menu items. You can build your menu using the `` and `` components, render your own, or render one of the default menu items. + +The default menu items are: + +- `` - opens the help dialog. + +- `` - open the load file dialog. + +- `` - intended to open the live collaboration dialog. Works similarly to [``](/docs/@excalidraw/excalidraw/api/children-components/live-collaboration-trigger) and you must supply `onSelect()` handler to integrate with your collaboration implementation. + +#### MenuItem + +The `` component can be used to render a menu item. + +| Prop | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `onSelect` | `function` | Yes | | The handler is triggered when the item is selected. | +| `children` | `React.ReactNode` | Yes | | The content of the menu item | +| `icon` | `JSX.Element` | No | | The icon used in the menu item | +| `shortcut` | `string` | No | | The keyboard shortcut (label-only, does not affect behavior) | + +**WelcomeScreen.Center.MenuItemLink** + +To render an external link in a menu item, you can use this component. + +| Prop | Type | Required | Default | Description | +| --- | --- | --- | --- | --- | +| `href` | `string` | Yes | | The `href` attribute to be added to the `anchor` element. | +| `children` | `React.ReactNode` | Yes | | The content of the menu item | +| `icon` | `JSX.Element` | No | | The icon used in the menu item | +| `shortcut` | `string` | No | | The keyboard shortcut (label-only, does not affect behavior) | + +### Hints + +These `` subcomponents render the UI hints. Text of each hint can be customized by supplying `children`. + +```jsx live +function App() { + return ( +
+ + + +

ToolBar Hints

+
+ + +
+
+
+ ); +} +``` + +#### MenuHint + +`` hint subcomponent for the main menu. Supply `children` to customize the hint text. + +#### ToolbarHint + +`` hint subcomponent for the toolbar. Supply `children` to customize the hint text. + +#### Help + +`` hint subcomponent for the help dialog. Supply `children` to customize the hint text. diff --git a/dev-docs/docs/@excalidraw/excalidraw/api/constants.mdx b/dev-docs/docs/@excalidraw/excalidraw/api/constants.mdx new file mode 100644 index 000000000..a6c95ab2a --- /dev/null +++ b/dev-docs/docs/@excalidraw/excalidraw/api/constants.mdx @@ -0,0 +1,46 @@ +# Constants + +### FONT_FAMILY + +**How to use** + +```js +import { FONT_FAMILY } from "@excalidraw/excalidraw"; +``` + +`FONT_FAMILY` contains all the font families used in `Excalidraw` as explained below + +| Font Family | Description | +| ----------- | ---------------------- | +| `Virgil` | The `handwritten` font | +| `Helvetica` | The `Normal` Font | +| `Cascadia` | The `Code` Font | + +Defaults to `FONT_FAMILY.Virgil` unless passed in `initialData.appState.currentItemFontFamily`. + +### THEME + +**How to use** + +```js +import { THEME } from "@excalidraw/excalidraw"; +``` + +`THEME` contains all the themes supported by `Excalidraw` as explained below + +| Theme | Description | +| ------- | ----------------- | +| `LIGHT` | The `light` theme | +| `DARK` | The `Dark` theme | + +Defaults to `THEME.LIGHT` unless passed in `initialData.appState.theme` + +### MIME_TYPES + +[`MIME_TYPES`](https://github.com/excalidraw/excalidraw/blob/master/src/constants.ts#L101) contains all the mime types supported by `Excalidraw`. + +**How to use ** + +```js +import { MIME_TYPES } from "@excalidraw/excalidraw"; +``` diff --git a/dev-docs/docs/@excalidraw/excalidraw/api/props/initialdata.mdx b/dev-docs/docs/@excalidraw/excalidraw/api/props/initialdata.mdx new file mode 100644 index 000000000..7d79128f0 --- /dev/null +++ b/dev-docs/docs/@excalidraw/excalidraw/api/props/initialdata.mdx @@ -0,0 +1,55 @@ +# initialData + +
+{ elements?: ExcalidrawElement[], appState?: AppState }
+
+ +This helps to load Excalidraw with `initialData`. It must be an object or a [promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise) which resolves to an object containing the below optional fields. + +| Name | Type | Description | +| --- | --- | --- | +| `elements` | [ExcalidrawElement[]](https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L114) | The `elements` with which `Excalidraw` should be mounted. | +| `appState` | [AppState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L95) | The `AppState` with which `Excalidraw` should be mounted. | +| `scrollToContent` | `boolean` | This attribute indicates whether to `scroll` to the nearest element to center once `Excalidraw` is mounted. By default, it will not scroll the nearest element to the center. Make sure you pass `initialData.appState.scrollX` and `initialData.appState.scrollY` when `scrollToContent` is false so that scroll positions are retained | +| `libraryItems` | [LibraryItems](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L247) | Promise<[LibraryItems](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L200)> | This library items with which `Excalidraw` should be mounted. | +| `files` | [BinaryFiles](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L82) | The `files` added to the scene. | + +You might want to use this when you want to load excalidraw with some initial elements and app state. + +```jsx live +function App() { + return ( +
+ +
+ ); +} +``` diff --git a/dev-docs/docs/@excalidraw/excalidraw/api/props/props.mdx b/dev-docs/docs/@excalidraw/excalidraw/api/props/props.mdx new file mode 100644 index 000000000..104d9dccd --- /dev/null +++ b/dev-docs/docs/@excalidraw/excalidraw/api/props/props.mdx @@ -0,0 +1,240 @@ +# Props + +All `props` are *optional*. + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| [`initialData`](/docs/@excalidraw/excalidraw/api/props/initialdata) | `object` | `null` | Promise | `null` | The initial data with which app loads. | +| [`ref`](/docs/@excalidraw/excalidraw/api/props/ref) | `object` | _ | `Ref` to be passed to Excalidraw | +| [`isCollaborating`](#iscollaborating) | `boolean` | _ | This indicates if the app is in `collaboration` mode | +| [`onChange`](#onchange) | `function` | _ | This callback is triggered whenever the component updates due to any change. This callback will receive the excalidraw `elements` and the current `app state`. | +| [`onPointerUpdate`](#onpointerupdate) | `function` | _ | Callback triggered when mouse pointer is updated. | +| [`onPointerDown`](#onpointerdown) | `function` | _ | This prop if passed gets triggered on pointer down evenets | +| [`onScrollChange`](#onscrollchange) | `function` | _ | This prop if passed gets triggered when scrolling the canvas. | +| [`onPaste`](#onpaste) | `function` | _ | Callback to be triggered if passed when the something is pasted in to the scene | +| [`onLibraryChange`](#onlibrarychange) | `function` | _ | The callback if supplied is triggered when the library is updated and receives the library items. | +| [`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 | +| [`renderCustomStats`](/docs/@excalidraw/excalidraw/api/props/render-props#rendercustomstats) | `function` | _ | Render function that can be used to render custom stats on the stats dialog. | +| [`renderSidebar`](/docs/@excalidraw/excalidraw/api/props/render-props#rendersidebar) | `function` | _ | Render function that renders custom sidebar. | +| [`viewModeEnabled`](#viewmodeenabled) | `boolean` | _ | This indicates if the app is in `view` mode. | +| [`zenModeEnabled`](#zenmodeenabled) | `boolean` | _ | This indicates if the `zen` mode is enabled | +| [`gridModeEnabled`](#gridmodeenabled) | `boolean` | _ | This indicates if the `grid` mode is enabled | +| [`libraryReturnUrl`](#libraryreturnurl) | `string` | _ | What URL should [libraries.excalidraw.com](https://libraries.excalidraw.com) be installed to | +| [`theme`](#theme) | `"light"` | `"dark"` | `"light"` | The theme of the Excalidraw component | +| [`name`](#name) | `string` | | Name of the drawing | +| [`UIOptions`](/docs/@excalidraw/excalidraw/api/props/ui-options) | `object` | [DEFAULT UI OPTIONS](https://github.com/excalidraw/excalidraw/blob/master/src/constants.ts#L151) | To customise UI options. Currently we support customising [`canvas actions`](#canvasactions) | +| [`detectScroll`](#detectscroll) | `boolean` | `true` | Indicates whether to update the offsets when nearest ancestor is scrolled. | +| [`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 | +| [`renderEmbeddable`](/docs/@excalidraw/excalidraw/api/props/render-props#renderEmbeddable) | `function` | \_ | Render function that can override the built-in `