Compare commits

...

45 Commits

Author SHA1 Message Date
Aakansha Doshi 0896892f8a docs: release @excalidraw/excalidraw@0.11.0 🎉 (#4799)
* docs: release @excalidraw/excalidraw@0.11.0  🎉

* Add commit link for bad commits
2022-02-17 18:52:44 +05:30
Aakansha Doshi 7fe225ee99 fix: rename --color-primary-chubb to --color-primary-contrast-offset and fallback to primary color if not present (#4803)
* fix: fallback to primary color if --color-primary-chubb not present

* rename to --color-primary-contrast-offset

* use contarst-offset

Co-authored-by: David Luzar <luzar.david@gmail.com>

* Update src/packages/excalidraw/README_NEXT.md

* remove

* Update src/packages/excalidraw/README_NEXT.md

Co-authored-by: David Luzar <luzar.david@gmail.com>

Co-authored-by: David Luzar <luzar.david@gmail.com>
2022-02-17 18:22:19 +05:30
Aakansha Doshi d2fd7be457 fix: add commits directly pushed to master in changelog (#4798) 2022-02-16 21:01:59 +05:30
David Luzar 5c61613a2e fix: don't bump element version when adding files data (#4794)
* fix: don't bump element version when adding files data

* fix lint
2022-02-16 18:26:36 +05:30
Aakansha Doshi b2767924de feat: show group/group and link action in mobile (#4795) 2022-02-16 15:41:35 +05:30
dependabot[bot] 59d0a77862 chore(deps): bump @types/react from 17.0.38 to 17.0.39 (#4757)
Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 17.0.38 to 17.0.39.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/react)

---
updated-dependencies:
- dependency-name: "@types/react"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-16 13:59:14 +05:30
Aakansha Doshi 987526d1e5 docs: tweak documentation for release and add examples (#4786)
* docs: tweak documentation for release

* Add image in initial data

* Add image

* remove watermark and make export work

* update readme
2022-02-15 19:13:46 +05:30
dependabot[bot] e894d41a22 chore(deps): bump vm2 from 3.9.5 to 3.9.7 (#4785)
Bumps [vm2](https://github.com/patriksimek/vm2) from 3.9.5 to 3.9.7.
- [Release notes](https://github.com/patriksimek/vm2/releases)
- [Changelog](https://github.com/patriksimek/vm2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/patriksimek/vm2/compare/3.9.5...3.9.7)

---
updated-dependencies:
- dependency-name: vm2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-15 16:47:23 +05:30
Aakansha Doshi 14d1d39e8e chore: variable naming :) (#4782) 2022-02-15 16:31:14 +05:30
Aakansha Doshi 69336b4832 build: rename release command to 'release package' (#4783) 2022-02-14 17:47:52 +05:30
dependabot[bot] 32b677fb8a chore(deps): bump follow-redirects in /src/packages/excalidraw (#4781)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.7 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.7...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-14 14:03:04 +05:30
dependabot[bot] 570f725516 chore(deps): bump follow-redirects from 1.14.7 to 1.14.8 (#4780)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.7 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.7...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-14 13:54:57 +05:30
Aakansha Doshi a60860867c build: release preview package when triggered via comment (#4750)
* build: autorelease preview on every commit during pull request

* add github workflow

* update readme

* update docs

* log changed files

* remove depth

* fetch pr head

* remove console.log

* log pr number

* pull pr number

* use pull request number in release version

* dummy

* dummy

* dummy

* fix

* dummy

* fix

* Add comment and set output as version

* dummy

* fix

* fix

* set output through js toolkit

* install

* dummy

* update

* fix

* fix

* typo

* update

* condition

* typo

* testing

* wrap conditions

* echo

* hope it works

* test

* test

* yay test again

* test updated

* remove reaction

* run if comment triggered

* fix

* fix

* Update script after testing in fork

* remove

* update changelog

* update readme

* update

* remove

* append pr number then commit hash
2022-02-14 13:54:24 +05:30
zsviczian 7a61196462 fix: mobile link click (#4742)
* add tolerance to redirect pointerDown_Up check

* Update src/components/App.tsx

Co-authored-by: David Luzar <luzar.david@gmail.com>

* Update App.tsx

* lint

* lint

* fix for ipad/mobile

* Update App.tsx

* Update App.tsx

* Update App.tsx

* testing if isIPad works on iOS15

* Update App.tsx

* Update keys.ts

* Update keys.ts

* lint

* test

* removed isTouchScreen

* isTouchScreen

* lint

* lint

* Update App.tsx

* tweak

Co-authored-by: David Luzar <luzar.david@gmail.com>
Co-authored-by: ad1992 <aakansha1216@gmail.com>
2022-02-10 14:52:33 +05:30
David Luzar 9653d676fe fix: contextMenu timer & pointers not correctly reset on iOS (#4765) 2022-02-09 20:42:02 +01:00
Arun 0cdd0eebf1 feat: support background fill for freedraw shapes (#4610)
* feat: support background fill for freedraw shapes

* refactor & support fill style

* make filled freedraw shapes selectable from inside

* get hit test on solid freedraw shapes to somewhat work

* fix SVG export of unclosed freedraw shapes & improve types

* fix lint

* type tweaks

* reuse `hitTestCurveInside` for collision tests

Co-authored-by: dwelle <luzar.david@gmail.com>
2022-02-09 17:43:21 +01:00
Aakansha Doshi ae8b1d8bf7 build: deploy excalidraw package example (#4762)
* build: deploy excalidraw package example

* deploy public

* install deps script

* new lines
2022-02-09 17:45:16 +05:30
Aakansha Doshi 92ffe8dda6 fix: use absolute coords when rendering link popover (#4753) 2022-02-09 16:33:49 +05:30
dependabot[bot] 4d9dbd5a45 chore(deps-dev): bump css-loader in /src/packages/excalidraw (#4712)
Bumps [css-loader](https://github.com/webpack-contrib/css-loader) from 6.5.1 to 6.6.0.
- [Release notes](https://github.com/webpack-contrib/css-loader/releases)
- [Changelog](https://github.com/webpack-contrib/css-loader/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/css-loader/compare/v6.5.1...v6.6.0)

---
updated-dependencies:
- dependency-name: css-loader
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-09 07:41:07 +00:00
dependabot[bot] c66cabaefd chore(deps-dev): bump webpack-cli in /src/packages/excalidraw (#4664)
Bumps [webpack-cli](https://github.com/webpack/webpack-cli) from 4.9.1 to 4.9.2.
- [Release notes](https://github.com/webpack/webpack-cli/releases)
- [Changelog](https://github.com/webpack/webpack-cli/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-cli/compare/webpack-cli@4.9.1...webpack-cli@4.9.2)

---
updated-dependencies:
- dependency-name: webpack-cli
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-09 07:37:33 +00:00
dependabot[bot] e073128469 chore(deps-dev): bump @babel/core in /src/packages/utils (#4754)
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.16.7 to 7.17.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.17.2/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-09 07:25:15 +00:00
dependabot[bot] 835848d711 chore(deps): bump sass from 1.47.0 to 1.49.7 (#4723)
Bumps [sass](https://github.com/sass/dart-sass) from 1.47.0 to 1.49.7.
- [Release notes](https://github.com/sass/dart-sass/releases)
- [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sass/dart-sass/compare/1.47.0...1.49.7)

---
updated-dependencies:
- dependency-name: sass
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-09 12:52:23 +05:30
dependabot[bot] 2bd1d7ef59 chore(deps-dev): bump lint-staged from 12.1.7 to 12.3.3 (#4724)
Bumps [lint-staged](https://github.com/okonet/lint-staged) from 12.1.7 to 12.3.3.
- [Release notes](https://github.com/okonet/lint-staged/releases)
- [Commits](https://github.com/okonet/lint-staged/compare/v12.1.7...v12.3.3)

---
updated-dependencies:
- dependency-name: lint-staged
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-09 12:51:23 +05:30
dependabot[bot] 37c8b9c2ff chore(deps-dev): bump webpack-dev-server in /src/packages/excalidraw (#4713)
Bumps [webpack-dev-server](https://github.com/webpack/webpack-dev-server) from 4.7.3 to 4.7.4.
- [Release notes](https://github.com/webpack/webpack-dev-server/releases)
- [Changelog](https://github.com/webpack/webpack-dev-server/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack-dev-server/compare/v4.7.3...v4.7.4)

---
updated-dependencies:
- dependency-name: webpack-dev-server
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-09 12:50:10 +05:30
dependabot[bot] cf9f00f55f chore(deps-dev): bump chai from 4.3.4 to 4.3.6 (#4667)
Bumps [chai](https://github.com/chaijs/chai) from 4.3.4 to 4.3.6.
- [Release notes](https://github.com/chaijs/chai/releases)
- [Changelog](https://github.com/chaijs/chai/blob/4.x.x/History.md)
- [Commits](https://github.com/chaijs/chai/compare/v4.3.4...v4.3.6)

---
updated-dependencies:
- dependency-name: chai
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-09 12:49:53 +05:30
dependabot[bot] 7ae9043221 chore(deps): bump @testing-library/jest-dom from 5.16.1 to 5.16.2 (#4745)
Bumps [@testing-library/jest-dom](https://github.com/testing-library/jest-dom) from 5.16.1 to 5.16.2.
- [Release notes](https://github.com/testing-library/jest-dom/releases)
- [Changelog](https://github.com/testing-library/jest-dom/blob/main/CHANGELOG.md)
- [Commits](https://github.com/testing-library/jest-dom/compare/v5.16.1...v5.16.2)

---
updated-dependencies:
- dependency-name: "@testing-library/jest-dom"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-09 12:49:33 +05:30
dependabot[bot] 7c567408c5 chore(deps-dev): bump @babel/core in /src/packages/excalidraw (#4707)
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.16.7 to 7.17.0.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.17.0/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-09 12:49:09 +05:30
dependabot[bot] 54612621aa chore(deps-dev): bump terser-webpack-plugin in /src/packages/excalidraw (#4709)
Bumps [terser-webpack-plugin](https://github.com/webpack-contrib/terser-webpack-plugin) from 5.3.0 to 5.3.1.
- [Release notes](https://github.com/webpack-contrib/terser-webpack-plugin/releases)
- [Changelog](https://github.com/webpack-contrib/terser-webpack-plugin/blob/master/CHANGELOG.md)
- [Commits](https://github.com/webpack-contrib/terser-webpack-plugin/compare/v5.3.0...v5.3.1)

---
updated-dependencies:
- dependency-name: terser-webpack-plugin
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-09 12:48:21 +05:30
Arun d27b3bbebe fix: changing font size when text is not selected or edited (#4751)
Co-authored-by: dwelle <luzar.david@gmail.com>
2022-02-08 21:18:43 +00:00
Aakansha Doshi e4ffc9812e docs: changelog tweaks (#4749) 2022-02-08 18:58:37 +05:30
David Luzar a066317d3c feat: add onLinkOpen component prop (#4694)
Co-authored-by: ad1992 <aakansha1216@gmail.com>
2022-02-08 11:25:35 +01:00
David Luzar 050bc1ce2b feat: keep selected tool on canvas reset (#4728) 2022-02-07 22:30:06 +01:00
David Luzar 5007df6522 fix: disable contextmenu on non-secondary pen events or touch (#4675) 2022-02-07 20:01:36 +01:00
zsviczian d450c36581 fix: mobile context menu won't show on long press (#4741)
* scribble fix only if not Android

* Update src/components/App.tsx

Co-authored-by: David Luzar <luzar.david@gmail.com>
2022-02-07 19:46:29 +01:00
Aakansha Doshi 66c92fc65a feat: Make whole element clickable in view mode when it has hyperlink (#4735)
* feat: Make whole element clickable in view mode when it has hyperlink

* redirect to link if pointerup and pointer down is exactly same point

* don't make element clickable in mobile
2022-02-07 19:54:39 +05:30
David Luzar 5f1cd4591a fix: do not open links twice (#4738) 2022-02-07 12:20:19 +00:00
Aakansha Doshi 9be6243873 fix: make link icon clickable in mobile (#4736) 2022-02-07 17:24:51 +05:30
David Luzar c3f6d6d344 test: revert node v16 requirement for tests (#4737) 2022-02-07 12:27:31 +01:00
David Luzar 339636caab feat: allow any precision when zooming (#4730) 2022-02-06 21:58:59 +01:00
David Luzar 08115ef311 fix: Apple Pen missing strokes (#4705) 2022-02-06 20:07:37 +01:00
Excalidraw Bot e68abdbab4 chore: Update translations from Crowdin (#4590) 2022-02-06 18:08:55 +01:00
David Luzar 8aff076782 feat: throttle pointermove events per framerate (#4727) 2022-02-06 17:45:37 +01:00
zsviczian 96de887cc8 fix: freedraw slow movement jittery lines (#4726)
Co-authored-by: David Luzar <luzar.david@gmail.com>
2022-02-06 17:45:23 +01:00
zsviczian 98ea46664c fix: Disable three finger pinch zoom in penMode (#4725) 2022-02-06 16:56:52 +01:00
Aakansha Doshi 00e30ca0e4 fix: remove click listener for opening popup (#4700)
* fix: remove click listener for oening popup

* fix
2022-02-04 20:36:21 +05:30
88 changed files with 2111 additions and 765 deletions
@@ -23,4 +23,5 @@ jobs:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Auto release
run: |
yarn add @actions/core
yarn autorelease
+55
View File
@@ -0,0 +1,55 @@
name: Auto release preview @excalidraw/excalidraw-preview
on:
issue_comment:
types: [created, edited]
jobs:
Auto-release-excalidraw-preview:
name: Auto release preview
if: github.event.comment.body == '@excalibot release package' && github.event.issue.pull_request
runs-on: ubuntu-latest
steps:
- name: React to release comment
uses: peter-evans/create-or-update-comment@v1
with:
token: ${{ secrets.PUSH_TRANSLATIONS_COVERAGE_PAT }}
comment-id: ${{ github.event.comment.id }}
reactions: "+1"
- name: Get PR SHA
id: sha
uses: actions/github-script@v4
with:
result-encoding: string
script: |
const { owner, repo, number } = context.issue;
const pr = await github.pulls.get({
owner,
repo,
pull_number: number,
});
return pr.data.head.sha
- uses: actions/checkout@v2
with:
ref: ${{ steps.sha.outputs.result }}
fetch-depth: 2
- name: Setup Node.js 14.x
uses: actions/setup-node@v2
with:
node-version: 14.x
- name: Set up publish access
run: |
npm config set //registry.npmjs.org/:_authToken ${NPM_TOKEN}
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Auto release preview
id: "autorelease"
run: |
yarn add @actions/core
yarn autorelease preview ${{ github.event.issue.number }}
- name: Post comment post release
if: always()
uses: peter-evans/create-or-update-comment@v1
with:
token: ${{ secrets.PUSH_TRANSLATIONS_COVERAGE_PAT }}
issue-number: ${{ github.event.issue.number }}
body: "@${{ github.event.comment.user.login }} ${{ steps.autorelease.outputs.result }}"
+1 -1
View File
@@ -10,7 +10,7 @@ jobs:
- name: Setup Node.js 14.x
uses: actions/setup-node@v2
with:
node-version: 16.x
node-version: 14.x
- name: Install and test
run: |
yarn --frozen-lockfile
+4
View File
@@ -23,3 +23,7 @@ static
yarn-debug.log*
yarn-error.log*
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
+7 -7
View File
@@ -21,12 +21,12 @@
"dependencies": {
"@sentry/browser": "6.2.5",
"@sentry/integrations": "6.2.5",
"@testing-library/jest-dom": "5.16.1",
"@testing-library/jest-dom": "5.16.2",
"@testing-library/react": "12.1.2",
"@tldraw/vec": "1.4.3",
"@types/jest": "27.4.0",
"@types/pica": "5.1.3",
"@types/react": "17.0.38",
"@types/react": "17.0.39",
"@types/react-dom": "17.0.11",
"@types/socket.io-client": "1.4.36",
"browser-fs-access": "0.23.0",
@@ -50,9 +50,9 @@
"react-dom": "17.0.2",
"react-scripts": "4.0.3",
"roughjs": "4.5.2",
"sass": "1.47.0",
"sass": "1.49.7",
"socket.io-client": "2.3.1",
"typescript": "4.5.4"
"typescript": "4.5.5"
},
"devDependencies": {
"@excalidraw/eslint-config": "1.0.0",
@@ -61,20 +61,20 @@
"@types/lodash.throttle": "4.1.6",
"@types/pako": "1.0.3",
"@types/resize-observer-browser": "0.1.6",
"chai": "4.3.4",
"chai": "4.3.6",
"dotenv": "10.0.0",
"eslint-config-prettier": "8.3.0",
"eslint-plugin-prettier": "3.3.1",
"firebase-tools": "9.23.0",
"husky": "7.0.4",
"jest-canvas-mock": "2.3.1",
"lint-staged": "12.1.7",
"lint-staged": "12.3.3",
"pepjs": "0.5.3",
"prettier": "2.5.1",
"rewire": "5.0.0"
},
"resolutions": {
"@typescript-eslint/typescript-estree": "5.3.0"
"@typescript-eslint/typescript-estree": "5.10.2"
},
"engines": {
"node": ">=14.0.0"
+30 -5
View File
@@ -1,5 +1,6 @@
const fs = require("fs");
const { exec, execSync } = require("child_process");
const core = require("@actions/core");
const excalidrawDir = `${__dirname}/../src/packages/excalidraw`;
const excalidrawPackage = `${excalidrawDir}/package.json`;
@@ -15,18 +16,25 @@ const publish = () => {
execSync(`yarn --frozen-lockfile`, { cwd: excalidrawDir });
execSync(`yarn run build:umd`, { cwd: excalidrawDir });
execSync(`yarn --cwd ${excalidrawDir} publish`);
console.info("Published 🎉");
core.setOutput(
"result",
`**Preview version has been shipped** :rocket:
You can use [@excalidraw/excalidraw-preview@${pkg.version}](https://www.npmjs.com/package/@excalidraw/excalidraw-preview/v/${pkg.version}) for testing!`,
);
} catch (error) {
core.setOutput("result", "package couldn't be published :warning:!");
console.error(error);
process.exit(1);
}
};
// get files changed between prev and head commit
exec(`git diff --name-only HEAD^ HEAD`, async (error, stdout, stderr) => {
if (error || stderr) {
console.error(error);
core.setOutput("result", ":warning: Package couldn't be published!");
process.exit(1);
}
const changedFiles = stdout.trim().split("\n");
const filesToIgnoreRegex = /src\/excalidraw-app|packages\/utils/;
@@ -37,16 +45,33 @@ exec(`git diff --name-only HEAD^ HEAD`, async (error, stdout, stderr) => {
);
});
if (!excalidrawPackageFiles.length) {
console.info("Skipping release as no valid diff found");
core.setOutput("result", "Skipping release as no valid diff found");
process.exit(0);
}
// update package.json
pkg.version = `${pkg.version}-${getShortCommitHash()}`;
pkg.name = "@excalidraw/excalidraw-next";
fs.writeFileSync(excalidrawPackage, JSON.stringify(pkg, null, 2), "utf8");
let version = `${pkg.version}-${getShortCommitHash()}`;
// update readme
const data = fs.readFileSync(`${excalidrawDir}/README_NEXT.md`, "utf8");
let data = fs.readFileSync(`${excalidrawDir}/README_NEXT.md`, "utf8");
const isPreview = process.argv.slice(2)[0] === "preview";
if (isPreview) {
// use pullNumber-commithash as the version for preview
const pullRequestNumber = process.argv.slice(3)[0];
version = `${pkg.version}-${pullRequestNumber}-${getShortCommitHash()}`;
// replace "excalidraw-next" with "excalidraw-preview"
pkg.name = "@excalidraw/excalidraw-preview";
data = data.replace(/excalidraw-next/g, "excalidraw-preview");
data = data.trim();
}
pkg.version = version;
fs.writeFileSync(excalidrawPackage, JSON.stringify(pkg, null, 2), "utf8");
fs.writeFileSync(`${excalidrawDir}/README.md`, data, "utf8");
console.info("Publish in progress...");
publish();
});
+18 -11
View File
@@ -20,7 +20,7 @@ const headerForType = {
perf: "Performance",
build: "Build",
};
const badCommits = [];
const getCommitHashForLastVersion = async () => {
try {
const commitMessage = `"release @excalidraw/excalidraw@${lastVersion}"`;
@@ -53,19 +53,26 @@ const getLibraryCommitsSinceLastRelease = async () => {
const messageWithoutType = commit.slice(indexOfColon + 1).trim();
const messageWithCapitalizeFirst =
messageWithoutType.charAt(0).toUpperCase() + messageWithoutType.slice(1);
const prNumber = commit.match(/\(#([0-9]*)\)/)[1];
const prMatch = commit.match(/\(#([0-9]*)\)/);
if (prMatch) {
const prNumber = prMatch[1];
// return if the changelog already contains the pr number which would happen for package updates
if (existingChangeLog.includes(prNumber)) {
return;
// return if the changelog already contains the pr number which would happen for package updates
if (existingChangeLog.includes(prNumber)) {
return;
}
const prMarkdown = `[#${prNumber}](https://github.com/excalidraw/excalidraw/pull/${prNumber})`;
const messageWithPRLink = messageWithCapitalizeFirst.replace(
/\(#[0-9]*\)/,
prMarkdown,
);
commitList[type].push(messageWithPRLink);
} else {
badCommits.push(commit);
commitList[type].push(messageWithCapitalizeFirst);
}
const prMarkdown = `[#${prNumber}](https://github.com/excalidraw/excalidraw/pull/${prNumber})`;
const messageWithPRLink = messageWithCapitalizeFirst.replace(
/\(#[0-9]*\)/,
prMarkdown,
);
commitList[type].push(messageWithPRLink);
});
console.info("Bad commits:", badCommits);
return commitList;
};
+2
View File
@@ -65,6 +65,8 @@ export const actionClearCanvas = register({
gridSize: appState.gridSize,
showStats: appState.showStats,
pasteDialog: appState.pasteDialog,
elementType:
appState.elementType === "image" ? "selection" : appState.elementType,
},
commitToHistory: true,
};
+7 -2
View File
@@ -145,6 +145,7 @@ const changeFontSize = (
elements: readonly ExcalidrawElement[],
appState: AppState,
getNewFontSize: (element: ExcalidrawTextElement) => number,
fallbackValue?: ExcalidrawTextElement["fontSize"],
) => {
const newFontSizes = new Set<number>();
@@ -182,7 +183,7 @@ const changeFontSize = (
currentItemFontSize:
newFontSizes.size === 1
? [...newFontSizes][0]
: appState.currentItemFontSize,
: fallbackValue ?? appState.currentItemFontSize,
},
commitToHistory: true,
};
@@ -520,7 +521,7 @@ export const actionChangeOpacity = register({
export const actionChangeFontSize = register({
name: "changeFontSize",
perform: (elements, appState, value) => {
return changeFontSize(elements, appState, () => value);
return changeFontSize(elements, appState, () => value, value);
},
PanelComponent: ({ elements, appState, updateData }) => (
<fieldset>
@@ -532,21 +533,25 @@ export const actionChangeFontSize = register({
value: 16,
text: t("labels.small"),
icon: <FontSizeSmallIcon theme={appState.theme} />,
testId: "fontSize-small",
},
{
value: 20,
text: t("labels.medium"),
icon: <FontSizeMediumIcon theme={appState.theme} />,
testId: "fontSize-medium",
},
{
value: 28,
text: t("labels.large"),
icon: <FontSizeLargeIcon theme={appState.theme} />,
testId: "fontSize-large",
},
{
value: 36,
text: t("labels.veryLarge"),
icon: <FontSizeExtraLargeIcon theme={appState.theme} />,
testId: "fontSize-veryLarge",
},
]}
value={getFormValue(
+3 -3
View File
@@ -150,12 +150,12 @@ export const SelectedShapeActions = ({
</div>
</fieldset>
)}
{!isMobile && !isEditing && targetElements.length > 0 && (
{!isEditing && targetElements.length > 0 && (
<fieldset>
<legend>{t("labels.actions")}</legend>
<div className="buttonList">
{renderAction("duplicateSelection")}
{renderAction("deleteSelectedElements")}
{!isMobile && renderAction("duplicateSelection")}
{!isMobile && renderAction("deleteSelectedElements")}
{renderAction("group")}
{renderAction("ungroup")}
{targetElements.length === 1 && renderAction("link")}
+139 -56
View File
@@ -115,11 +115,7 @@ import {
updateBoundElements,
} from "../element/binding";
import { LinearElementEditor } from "../element/linearElementEditor";
import {
bumpVersion,
mutateElement,
newElementWith,
} from "../element/mutateElement";
import { mutateElement, newElementWith } from "../element/mutateElement";
import { deepCopyElement, newFreeDrawElement } from "../element/newElement";
import {
hasBoundTextElement,
@@ -163,6 +159,7 @@ import {
shouldRotateWithDiscreteAngle,
isArrowKey,
KEYS,
isAndroid,
} from "../keys";
import { distance2d, getGridPoint, isPathALoop } from "../math";
import { renderScene } from "../renderer";
@@ -212,6 +209,8 @@ import {
tupleToCoors,
viewportCoordsToSceneCoords,
withBatchedUpdates,
wrapEvent,
withBatchedUpdatesThrottled,
} from "../utils";
import ContextMenu, { ContextMenuOption } from "./ContextMenu";
import LayerUI from "./LayerUI";
@@ -415,7 +414,7 @@ class App extends React.Component<AppProps, AppState> {
ref={this.handleCanvasRef}
onContextMenu={this.handleCanvasContextMenu}
onPointerMove={this.handleCanvasPointerMove}
onPointerUp={this.removePointer}
onPointerUp={this.handleCanvasPointerUp}
onPointerCancel={this.removePointer}
onTouchMove={this.handleTouchMove}
onPointerDown={this.handleCanvasPointerDown}
@@ -438,7 +437,7 @@ class App extends React.Component<AppProps, AppState> {
onPointerDown={this.handleCanvasPointerDown}
onDoubleClick={this.handleCanvasDoubleClick}
onPointerMove={this.handleCanvasPointerMove}
onPointerUp={this.removePointer}
onPointerUp={this.handleCanvasPointerUp}
onPointerCancel={this.removePointer}
onTouchMove={this.handleTouchMove}
>
@@ -524,6 +523,7 @@ class App extends React.Component<AppProps, AppState> {
element={selectedElement[0]}
appState={this.state}
setAppState={this.setAppState}
onLinkOpen={this.props.onLinkOpen}
/>
)}
{this.state.showStats && (
@@ -1272,6 +1272,12 @@ class App extends React.Component<AppProps, AppState> {
}
private onTapStart = (event: TouchEvent) => {
// fix for Apple Pencil Scribble
// On Android, preventing the event would disable contextMenu on tap-hold
if (!isAndroid) {
event.preventDefault();
}
if (!didTapTwice) {
didTapTwice = true;
clearTimeout(tappedTwiceTimer);
@@ -1293,7 +1299,10 @@ class App extends React.Component<AppProps, AppState> {
didTapTwice = false;
clearTimeout(tappedTwiceTimer);
}
event.preventDefault();
if (isAndroid) {
event.preventDefault();
}
if (event.touches.length === 2) {
this.setState({
selectedElementIds: {},
@@ -1302,11 +1311,14 @@ class App extends React.Component<AppProps, AppState> {
};
private onTapEnd = (event: TouchEvent) => {
this.resetContextMenuTimer();
if (event.touches.length > 0) {
this.setState({
previousSelectedElementIds: {},
selectedElementIds: this.state.previousSelectedElementIds,
});
} else {
gesture.pointers.clear();
}
};
@@ -1519,12 +1531,8 @@ class App extends React.Component<AppProps, AppState> {
};
removePointer = (event: React.PointerEvent<HTMLElement> | PointerEvent) => {
this.lastPointerUp = event;
// remove touch handler for context menu on touch devices
if (event.pointerType === "touch" && touchTimeout) {
clearTimeout(touchTimeout);
touchTimeout = 0;
invalidateContextMenu = false;
if (touchTimeout) {
this.resetContextMenuTimer();
}
gesture.pointers.delete(event.pointerId);
@@ -1608,9 +1616,6 @@ class App extends React.Component<AppProps, AppState> {
this.files = { ...this.files, ...Object.fromEntries(filesMap) };
// bump versions for elements that reference added files so that
// we/host apps can detect the change, and invalidate the image & shape
// cache
this.scene.getElements().forEach((element) => {
if (
isInitializedImageElement(element) &&
@@ -1618,7 +1623,6 @@ class App extends React.Component<AppProps, AppState> {
) {
this.imageCache.delete(element.fileId);
invalidateShapeForElement(element);
bumpVersion(element);
}
});
this.scene.informMutation();
@@ -1924,7 +1928,7 @@ class App extends React.Component<AppProps, AppState> {
// zoom in at the right location on the touchMove handler already.
// On Macbook, we don't have those events so will zoom in at the
// current location instead.
if (gesture.pointers.size === 2) {
if (gesture.pointers.size >= 2) {
return;
}
@@ -2363,16 +2367,35 @@ class App extends React.Component<AppProps, AppState> {
}
return (
element.link &&
isPointHittingLinkIcon(element, this.state, [
scenePointer.x,
scenePointer.y,
]) &&
isPointHittingLinkIcon(
element,
this.state,
[scenePointer.x, scenePointer.y],
this.isMobile,
) &&
index <= hitElementIndex
);
});
};
private redirectToLink = () => {
private redirectToLink = (
event: React.PointerEvent<HTMLCanvasElement>,
isTouchScreen: boolean,
) => {
const draggedDistance = distance2d(
this.lastPointerDown!.clientX,
this.lastPointerDown!.clientY,
this.lastPointerUp!.clientX,
this.lastPointerUp!.clientY,
);
if (
!this.hitLinkElement ||
// For touch screen allow dragging threshold else strict check
(isTouchScreen && draggedDistance > DRAGGING_THRESHOLD) ||
(!isTouchScreen && draggedDistance !== 0)
) {
return;
}
const lastPointerDownCoords = viewportCoordsToSceneCoords(
this.lastPointerDown!,
this.state,
@@ -2381,35 +2404,38 @@ class App extends React.Component<AppProps, AppState> {
this.hitLinkElement!,
this.state,
[lastPointerDownCoords.x, lastPointerDownCoords.y],
this.isMobile,
);
const lastPointerUpCoords = viewportCoordsToSceneCoords(
this.lastPointerUp!,
this.state,
);
const LastPointerUpHittingLinkIcon = isPointHittingLinkIcon(
const lastPointerUpHittingLinkIcon = isPointHittingLinkIcon(
this.hitLinkElement!,
this.state,
[lastPointerUpCoords.x, lastPointerUpCoords.y],
this.isMobile,
);
if (lastPointerDownHittingLinkIcon && LastPointerUpHittingLinkIcon) {
const url = this.hitLinkElement?.link;
if (lastPointerDownHittingLinkIcon && lastPointerUpHittingLinkIcon) {
const url = this.hitLinkElement.link;
if (url) {
const target = isLocalLink(url) ? "_self" : "_blank";
const newWindow = window.open(undefined, target);
// https://mathiasbynens.github.io/rel-noopener/
if (newWindow) {
newWindow.opener = null;
newWindow.location = normalizeLink(url);
let customEvent;
if (this.props.onLinkOpen) {
customEvent = wrapEvent(EVENT.EXCALIDRAW_LINK, event.nativeEvent);
this.props.onLinkOpen(this.hitLinkElement, customEvent);
}
if (!customEvent?.defaultPrevented) {
const target = isLocalLink(url) ? "_self" : "_blank";
const newWindow = window.open(undefined, target);
// https://mathiasbynens.github.io/rel-noopener/
if (newWindow) {
newWindow.opener = null;
newWindow.location = normalizeLink(url);
}
}
}
}
};
private attachLinkListener = () => {
this.canvas?.addEventListener("click", this.redirectToLink);
};
private detachLinkListener = () => {
this.canvas?.removeEventListener("click", this.redirectToLink);
};
private handleCanvasPointerMove = (
event: React.PointerEvent<HTMLCanvasElement>,
@@ -2654,10 +2680,8 @@ class App extends React.Component<AppProps, AppState> {
) {
setCursor(this.canvas, CURSOR_TYPE.POINTER);
showHyperlinkTooltip(this.hitLinkElement, this.state);
this.attachLinkListener();
} else {
hideHyperlinkToolip();
this.detachLinkListener();
if (
hitElement &&
hitElement.link &&
@@ -2862,6 +2886,35 @@ class App extends React.Component<AppProps, AppState> {
}
};
private handleCanvasPointerUp = (
event: React.PointerEvent<HTMLCanvasElement>,
) => {
this.lastPointerUp = event;
const isTouchScreen = ["pen", "touch"].includes(event.pointerType);
if (isTouchScreen) {
const scenePointer = viewportCoordsToSceneCoords(
{ clientX: event.clientX, clientY: event.clientY },
this.state,
);
const hitElement = this.getElementAtPosition(
scenePointer.x,
scenePointer.y,
);
this.hitLinkElement = this.getElementLinkAtPosition(
scenePointer,
hitElement,
);
}
if (
this.hitLinkElement &&
!this.state.selectedElementIds[this.hitLinkElement.id]
) {
this.redirectToLink(event, isTouchScreen);
}
this.removePointer(event);
};
private maybeOpenContextMenuAfterPointerDownOnTouchDevices = (
event: React.PointerEvent<HTMLCanvasElement>,
): void => {
@@ -2887,6 +2940,12 @@ class App extends React.Component<AppProps, AppState> {
}
};
private resetContextMenuTimer = () => {
clearTimeout(touchTimeout);
touchTimeout = 0;
invalidateContextMenu = false;
};
private maybeCleanupAfterMissingPointerUp(
event: React.PointerEvent<HTMLCanvasElement>,
): void {
@@ -2921,7 +2980,7 @@ class App extends React.Component<AppProps, AppState> {
setCursor(this.canvas, CURSOR_TYPE.GRABBING);
let { clientX: lastX, clientY: lastY } = event;
const onPointerMove = withBatchedUpdates((event: PointerEvent) => {
const onPointerMove = withBatchedUpdatesThrottled((event: PointerEvent) => {
const deltaX = lastX - event.clientX;
const deltaY = lastY - event.clientY;
lastX = event.clientX;
@@ -2984,6 +3043,7 @@ class App extends React.Component<AppProps, AppState> {
window.removeEventListener(EVENT.POINTER_MOVE, onPointerMove);
window.removeEventListener(EVENT.POINTER_UP, teardown);
window.removeEventListener(EVENT.BLUR, teardown);
onPointerMove.flush();
}),
);
window.addEventListener(EVENT.BLUR, teardown);
@@ -3086,7 +3146,7 @@ class App extends React.Component<AppProps, AppState> {
isDraggingScrollBar = true;
pointerDownState.lastCoords.x = event.clientX;
pointerDownState.lastCoords.y = event.clientY;
const onPointerMove = withBatchedUpdates((event: PointerEvent) => {
const onPointerMove = withBatchedUpdatesThrottled((event: PointerEvent) => {
const target = event.target;
if (!(target instanceof HTMLElement)) {
return;
@@ -3105,6 +3165,7 @@ class App extends React.Component<AppProps, AppState> {
this.savePointer(event.clientX, event.clientY, "up");
window.removeEventListener(EVENT.POINTER_MOVE, onPointerMove);
window.removeEventListener(EVENT.POINTER_UP, onPointerUp);
onPointerMove.flush();
});
lastPointerUp = onPointerUp;
@@ -3213,10 +3274,12 @@ class App extends React.Component<AppProps, AppState> {
if (pointerDownState.hit.element) {
// Early return if pointer is hitting link icon
if (
isPointHittingLinkIcon(pointerDownState.hit.element, this.state, [
pointerDownState.origin.x,
pointerDownState.origin.y,
])
isPointHittingLinkIcon(
pointerDownState.hit.element,
this.state,
[pointerDownState.origin.x, pointerDownState.origin.y],
this.isMobile,
)
) {
return false;
}
@@ -3640,8 +3703,8 @@ class App extends React.Component<AppProps, AppState> {
private onPointerMoveFromPointerDownHandler(
pointerDownState: PointerDownState,
): (event: PointerEvent) => void {
return withBatchedUpdates((event: PointerEvent) => {
) {
return withBatchedUpdatesThrottled((event: PointerEvent) => {
// We need to initialize dragOffsetXY only after we've updated
// `state.selectedElementIds` on pointerDown. Doing it here in pointerMove
// event handler should hopefully ensure we're already working with
@@ -3852,14 +3915,20 @@ class App extends React.Component<AppProps, AppState> {
const dx = pointerCoords.x - draggingElement.x;
const dy = pointerCoords.y - draggingElement.y;
const pressures = draggingElement.simulatePressure
? draggingElement.pressures
: [...draggingElement.pressures, event.pressure];
const lastPoint = points.length > 0 && points[points.length - 1];
const discardPoint =
lastPoint && lastPoint[0] === dx && lastPoint[1] === dy;
mutateElement(draggingElement, {
points: [...points, [dx, dy]],
pressures,
});
if (!discardPoint) {
const pressures = draggingElement.simulatePressure
? draggingElement.pressures
: [...draggingElement.pressures, event.pressure];
mutateElement(draggingElement, {
points: [...points, [dx, dy]],
pressures,
});
}
} else if (isLinearElement(draggingElement)) {
pointerDownState.drag.hasOccurred = true;
const points = draggingElement.points;
@@ -4056,6 +4125,10 @@ class App extends React.Component<AppProps, AppState> {
lastPointerUp = null;
if (pointerDownState.eventListeners.onMove) {
pointerDownState.eventListeners.onMove.flush();
}
window.removeEventListener(
EVENT.POINTER_MOVE,
pointerDownState.eventListeners.onMove!,
@@ -4981,6 +5054,16 @@ class App extends React.Component<AppProps, AppState> {
) => {
event.preventDefault();
if (
(event.nativeEvent.pointerType === "touch" ||
(event.nativeEvent.pointerType === "pen" &&
// always allow if user uses a pen secondary button
event.button !== POINTER_BUTTON.SECONDARY)) &&
this.state.elementType !== "selection"
) {
return;
}
const { x, y } = viewportCoordsToSceneCoords(event, this.state);
const element = this.getElementAtPosition(x, y, { preferSelected: true });
+2 -1
View File
@@ -7,7 +7,7 @@ export const ButtonIconSelect = <T extends Object>({
onChange,
group,
}: {
options: { value: T; text: string; icon: JSX.Element }[];
options: { value: T; text: string; icon: JSX.Element; testId?: string }[];
value: T | null;
onChange: (value: T) => void;
group: string;
@@ -24,6 +24,7 @@ export const ButtonIconSelect = <T extends Object>({
name={group}
onChange={() => onChange(option.value)}
checked={value === option.value}
data-testid={option.testId}
/>
{option.icon}
</label>
+9 -2
View File
@@ -49,6 +49,7 @@
.ToolIcon__hidden {
box-shadow: none !important;
background-color: transparent !important;
pointer-events: none !important;
}
.ToolIcon.ToolIcon__lock {
@@ -86,8 +87,14 @@
.ToolIcon {
&:hover {
--icon-fill-color: var(--color-primary-chubb);
--keybinding-color: var(--color-primary-chubb);
--icon-fill-color: var(
--color-primary-contrast-offset,
var(--color-primary)
);
--keybinding-color: var(
--color-primary-contrast-offset,
var(--color-primary)
);
}
&:active {
--icon-fill-color: #{$oc-gray-9};
+3 -1
View File
@@ -24,7 +24,7 @@ export const POINTER_BUTTON = {
WHEEL: 1,
SECONDARY: 2,
TOUCH: -1,
};
} as const;
export enum EVENT {
COPY = "copy",
@@ -52,6 +52,8 @@ export enum EVENT {
HASHCHANGE = "hashchange",
VISIBILITY_CHANGE = "visibilitychange",
SCROLL = "scroll",
// custom events
EXCALIDRAW_LINK = "excalidraw-link",
}
export const ENV = {
-2
View File
@@ -38,7 +38,6 @@
--text-primary-color: #{$oc-gray-8};
--color-primary: #6965db;
--color-primary-chubb: #625ee0; // to offset Chubb illusion
--color-primary-darker: #5b57d1;
--color-primary-darkest: #4a47b1;
--color-primary-light: #e2e1fc;
@@ -85,7 +84,6 @@
--text-primary-color: #{$oc-gray-4};
--color-primary: #5650f0;
--color-primary-chubb: #726dff; // to offset Chubb illusion
--color-primary-darker: #4b46d8;
--color-primary-darkest: #3e39be;
--color-primary-light: #3f3d64;
+34 -10
View File
@@ -1,8 +1,9 @@
import { AppState, Point } from "../types";
import { AppState, ExcalidrawProps, Point } from "../types";
import {
getShortcutKey,
sceneCoordsToViewportCoords,
viewportCoordsToSceneCoords,
wrapEvent,
} from "../utils";
import { mutateElement } from "./mutateElement";
import { NonDeletedExcalidrawElement } from "./types";
@@ -48,10 +49,12 @@ export const Hyperlink = ({
element,
appState,
setAppState,
onLinkOpen,
}: {
element: NonDeletedExcalidrawElement;
appState: AppState;
setAppState: React.Component<any, AppState>["setState"];
onLinkOpen: ExcalidrawProps["onLinkOpen"];
}) => {
const linkVal = element.link || "";
@@ -119,7 +122,8 @@ export const Hyperlink = ({
if (
appState.draggingElement ||
appState.resizingElement ||
appState.isRotating
appState.isRotating ||
appState.openMenu
) {
return null;
}
@@ -159,6 +163,18 @@ export const Hyperlink = ({
"d-none": isEditing,
})}
target={isLocalLink(element.link) ? "_self" : "_blank"}
onClick={(event) => {
if (element.link && onLinkOpen) {
const customEvent = wrapEvent(
EVENT.EXCALIDRAW_LINK,
event.nativeEvent,
);
onLinkOpen(element, customEvent);
if (customEvent.defaultPrevented) {
event.preventDefault();
}
}
}}
rel="noopener noreferrer"
>
{element.link}
@@ -197,8 +213,9 @@ const getCoordsForPopover = (
element: NonDeletedExcalidrawElement,
appState: AppState,
) => {
const [x1, y1] = getElementAbsoluteCoords(element);
const { x: viewportX, y: viewportY } = sceneCoordsToViewportCoords(
{ sceneX: element.x + element.width / 2, sceneY: element.y },
{ sceneX: x1 + element.width / 2, sceneY: y1 },
appState,
);
const x = viewportX - appState.offsetLeft - CONTAINER_WIDTH / 2;
@@ -232,6 +249,7 @@ export const actionLink = register({
appState: {
...appState,
showHyperlinkPopup: "editor",
openMenu: null,
},
commitToHistory: true,
};
@@ -306,9 +324,16 @@ export const isPointHittingLinkIcon = (
element: NonDeletedExcalidrawElement,
appState: AppState,
[x, y]: Point,
isMobile: boolean,
) => {
const threshold = 4 / appState.zoom.value;
if (
!isMobile &&
appState.viewModeEnabled &&
isPointHittingElementBoundingBox(element, [x, y], threshold)
) {
return true;
}
const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
const [linkX, linkY, linkWidth, linkHeight] = getLinkHandleFromCoords(
@@ -321,7 +346,6 @@ export const isPointHittingLinkIcon = (
x < linkX + threshold + linkWidth &&
y > linkY - threshold &&
y < linkY + linkHeight + threshold;
return hitLink;
};
@@ -404,13 +428,13 @@ export const shouldHideLinkPopup = (
if (isPointHittingElementBoundingBox(element, [sceneX, sceneY], threshold)) {
return false;
}
const [x1, y1, x2] = getElementAbsoluteCoords(element);
// hit box to prevent hiding when hovered in the vertical area between element and popover
if (
sceneX >= element.x &&
sceneX <= element.x + element.width &&
sceneY <= element.y &&
sceneY >= element.y - SPACE_BOTTOM
sceneX >= x1 &&
sceneX <= x2 &&
sceneY >= y1 - SPACE_BOTTOM &&
sceneY <= y1
) {
return false;
}
+2 -2
View File
@@ -185,7 +185,7 @@ const getLinearElementAbsoluteCoords = (
maxY + element.y,
];
} else {
const shape = getShapeForElement(element) as Drawable[];
const shape = getShapeForElement(element)!;
// first element is always the curve
const ops = getCurvePathOps(shape[0]);
@@ -326,7 +326,7 @@ const getLinearElementRotatedBounds = (
return [minX, minY, maxX, maxY];
}
const shape = getShapeForElement(element) as Drawable[];
const shape = getShapeForElement(element)!;
// first element is always the curve
const ops = getCurvePathOps(shape[0]);
+22 -4
View File
@@ -24,6 +24,7 @@ import {
NonDeleted,
ExcalidrawFreeDrawElement,
ExcalidrawImageElement,
ExcalidrawLinearElement,
} from "./types";
import { getElementAbsoluteCoords, getCurvePathOps, Bounds } from "./bounds";
@@ -361,6 +362,14 @@ const hitTestFreeDrawElement = (
B = element.points[i + 1];
}
const shape = getShapeForElement(element);
// for filled freedraw shapes, support
// selecting from inside
if (shape && shape.sets.length) {
return hitTestRoughShape(shape, x, y, threshold);
}
return false;
};
@@ -383,7 +392,11 @@ const hitTestLinear = (args: HitTestArgs): boolean => {
}
const [relX, relY] = GAPoint.toTuple(point);
const shape = getShapeForElement(element) as Drawable[];
const shape = getShapeForElement(element as ExcalidrawLinearElement);
if (!shape) {
return false;
}
if (args.check === isInsideCheck) {
const hit = shape.some((subshape) =>
@@ -821,7 +834,7 @@ const hitTestCurveInside = (
sharpness: ExcalidrawElement["strokeSharpness"],
) => {
const ops = getCurvePathOps(drawable);
const points: Point[] = [];
const points: Mutable<Point>[] = [];
let odd = false; // select one line out of double lines
for (const operation of ops) {
if (operation.op === "move") {
@@ -835,13 +848,17 @@ const hitTestCurveInside = (
points.push([operation.data[2], operation.data[3]]);
points.push([operation.data[4], operation.data[5]]);
}
} else if (operation.op === "lineTo") {
if (odd) {
points.push([operation.data[0], operation.data[1]]);
}
}
}
if (points.length >= 4) {
if (sharpness === "sharp") {
return isPointInPolygon(points, x, y);
}
const polygonPoints = pointsOnBezierCurves(points as any, 10, 5);
const polygonPoints = pointsOnBezierCurves(points, 10, 5);
return isPointInPolygon(polygonPoints, x, y);
}
return false;
@@ -896,9 +913,10 @@ const hitTestRoughShape = (
// position of the previous operation
return retVal;
} else if (op === "lineTo") {
// TODO: Implement this
return hitTestCurveInside(drawable, x, y, "sharp");
} else if (op === "qcurveTo") {
// TODO: Implement this
console.warn("qcurveTo is not implemented yet");
}
return false;
+1 -1
View File
@@ -86,7 +86,7 @@ export const textWysiwyg = ({
updatedElement: ExcalidrawTextElement,
editable: HTMLTextAreaElement,
) => {
const currentFont = editable.style.fontFamily.replaceAll('"', "");
const currentFont = editable.style.fontFamily.replace(/"/g, "");
if (
getFontFamilyString({ fontFamily: updatedElement.fontFamily }) !==
currentFont
+5
View File
@@ -1,4 +1,9 @@
.excalidraw {
--color-primary-contrast-offset: #625ee0; // to offset Chubb illusion
&.theme--dark {
--color-primary-contrast-offset: #726dff; // to offset Chubb illusion
}
.layer-ui__wrapper__footer-center {
display: flex;
justify-content: space-between;
+1
View File
@@ -1,5 +1,6 @@
export const isDarwin = /Mac|iPod|iPhone|iPad/.test(window.navigator.platform);
export const isWindows = /^Win/.test(window.navigator.platform);
export const isAndroid = /\b(android)\b/i.test(navigator.userAgent);
export const CODES = {
EQUAL: "Equal",
+14 -6
View File
@@ -103,8 +103,14 @@
"toggleTheme": "غير النمط",
"personalLib": "المكتبة الشخصية",
"excalidrawLib": "مكتبتنا",
"decreaseFontSize": "",
"increaseFontSize": ""
"decreaseFontSize": "تصغير حجم الخط",
"increaseFontSize": "تكبير حجم الخط",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "إعادة تعيين اللوحة",
@@ -173,7 +179,7 @@
"imageInsertError": "تعذر إدراج الصورة. حاول مرة أخرى لاحقاً...",
"fileTooBig": "الملف كبير جداً. الحد الأقصى المسموح به للحجم هو {{maxSize}}.",
"svgImageInsertError": "تعذر إدراج صورة SVG. يبدو أن ترميز SVG غير صحيح.",
"invalidSVGString": ""
"invalidSVGString": "SVG غير صالح."
},
"toolBar": {
"selection": "تحديد",
@@ -186,7 +192,9 @@
"freedraw": "رسم",
"text": "نص",
"library": "مكتبة",
"lock": "الحفاظ على أداة التحديد نشطة بعد الرسم"
"lock": "الحفاظ على أداة التحديد نشطة بعد الرسم",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "إجراءات اللوحة",
@@ -194,7 +202,7 @@
"shapes": "الأشكال"
},
"hints": {
"canvasPanning": "",
"canvasPanning": "لتحريك لوحة الرسم ، استمر في الضغط على عجلة الماوس أو مفتاح المسافة أثناء السحب",
"linearElement": "انقر لبدء نقاط متعددة، اسحب لخط واحد",
"freeDraw": "انقر واسحب، افرج عند الانتهاء",
"text": "نصيحة: يمكنك أيضًا إضافة نص بالنقر المزدوج في أي مكان بأداة الاختيار",
@@ -301,7 +309,7 @@
"website": ""
},
"errors": {
"required": "",
"required": "مطلوب",
"website": ""
},
"noteDescription": {
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "",
"excalidrawLib": "",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "Нулиране на платно",
@@ -186,7 +192,9 @@
"freedraw": "Рисуване",
"text": "Текст",
"library": "Библиотека",
"lock": "Поддържайте избрания инструмент активен след рисуване"
"lock": "Поддържайте избрания инструмент активен след рисуване",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "Действия по платното",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "",
"excalidrawLib": "",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "",
@@ -186,7 +192,9 @@
"freedraw": "",
"text": "",
"library": "",
"lock": ""
"lock": "",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "Biblioteca personal",
"excalidrawLib": "Biblioteca d'Excalidraw",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "Neteja el llenç",
@@ -186,7 +192,9 @@
"freedraw": "Dibuix",
"text": "Text",
"library": "Biblioteca",
"lock": "Mantenir activa l'eina seleccionada desprès de dibuixar"
"lock": "Mantenir activa l'eina seleccionada desprès de dibuixar",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "Accions del llenç",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "",
"excalidrawLib": "",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "",
@@ -186,7 +192,9 @@
"freedraw": "Kreslení",
"text": "Text",
"library": "",
"lock": ""
"lock": "",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "",
"excalidrawLib": "",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "",
@@ -186,7 +192,9 @@
"freedraw": "",
"text": "",
"library": "",
"lock": ""
"lock": "",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "",
+12 -4
View File
@@ -100,11 +100,17 @@
"share": "Teilen",
"showStroke": "Auswahl für Strichfarbe anzeigen",
"showBackground": "Hintergrundfarbe auswählen",
"toggleTheme": "Design umschalten",
"toggleTheme": "Thema umschalten",
"personalLib": "Persönliche Bibliothek",
"excalidrawLib": "Excalidraw-Bibliothek",
"decreaseFontSize": "Schrift verkleinern",
"increaseFontSize": "Schrift vergrößern"
"increaseFontSize": "Schrift vergrößern",
"unbindText": "Text lösen",
"link": {
"edit": "Link bearbeiten",
"create": "Link erstellen",
"label": "Link"
}
},
"buttons": {
"clearReset": "Zeichenfläche löschen & Hintergrundfarbe zurücksetzen",
@@ -186,7 +192,9 @@
"freedraw": "Zeichnen",
"text": "Text",
"library": "Bibliothek",
"lock": "Ausgewähltes Werkzeug nach Zeichnen aktiv lassen"
"lock": "Ausgewähltes Werkzeug nach Zeichnen aktiv lassen",
"penMode": "",
"link": "Link für ausgewählte Form hinzufügen / aktualisieren"
},
"headings": {
"canvasActions": "Aktionen für Zeichenfläche",
@@ -247,7 +255,7 @@
"exportDialog": {
"disk_title": "Auf Festplatte speichern",
"disk_details": "Exportiere die Zeichnungsdaten in eine Datei, die Du später importieren kannst.",
"disk_button": "In Datei speichern",
"disk_button": "Als Datei speichern",
"link_title": "Teilbarer Link",
"link_details": "Als schreibgeschützten Link exportieren.",
"link_button": "Als Link exportieren",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "Προσωπική Βιβλιοθήκη",
"excalidrawLib": "Βιβλιοθήκη Excalidraw",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "Επαναφορά του καμβά",
@@ -186,7 +192,9 @@
"freedraw": "Σχεδίαση",
"text": "Κείμενο",
"library": "Βιβλιοθήκη",
"lock": "Κράτησε επιλεγμένο το εργαλείο μετά το σχέδιο"
"lock": "Κράτησε επιλεγμένο το εργαλείο μετά το σχέδιο",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "Ενέργειες καμβά",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "",
"excalidrawLib": "",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "Limpiar lienzo y reiniciar el color de fondo",
@@ -186,7 +192,9 @@
"freedraw": "Dibujar",
"text": "Texto",
"library": "Biblioteca",
"lock": "Mantener la herramienta seleccionada activa después de dibujar"
"lock": "Mantener la herramienta seleccionada activa después de dibujar",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "Acciones del lienzo",
+57 -49
View File
@@ -103,8 +103,14 @@
"toggleTheme": "Aldatu gaia",
"personalLib": "Liburutegi pertsonala",
"excalidrawLib": "Excalidraw liburutegia",
"decreaseFontSize": "",
"increaseFontSize": ""
"decreaseFontSize": "Txikitu letra tamaina",
"increaseFontSize": "Handitu letra tamaina",
"unbindText": "Askatu testua",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "Garbitu oihala",
@@ -156,61 +162,63 @@
"decryptFailed": "Ezin izan da deszifratu.",
"uploadedSecurly": "Kargatzea muturretik muturrerako zifratze bidez ziurtatu da, hau da, Excalidraw zerbitzariak eta hirugarrenek ezin dutela edukia irakurri.",
"loadSceneOverridePrompt": "Kanpoko marrazkia kargatzeak lehendik duzun edukia ordezkatuko du. Jarraitu nahi duzu?",
"collabStopOverridePrompt": "",
"errorLoadingLibrary": "",
"errorAddingToLibrary": "",
"errorRemovingFromLibrary": "",
"confirmAddLibrary": "",
"imageDoesNotContainScene": "",
"cannotRestoreFromImage": "",
"invalidSceneUrl": "",
"resetLibrary": "",
"removeItemsFromsLibrary": "",
"invalidEncryptionKey": ""
"collabStopOverridePrompt": "Saioa gelditzeak lokalean gordetako zure aurreko marrazkia gainidatziko du. Ziur zaude?\n\n(Zure marrazki lokala mantendu nahi baduzu, itxi arakatzailearen fitxa.)",
"errorLoadingLibrary": "Errore bat gertatu da hirugarrenen liburutegia kargatzean.",
"errorAddingToLibrary": "Ezin izan da elementua liburutegian gehitu",
"errorRemovingFromLibrary": "Ezin izan da elementua liburutegitik kendu",
"confirmAddLibrary": "Honek {{numShapes}} forma gehituko ditu zure liburutegian. Ziur zaude?",
"imageDoesNotContainScene": "Irudi honek ez dirudi eszena daturik duenik. Eszena kapsulatzea gaitu al duzu esportazioan?",
"cannotRestoreFromImage": "Ezin izan da eszena leheneratu irudi fitxategi honetatik",
"invalidSceneUrl": "Ezin izan da eszena inportatu emandako URLtik. Gaizki eratuta dago edo ez du baliozko Excalidraw JSON daturik.",
"resetLibrary": "Honek zure liburutegia garbituko du. Ziur zaude?",
"removeItemsFromsLibrary": "Liburutegitik {{count}} elementu ezabatu?",
"invalidEncryptionKey": "Enkriptazio-gakoak 22 karaktere izan behar ditu. Zuzeneko lankidetza desgaituta dago."
},
"errors": {
"unsupportedFileType": "",
"imageInsertError": "",
"fileTooBig": "",
"svgImageInsertError": "",
"invalidSVGString": ""
"unsupportedFileType": "Onartu gabeko fitxategi mota.",
"imageInsertError": "Ezin izan da irudia txertatu. Saiatu berriro geroago...",
"fileTooBig": "Fitxategia handiegia da. Onartutako gehienezko tamaina {{maxSize}} da.",
"svgImageInsertError": "Ezin izan da SVG irudia txertatu. SVG markak baliogabea dirudi.",
"invalidSVGString": "SVG baliogabea."
},
"toolBar": {
"selection": "",
"image": "",
"rectangle": "",
"diamond": "",
"ellipse": "",
"arrow": "",
"line": "",
"freedraw": "",
"text": "",
"library": "",
"lock": ""
"selection": "Hautapena",
"image": "Txertatu irudia",
"rectangle": "Laukizuzena",
"diamond": "Diamantea",
"ellipse": "Elipsea",
"arrow": "Gezia",
"line": "Lerroa",
"freedraw": "Marraztu",
"text": "Testua",
"library": "Liburutegia",
"lock": "Mantendu aktibo hautatutako tresna marraztu ondoren",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "",
"selectedShapeActions": "",
"shapes": ""
"canvasActions": "Canvas ekintzak",
"selectedShapeActions": "Hautatutako formaren ekintzak",
"shapes": "Formak"
},
"hints": {
"canvasPanning": "",
"linearElement": "",
"freeDraw": "",
"text": "",
"text_selected": "",
"text_editing": "",
"linearElementMulti": "",
"lockAngle": "",
"resize": "",
"resizeImage": "",
"rotate": "",
"lineEditor_info": "",
"lineEditor_pointSelected": "",
"lineEditor_nothingSelected": "",
"placeImage": "",
"publishLibrary": "",
"bindTextToElement": "",
"canvasPanning": "Oihala mugitzeko, sakatu saguaren gurpila edo zuriune-barra arrastatzean",
"linearElement": "Egin klik hainbat puntu hasteko, arrastatu lerro bakarrerako",
"freeDraw": "Egin klik eta arrastatu, askatu amaitutakoan",
"text": "Aholkua: testua gehitu dezakezu edozein lekutan klik bikoitza eginez hautapen tresnarekin",
"text_selected": "Egin klik bikoitza edo sakatu SARTU testua editatzeko",
"text_editing": "Sakatu Esc edo Ctrl+SARTU editatzen amaitzeko",
"linearElementMulti": "Egin klik azken puntuan edo sakatu Esc edo Sartu amaitzeko",
"lockAngle": "SHIFT sakatuta angelua mantendu dezakezu",
"resize": "Proportzioak mantendu ditzakezu SHIFT sakatuta tamaina aldatzen duzun bitartean.\nsakatu ALT erditik tamaina aldatzeko",
"resizeImage": "Tamaina libreki alda dezakezu SHIFT sakatuta,\nsakatu ALT erditik tamaina aldatzeko",
"rotate": "Angeluak mantendu ditzakezu SHIFT sakatuta biratzen duzun bitartean",
"lineEditor_info": "Egin klik bikoitza edo sakatu Sartu puntuak editatzeko",
"lineEditor_pointSelected": "Sakatu Ezabatu puntuak kentzeko,\nKtrl+D bikoizteko, edo arrastatu mugitzeko",
"lineEditor_nothingSelected": "Hautatu editatzeko puntu bat (SHIFT sakatuta anitz hautatzeko),\nedo eduki Alt sakatuta eta egin klik puntu berriak gehitzeko",
"placeImage": "Egin klik irudia kokatzeko, edo egin klik eta arrastatu bere tamaina eskuz ezartzeko",
"publishLibrary": "Argitaratu zure liburutegia",
"bindTextToElement": "Sakatu Sartu testua gehitzeko",
"deepBoxSelect": ""
},
"canvasError": {
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "",
"excalidrawLib": "",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "پاکسازی بوم نقاشی",
@@ -186,7 +192,9 @@
"freedraw": "کشیدن",
"text": "متن",
"library": "کتابخانه",
"lock": "ابزار انتخاب شده را بعد از کشیدن نگه دار"
"lock": "ابزار انتخاب شده را بعد از کشیدن نگه دار",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "عملیات روی بوم",
+14 -6
View File
@@ -103,8 +103,14 @@
"toggleTheme": "Vaihda teema",
"personalLib": "Oma kirjasto",
"excalidrawLib": "Excalidraw kirjasto",
"decreaseFontSize": "",
"increaseFontSize": ""
"decreaseFontSize": "Pienennä kirjasinkokoa",
"increaseFontSize": "Kasvata kirjasinkokoa",
"unbindText": "",
"link": {
"edit": "Muokkaa linkkiä",
"create": "Luo linkki",
"label": "Linkki"
}
},
"buttons": {
"clearReset": "Tyhjennä piirtoalue",
@@ -186,7 +192,9 @@
"freedraw": "Piirrä",
"text": "Teksti",
"library": "Kirjasto",
"lock": "Pidä valittu työkalu aktiivisena piirron jälkeen"
"lock": "Pidä valittu työkalu aktiivisena piirron jälkeen",
"penMode": "Estä nipistyszoomaus ja vastaanota ainoastaan kynällä piirretty",
"link": "Lisää/päivitä linkki valitulle muodolle"
},
"headings": {
"canvasActions": "Piirtoalueen toiminnot",
@@ -206,11 +214,11 @@
"resizeImage": "Voit muuttaa kokoa vapaasti pitämällä SHIFTiä pohjassa, pidä ALT pohjassa muuttaaksesi kokoa keskipisteen ympäri",
"rotate": "Voit rajoittaa kulman pitämällä SHIFT pohjassa pyörittäessäsi",
"lineEditor_info": "Kaksoisnapauta tai paina Enter muokataksesi pisteitä",
"lineEditor_pointSelected": "",
"lineEditor_nothingSelected": "",
"lineEditor_pointSelected": "Poista piste(et) painamalla delete, monista painamalla CtrlOrCmd+D, tai liikuta raahaamalla",
"lineEditor_nothingSelected": "Valitse muokattava piste (monivalinta pitämällä SHIFT pohjassa), tai paina Alt ja klikkaa lisätäksesi uusia pisteitä",
"placeImage": "Klikkaa asettaaksesi kuvan, tai klikkaa ja raahaa asettaaksesi sen koon manuaalisesti",
"publishLibrary": "Julkaise oma kirjasto",
"bindTextToElement": "",
"bindTextToElement": "Lisää tekstiä painamalla enter",
"deepBoxSelect": ""
},
"canvasError": {
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "Bibliothèque personnelle",
"excalidrawLib": "Bibliothèque Excalidraw",
"decreaseFontSize": "Réduire la taille de police",
"increaseFontSize": "Augmenter la taille de police"
"increaseFontSize": "Augmenter la taille de police",
"unbindText": "Délier le texte",
"link": {
"edit": "Modifier le lien",
"create": "Créer un lien",
"label": "Lien"
}
},
"buttons": {
"clearReset": "Réinitialiser le canevas",
@@ -186,7 +192,9 @@
"freedraw": "Dessiner",
"text": "Texte",
"library": "Bibliothèque",
"lock": "Garder l'outil sélectionné actif après le dessin"
"lock": "Garder l'outil sélectionné actif après le dessin",
"penMode": "Empêcher le zoom tactile et accepter la saisie libre uniquement à partir du stylet",
"link": "Ajouter/mettre à jour le lien pour une forme sélectionnée"
},
"headings": {
"canvasActions": "Actions du canevas",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "",
"excalidrawLib": "",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "אפס את הלוח",
@@ -186,7 +192,9 @@
"freedraw": "צייר",
"text": "טקסט",
"library": "ספריה",
"lock": "השאר את הכלי הנבחר פעיל גם לאחר סיום הציור"
"lock": "השאר את הכלי הנבחר פעיל גם לאחר סיום הציור",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "פעולות הלוח",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "",
"excalidrawLib": "",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "कैनवास रीसेट करें",
@@ -186,7 +192,9 @@
"freedraw": "",
"text": "पाठ",
"library": "लाइब्रेरी",
"lock": "ड्राइंग के बाद चयनित टूल को सक्रिय रखें"
"lock": "ड्राइंग के बाद चयनित टूल को सक्रिय रखें",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "कैनवास क्रिया",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "",
"excalidrawLib": "",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "Vászon törlése",
@@ -186,7 +192,9 @@
"freedraw": "",
"text": "Szöveg",
"library": "Könyvtár",
"lock": "Rajzolás után az aktív eszközt tartsa kijelölve"
"lock": "Rajzolás után az aktív eszközt tartsa kijelölve",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "Vászon műveletek",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "Pustaka Pribadi",
"excalidrawLib": "Pustaka Excalidraw",
"decreaseFontSize": "Kecilkan ukuran font",
"increaseFontSize": "Besarkan ukuran font"
"increaseFontSize": "Besarkan ukuran font",
"unbindText": "Lepas teks",
"link": {
"edit": "Edit tautan",
"create": "Buat tautan",
"label": "Tautan"
}
},
"buttons": {
"clearReset": "Setel Ulang Kanvas",
@@ -186,7 +192,9 @@
"freedraw": "Gambar",
"text": "Teks",
"library": "Pustaka",
"lock": "Biarkan alat yang dipilih aktif setelah menggambar"
"lock": "Biarkan alat yang dipilih aktif setelah menggambar",
"penMode": "Cegah jepit perbesar dan terima hanya input freedraw dari pena",
"link": "Tambah/Perbarui tautan untuk bentuk yang dipilih"
},
"headings": {
"canvasActions": "Opsi Kanvas",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "Libreria Personale",
"excalidrawLib": "Libreria di Excalidraw",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "Svuota la tela",
@@ -186,7 +192,9 @@
"freedraw": "Disegno",
"text": "Testo",
"library": "Libreria",
"lock": "Mantieni lo strumento selezionato attivo dopo aver disegnato"
"lock": "Mantieni lo strumento selezionato attivo dopo aver disegnato",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "Azioni sulla Tela",
+11 -3
View File
@@ -103,8 +103,14 @@
"toggleTheme": "テーマの切り替え",
"personalLib": "個人ライブラリ",
"excalidrawLib": "Excalidrawライブラリ",
"decreaseFontSize": "",
"increaseFontSize": ""
"decreaseFontSize": "フォントサイズを縮小",
"increaseFontSize": "フォントサイズを拡大",
"unbindText": "",
"link": {
"edit": "リンクを編集",
"create": "リンクを作成",
"label": "リンク"
}
},
"buttons": {
"clearReset": "キャンバスのリセット",
@@ -186,7 +192,9 @@
"freedraw": "描画",
"text": "テキスト",
"library": "ライブラリ",
"lock": "描画後も使用中のツールを選択したままにする"
"lock": "描画後も使用中のツールを選択したままにする",
"penMode": "ピンチとズームを抑止し、ペンからのみ自由な入力を受け付けます",
"link": ""
},
"headings": {
"canvasActions": "キャンバス操作",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "Tamkarḍit tudmawant",
"excalidrawLib": "Tamkarḍit n Excalidraw",
"decreaseFontSize": "Senqes tiddi n tsefsit",
"increaseFontSize": "Sali tiddi n tsefsit"
"increaseFontSize": "Sali tiddi n tsefsit",
"unbindText": "",
"link": {
"edit": "Ẓreg aseɣwen",
"create": "Snulfu-d aseɣwen",
"label": "Aseɣwen"
}
},
"buttons": {
"clearReset": "Ales awennez n teɣzut n usuneɣ",
@@ -186,7 +192,9 @@
"freedraw": "Suneɣ",
"text": "Aḍris",
"library": "Tamkarḍit",
"lock": "Eǧǧ afecku n tefrayt yermed mbaɛd asuneɣ"
"lock": "Eǧǧ afecku n tefrayt yermed mbaɛd asuneɣ",
"penMode": "",
"link": "Rnu/leqqem aseɣwen i talɣa yettwafernen"
},
"headings": {
"canvasActions": "Tigawin n teɣzut n usuneɣ",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "",
"excalidrawLib": "",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "",
@@ -186,7 +192,9 @@
"freedraw": "",
"text": "Мәтін",
"library": "",
"lock": ""
"lock": "",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "",
+68 -60
View File
@@ -35,11 +35,11 @@
"arrowhead_arrow": "화살표",
"arrowhead_bar": "막대",
"arrowhead_dot": "점",
"arrowhead_triangle": "",
"arrowhead_triangle": "삼각형",
"fontSize": "글자 크기",
"fontFamily": "글꼴",
"onlySelected": "선택한 항목만",
"withBackground": "",
"withBackground": "배경",
"exportEmbedScene": "",
"exportEmbedScene_details": "화면 정보가 내보내는 PNG/SVG 파일에 저장되어 이후에 파일에서 화면을 복구할 수 있습니다. 파일 크기가 증가합니다.",
"addWatermark": "\"Made with Excalidraw\" 추가",
@@ -62,14 +62,14 @@
"architect": "건축가",
"artist": "예술가",
"cartoonist": "만화가",
"fileTitle": "",
"fileTitle": "파일 이름",
"colorPicker": "색상 선택기",
"canvasBackground": "캔버스 배경",
"drawingCanvas": "캔버스 그리기",
"layers": "레이어",
"actions": "동작",
"language": "언어",
"liveCollaboration": "",
"liveCollaboration": "라이브 협력",
"duplicateSelection": "복제",
"untitled": "제목 없음",
"name": "이름",
@@ -78,7 +78,7 @@
"group": "그룹 생성",
"ungroup": "그룹 해제",
"collaborators": "공동 작업자",
"showGrid": "",
"showGrid": "그리드 보기",
"addToLibrary": "라이브러리에 추가",
"removeFromLibrary": "라이브러리에서 제거",
"libraryLoadingMessage": "라이브러리 불러오는 중…",
@@ -93,30 +93,36 @@
"centerHorizontally": "수평으로 중앙 정렬",
"distributeHorizontally": "수평으로 분배",
"distributeVertically": "수직으로 분배",
"flipHorizontal": "",
"flipVertical": "",
"flipHorizontal": "좌우반전",
"flipVertical": "상하반전",
"viewMode": "보기 모드",
"toggleExportColorScheme": "",
"share": "",
"share": "공유",
"showStroke": "",
"showBackground": "",
"toggleTheme": "",
"personalLib": "",
"excalidrawLib": "",
"decreaseFontSize": "",
"increaseFontSize": ""
"personalLib": "개인 라이브러리",
"excalidrawLib": "Excalidraw 라이브러리",
"decreaseFontSize": "폰트 사이즈 줄이기",
"increaseFontSize": "폰트 사이즈 키우기",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "캔버스 초기화",
"exportJSON": "",
"exportImage": "",
"exportJSON": "파일로 익스포트",
"exportImage": "이미지로 저장",
"export": "내보내기",
"exportToPng": "PNG로 내보내기",
"exportToSvg": "SVG로 내보내기",
"copyToClipboard": "클립보드로 복사",
"copyPngToClipboard": "클립보드로 PNG 이미지 복사",
"scale": "크기",
"save": "",
"save": "현재 파일에 저장",
"saveAs": "다른 이름으로 저장",
"load": "불러오기",
"getShareableLink": "공유 가능한 링크 생성",
@@ -131,19 +137,19 @@
"edit": "수정",
"undo": "실행 취소",
"redo": "다시 실행",
"resetLibrary": "",
"resetLibrary": "라이브러리 리셋",
"createNewRoom": "방 만들기",
"fullScreen": "전체화면",
"darkMode": "다크 모드",
"lightMode": "밝은 모드",
"zenMode": "젠 모드",
"exitZenMode": "젠 모드 종료하기",
"cancel": "",
"clear": "",
"remove": "",
"publishLibrary": "",
"submit": "",
"confirm": ""
"cancel": "취소",
"clear": "지우기",
"remove": "삭제",
"publishLibrary": "게시하기",
"submit": "제출",
"confirm": "확인"
},
"alerts": {
"clearReset": "모든 작업 내용이 초기화됩니다. 계속하시겠습니까?",
@@ -158,8 +164,8 @@
"loadSceneOverridePrompt": "외부 파일을 불러 오면 기존 콘텐츠가 대체됩니다. 계속 진행할까요?",
"collabStopOverridePrompt": "협업 세션을 종료하면 로컬 저장소에 있는 그림이 협업 세션의 그림으로 대체됩니다. 진행하겠습니까?\n\n(로컬 저장소에 있는 그림을 유지하려면 현재 브라우저 탭을 닫아주세요.)",
"errorLoadingLibrary": "외부 라이브러리를 불러오는 중에 문제가 발생했습니다.",
"errorAddingToLibrary": "",
"errorRemovingFromLibrary": "",
"errorAddingToLibrary": "아이템을 라이브러리에 추가 할수 없습니다",
"errorRemovingFromLibrary": "라이브러리에서 아이템을 삭제할수 없습니다",
"confirmAddLibrary": "{{numShapes}}개의 모양이 라이브러리에 추가됩니다. 계속하시겠어요?",
"imageDoesNotContainScene": "",
"cannotRestoreFromImage": "이미지 파일에서 화면을 복구할 수 없었습니다",
@@ -169,24 +175,26 @@
"invalidEncryptionKey": ""
},
"errors": {
"unsupportedFileType": "",
"imageInsertError": "",
"unsupportedFileType": "지원하지 않는 파일 형식 입니다.",
"imageInsertError": "이미지를 삽입할 수 없습니다. 나중에 다시 시도 하십시오",
"fileTooBig": "",
"svgImageInsertError": "",
"invalidSVGString": ""
},
"toolBar": {
"selection": "선택",
"image": "",
"image": "이미지 삽입",
"rectangle": "사각형",
"diamond": "다이아몬드",
"ellipse": "타원",
"arrow": "화살표",
"line": "선",
"freedraw": "",
"freedraw": "그리기",
"text": "텍스트",
"library": "라이브러리",
"lock": "선택된 도구 유지하기"
"lock": "선택된 도구 유지하기",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "캔버스 동작",
@@ -245,14 +253,14 @@
"title": "오류"
},
"exportDialog": {
"disk_title": "",
"disk_title": "디스크에 저장",
"disk_details": "",
"disk_button": "",
"link_title": "",
"disk_button": "파일로 저장",
"link_title": "공유 가능한 링크 생성",
"link_details": "",
"link_button": "",
"link_button": "링크로 내보내기",
"excalidrawplus_description": "",
"excalidrawplus_button": "",
"excalidrawplus_button": "내보내기",
"excalidrawplus_exportError": ""
},
"helpDialog": {
@@ -263,35 +271,35 @@
"curvedArrow": "곡선 화살표",
"curvedLine": "곡선",
"documentation": "설명서",
"doubleClick": "",
"doubleClick": "더블 클릭",
"drag": "드래그",
"editor": "에디터",
"editSelectedShape": "",
"editSelectedShape": "선택한 도형 편집하기(텍스트/화살표/라인)",
"github": "문제 제보하기",
"howto": "가이드 참고하기",
"or": "또는",
"preventBinding": "화살표가 붙지 않게 하기",
"shapes": "도형",
"shortcuts": "키보드 단축키",
"textFinish": "",
"textNewLine": "",
"textFinish": "편집 완료 (텍스트 에디터)",
"textNewLine": "줄바꿈(텍스트 에디터)",
"title": "도움말",
"view": "보기",
"zoomToFit": "모든 요소가 보이도록 확대/축소",
"zoomToSelection": "선택 영역으로 확대/축소"
},
"clearCanvasDialog": {
"title": ""
"title": "캔버스 지우기"
},
"publishDialog": {
"title": "",
"itemName": "",
"authorName": "",
"githubUsername": "",
"twitterUsername": "",
"libraryName": "",
"itemName": "아이템 이름",
"authorName": "저자명",
"githubUsername": "깃허브 사용자이름",
"twitterUsername": "트위터 사용자이름",
"libraryName": "라이브러리 이름",
"libraryDesc": "",
"website": "",
"website": "웹사이트",
"placeholder": {
"authorName": "",
"libraryName": "",
@@ -301,7 +309,7 @@
"website": ""
},
"errors": {
"required": "",
"required": "필수사항",
"website": ""
},
"noteDescription": {
@@ -311,12 +319,12 @@
},
"noteGuidelines": {
"pre": "",
"link": "",
"link": "가이드라인",
"post": ""
},
"noteLicense": {
"pre": "",
"link": "",
"link": "MIT 라이선스, ",
"post": ""
},
"noteItems": "",
@@ -325,10 +333,10 @@
"publishSuccessDialog": {
"title": "",
"content": "",
"link": ""
"link": "여기"
},
"confirmDialog": {
"resetLibrary": "",
"resetLibrary": "라이브러리 리셋",
"removeItemsFromLib": ""
},
"encrypted": {
@@ -351,21 +359,21 @@
"width": "너비"
},
"toast": {
"addedToLibrary": "",
"addedToLibrary": "라이브러리에 추가되었습니다",
"copyStyles": "스타일 복사.",
"copyToClipboard": "클립보드로 복사.",
"copyToClipboardAsPng": "",
"fileSaved": "",
"fileSavedToFilename": "",
"canvas": "",
"selection": ""
"fileSaved": "파일이 저장되었습니다.",
"fileSavedToFilename": "{filename} 로 저장되었습니다",
"canvas": "캔버스",
"selection": "선택"
},
"colors": {
"ffffff": "",
"f8f9fa": "",
"f1f3f5": "",
"fff5f5": "",
"fff0f6": "",
"ffffff": "화이트",
"f8f9fa": "그레이 0",
"f1f3f5": "그레이 1",
"fff5f5": "레드 0",
"fff0f6": "핑크 0",
"f8f0fc": "",
"f3f0ff": "",
"edf2ff": "",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "Asmeninė biblioteka",
"excalidrawLib": "Exaclidraw biblioteka",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "",
@@ -186,7 +192,9 @@
"freedraw": "Piešti",
"text": "Tekstas",
"library": "Biblioteka",
"lock": ""
"lock": "",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "",
+13 -5
View File
@@ -104,7 +104,13 @@
"personalLib": "Personīgā bibliotēka",
"excalidrawLib": "Excalidraw bibliotēka",
"decreaseFontSize": "Samazināt fonta izmēru",
"increaseFontSize": "Palielināt fonta izmēru"
"increaseFontSize": "Palielināt fonta izmēru",
"unbindText": "Atdalīt tekstu",
"link": {
"edit": "Rediģēt saiti",
"create": "Izveidot saiti",
"label": "Saite"
}
},
"buttons": {
"clearReset": "Atiestatīt tāfeli",
@@ -151,7 +157,7 @@
"couldNotCreateShareableLinkTooBig": "Nevarēja izveidot kopīgojamo saiti aina ir par lielu",
"couldNotLoadInvalidFile": "Nevarēja ielādēt nederīgu datni",
"importBackendFailed": "Ielāde no krātuves neizdevās.",
"cannotExportEmptyCanvas": "Nevar eksportēt tukšu zīmējumu.",
"cannotExportEmptyCanvas": "Nevar eksportēt tukšu tāfeli.",
"couldNotCopyToClipboard": "Neizdevās kopēt starpliktuvē. Mēģiniet vēlreiz, izmantojot pārlūku Chrome.",
"decryptFailed": "Nevarēja atšifrēt datus.",
"uploadedSecurly": "Augšuplāde nodrošināta ar šifrēšanu no gala līdz galam, kas nozīmē, ka Excalidraw serveri un trešās puses nevar lasīt saturu.",
@@ -186,7 +192,9 @@
"freedraw": "Zīmēt",
"text": "Teksts",
"library": "Bibliotēka",
"lock": "Paturēt izvēlēto rīku pēc darbības"
"lock": "Paturēt izvēlēto rīku pēc darbības",
"penMode": "Lietojot pildspalvu, bloķēt tuvināšanu un atļaut tikai zīmēšanu",
"link": "Pievienot/rediģēt atlasītās figūras saiti"
},
"headings": {
"canvasActions": "Tāfeles darbības",
@@ -266,12 +274,12 @@
"doubleClick": "dubultklikšķis",
"drag": "vilkt",
"editor": "Redaktors",
"editSelectedShape": "Rediģēt atlasīto formu (tekstu/bultu/līniju)",
"editSelectedShape": "Rediģēt atlasīto figūru (tekstu/bultu/līniju)",
"github": "Sastapāt kļūdu? Ziņot",
"howto": "Sekojiet mūsu instrukcijām",
"or": "vai",
"preventBinding": "Novērst bultu piesaistīšanos",
"shapes": "Formas",
"shapes": "Figūras",
"shortcuts": "Tastatūras saīsnes",
"textFinish": "Pabeigt rediģēšanu (teksta redaktorā)",
"textNewLine": "Nākamā rindiņa (teksta redaktorā)",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "",
"excalidrawLib": "",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "ကားချပ်ရှင်းလင်း",
@@ -186,7 +192,9 @@
"freedraw": "",
"text": "စာသား",
"library": "မှတ်တမ်း",
"lock": "ရွေးချယ်ထားသောကိရိယာကိုသာဆက်သုံး"
"lock": "ရွေးချယ်ထားသောကိရိယာကိုသာဆက်သုံး",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "ကားချပ်လုပ်ဆောင်ချက်",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "Personlig bibliotek",
"excalidrawLib": "Excalidraw-bibliotek",
"decreaseFontSize": "Reduser skriftstørrelse",
"increaseFontSize": "Øk skriftstørrelse"
"increaseFontSize": "Øk skriftstørrelse",
"unbindText": "Avbind tekst",
"link": {
"edit": "Rediger lenke",
"create": "Opprett lenke",
"label": "Lenke"
}
},
"buttons": {
"clearReset": "Tøm lerretet og tilbakestill bakgrunnsfargen",
@@ -186,7 +192,9 @@
"freedraw": "Tegn",
"text": "Tekst",
"library": "Bibliotek",
"lock": "Behold merket verktøy som aktivt"
"lock": "Behold merket verktøy som aktivt",
"penMode": "Forhindre zoom ved kniping og godta frihåndstegning kun fra penn",
"link": "Legg til / oppdater link for en valgt figur"
},
"headings": {
"canvasActions": "Handlinger: lerret",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "Persoonlijke bibliotheek",
"excalidrawLib": "Excalidraw bibliotheek",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "Ontkoppel tekst",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "Canvas opnieuw instellen",
@@ -186,7 +192,9 @@
"freedraw": "Tekenen",
"text": "Tekst",
"library": "Bibliotheek",
"lock": "Geselecteerde tool actief houden na tekenen"
"lock": "Geselecteerde tool actief houden na tekenen",
"penMode": "Voorkom pinch-zoom en accepteer freedraw invoer alleen van pen",
"link": ""
},
"headings": {
"canvasActions": "Canvasacties",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "",
"excalidrawLib": "",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "Tilbakestill lerretet",
@@ -186,7 +192,9 @@
"freedraw": "Teikn",
"text": "Tekst",
"library": "Bibliotek",
"lock": "Hald fram med valt verktøy"
"lock": "Hald fram med valt verktøy",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "Handlingar: lerret",
+12 -4
View File
@@ -103,8 +103,14 @@
"toggleTheme": "Alternar tèma",
"personalLib": "Bibliotèca personala",
"excalidrawLib": "Bibliotèca Excalidraw",
"decreaseFontSize": "",
"increaseFontSize": ""
"decreaseFontSize": "Reduire talha poliça",
"increaseFontSize": "Aumentar talha poliça",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "Reïnicializar lo canabàs",
@@ -186,7 +192,9 @@
"freedraw": "Dessenhar",
"text": "Tèxt",
"library": "Bibliotèca",
"lock": "Mantenir activa laisina aprèp dessenhar"
"lock": "Mantenir activa laisina aprèp dessenhar",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "Accions del canabàs",
@@ -302,7 +310,7 @@
},
"errors": {
"required": "Requerit",
"website": ""
"website": "Picatz una URL valida"
},
"noteDescription": {
"pre": "Enviatz vòstra bibliotèca per èsser compresa al ",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "ਨਿੱਜੀ ਲਾਇਬ੍ਰੇਰੀ",
"excalidrawLib": "ਐਕਸਕਲੀਡਰਾਅ ਲਾਇਬ੍ਰੇਰੀ",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "ਕੈਨਵਸ ਰੀਸੈੱਟ ਕਰੋ",
@@ -186,7 +192,9 @@
"freedraw": "ਵਾਹੋ",
"text": "ਪਾਠ",
"library": "ਲਾਇਬ੍ਰੇਰੀ",
"lock": "ਡਰਾਇੰਗ ਤੋਂ ਬਾਅਦ ਵੀ ਚੁਣੇ ਹੋਏ ਸੰਦ ਨੂੰ ਸਰਗਰਮ ਰੱਖੋ "
"lock": "ਡਰਾਇੰਗ ਤੋਂ ਬਾਅਦ ਵੀ ਚੁਣੇ ਹੋਏ ਸੰਦ ਨੂੰ ਸਰਗਰਮ ਰੱਖੋ ",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "ਕੈਨਵਸ ਦੀਆਂ ਕਾਰਵਾਈਆਂ",
+30 -30
View File
@@ -1,47 +1,47 @@
{
"ar-SA": 88,
"bg-BG": 62,
"bg-BG": 61,
"bn-BD": 0,
"ca-ES": 97,
"ca-ES": 95,
"cs-CZ": 24,
"da-DK": 17,
"de-DE": 100,
"el-GR": 88,
"da-DK": 16,
"de-DE": 99,
"el-GR": 87,
"en": 100,
"es-ES": 86,
"eu-ES": 84,
"fa-IR": 64,
"fi-FI": 97,
"es-ES": 84,
"eu-ES": 96,
"fa-IR": 63,
"fi-FI": 98,
"fr-FR": 100,
"he-IL": 82,
"hi-IN": 56,
"hu-HU": 50,
"he-IL": 80,
"hi-IN": 55,
"hu-HU": 49,
"id-ID": 100,
"it-IT": 98,
"it-IT": 96,
"ja-JP": 98,
"kab-KAB": 96,
"kab-KAB": 95,
"kk-KZ": 23,
"ko-KR": 57,
"ko-KR": 72,
"lt-LT": 24,
"lv-LV": 100,
"my-MM": 47,
"my-MM": 46,
"nb-NO": 100,
"nl-NL": 91,
"nn-NO": 85,
"oc-FR": 98,
"pa-IN": 88,
"pl-PL": 95,
"pt-BR": 100,
"pt-PT": 85,
"nl-NL": 90,
"nn-NO": 83,
"oc-FR": 97,
"pa-IN": 87,
"pl-PL": 93,
"pt-BR": 98,
"pt-PT": 83,
"ro-RO": 100,
"ru-RU": 100,
"ru-RU": 99,
"si-LK": 9,
"sk-SK": 99,
"sv-SE": 99,
"ta-IN": 97,
"tr-TR": 86,
"uk-UA": 83,
"sk-SK": 100,
"sv-SE": 100,
"ta-IN": 99,
"tr-TR": 85,
"uk-UA": 82,
"zh-CN": 100,
"zh-HK": 29,
"zh-HK": 28,
"zh-TW": 100
}
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "Biblioteka prywatna",
"excalidrawLib": "Biblioteka Excalidraw",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "Wyczyść dokument i zresetuj kolor dokumentu",
@@ -186,7 +192,9 @@
"freedraw": "Rysuj",
"text": "Tekst",
"library": "Biblioteka",
"lock": "Zablokuj wybrane narzędzie"
"lock": "Zablokuj wybrane narzędzie",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "Narzędzia",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "Biblioteca Pessoal",
"excalidrawLib": "Biblioteca do Excalidraw",
"decreaseFontSize": "Diminuir o tamanho da fonte",
"increaseFontSize": "Aumentar o tamanho da fonte"
"increaseFontSize": "Aumentar o tamanho da fonte",
"unbindText": "Desvincular texto",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "Limpar o canvas e redefinir a cor de fundo",
@@ -186,7 +192,9 @@
"freedraw": "Desenhar",
"text": "Texto",
"library": "Biblioteca",
"lock": "Manter ativa a ferramenta selecionada após desenhar"
"lock": "Manter ativa a ferramenta selecionada após desenhar",
"penMode": "Prevenir a ação de tocar-ampliar e permitir apenas interações da caneta",
"link": ""
},
"headings": {
"canvasActions": "Ações da tela",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "",
"excalidrawLib": "",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "Limpar a área de desenho e redefinir a cor de fundo",
@@ -186,7 +192,9 @@
"freedraw": "Desenhar",
"text": "Texto",
"library": "Biblioteca",
"lock": "Manter a ferramenta selecionada ativa após desenhar"
"lock": "Manter a ferramenta selecionada ativa após desenhar",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "Ações da área de desenho",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "Biblioteca personală",
"excalidrawLib": "Biblioteca Excalidraw",
"decreaseFontSize": "Micșorează dimensiunea fontului",
"increaseFontSize": "Mărește dimensiunea fontului"
"increaseFontSize": "Mărește dimensiunea fontului",
"unbindText": "Deconectare text",
"link": {
"edit": "Editare URL",
"create": "Creare URL",
"label": "URL"
}
},
"buttons": {
"clearReset": "Resetare pânză",
@@ -186,7 +192,9 @@
"freedraw": "Desenare",
"text": "Text",
"library": "Bibliotecă",
"lock": "Menține activ instrumentul selectat după desenare"
"lock": "Menține activ instrumentul selectat după desenare",
"penMode": "Împiedică mărirea prin ciupire și acceptă desenarea liberă doar de la stilou",
"link": "Adăugare/actualizare URL pentru forma selectată"
},
"headings": {
"canvasActions": "Acțiuni pentru pânză",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "Личная библиотека",
"excalidrawLib": "Библиотека Excalidraw",
"decreaseFontSize": "Уменьшить шрифт",
"increaseFontSize": "Увеличить шрифт"
"increaseFontSize": "Увеличить шрифт",
"unbindText": "Отвязать текст",
"link": {
"edit": "Редактировать ссылку",
"create": "Создать ссылку",
"label": "Ссылка"
}
},
"buttons": {
"clearReset": "Очистить холст и сбросить цвет фона",
@@ -186,7 +192,9 @@
"freedraw": "Чертить",
"text": "Текст",
"library": "Библиотека",
"lock": "Сохранять выбранный инструмент активным после рисования"
"lock": "Сохранять выбранный инструмент активным после рисования",
"penMode": "",
"link": "Добавить/обновить ссылку для выбранной фигуры"
},
"headings": {
"canvasActions": "Операции холста",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "",
"excalidrawLib": "",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "",
@@ -186,7 +192,9 @@
"freedraw": "",
"text": "",
"library": "",
"lock": ""
"lock": "",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "",
+12 -4
View File
@@ -103,8 +103,14 @@
"toggleTheme": "Prepnúť tému",
"personalLib": "Moja knižnica",
"excalidrawLib": "Excalidraw knižnica",
"decreaseFontSize": "",
"increaseFontSize": ""
"decreaseFontSize": "Zmenšiť veľkosť písma",
"increaseFontSize": "Zväčšiť veľkosť písma",
"unbindText": "Zrušiť previazanie textu",
"link": {
"edit": "Upraviť odkaz",
"create": "Vytvoriť odkaz",
"label": "Odkaz"
}
},
"buttons": {
"clearReset": "Obnoviť plátno",
@@ -186,7 +192,9 @@
"freedraw": "Kresliť",
"text": "Text",
"library": "Knižnica",
"lock": "Nechať zvolený nástroj aktívny po skončení kreslenia"
"lock": "Nechať zvolený nástroj aktívny po skončení kreslenia",
"penMode": "Zabrániť priblíženiu potiahnutím a povoliť vstup voľnou rokou iba z pera",
"link": "Pridať/ Upraviť odkaz pre vybraný tvar"
},
"headings": {
"canvasActions": "Akcie plátna",
@@ -295,7 +303,7 @@
"placeholder": {
"authorName": "Vaše meno alebo užívateľské meno",
"libraryName": "Názov vašej knižnice",
"libraryDesc": "",
"libraryDesc": "Popis vašej knižnice, ktorý ostatným pomôže porozumieť jej vhodnému použitiu",
"githubHandle": "GitHub užívateľské meno (nepovinné), aby ste mohli robiť úpravy po tom, čo bude knižnica uverejnená na schválenie",
"twitterHandle": "Twitter užívateľské meno (nepovinné), aby sme vedeli komu pripísať zásluhu pri propagovaní cez Twitter",
"website": "Odkaz na vašu osobnú webovú stránku alebo niekam inam (nepovinné)"
+11 -3
View File
@@ -103,8 +103,14 @@
"toggleTheme": "Växla tema",
"personalLib": "Personligt bibliotek",
"excalidrawLib": "Excalidraw bibliotek",
"decreaseFontSize": "",
"increaseFontSize": ""
"decreaseFontSize": "Minska fontstorleken",
"increaseFontSize": "Öka fontstorleken",
"unbindText": "Koppla bort text",
"link": {
"edit": "Redigera länk",
"create": "Skapa länk",
"label": "Länk"
}
},
"buttons": {
"clearReset": "Återställ canvasen",
@@ -186,7 +192,9 @@
"freedraw": "Rita",
"text": "Text",
"library": "Bibliotek",
"lock": "Håll valt verktyg aktivt efter ritande"
"lock": "Håll valt verktyg aktivt efter ritande",
"penMode": "Förhindra nypzoom och acceptera endast frihandsteckning från penna",
"link": "Lägg till / Uppdatera länk för en vald form"
},
"headings": {
"canvasActions": "Canvas-åtgärder",
+17 -9
View File
@@ -40,7 +40,7 @@
"fontFamily": "எழுத்துரு குடும்பம்",
"onlySelected": "தேர்ந்ததை மட்டும்",
"withBackground": "பின்புலம்",
"exportEmbedScene": "கட்சியை உட்பொதி",
"exportEmbedScene": "கட்சியை உட்பொதி",
"exportEmbedScene_details": "காட்சி தரவு ஏற்றுமதி செய்யப்பட்ட PNG/SVG கோப்பினுள் சேமிக்கப்படும் இதனால் காட்சியை அதிலிருந்து மீட்டெடுக்க முடியும். ஏற்றுமதி செய்யப்பட்ட கோப்பின் அளவை அதிகரிக்கும்.",
"addWatermark": "\"எக்ஸ்கேலிட்ரா கொண்டு ஆனது\"-ஐச் சேர்",
"handDrawn": "கையால்-வரைந்த",
@@ -103,8 +103,14 @@
"toggleTheme": "தோற்றத்தை நிலைமாற்று",
"personalLib": "தனக்குரிய நூலகம்",
"excalidrawLib": "எக்ஸ்கேலிட்ரா நூலகம்",
"decreaseFontSize": "",
"increaseFontSize": ""
"decreaseFontSize": "எழுத்துரு அளவைக் குறை",
"increaseFontSize": "எழுத்துரு அளவை அதிகரி",
"unbindText": "உரையைப் பிணைவவிழ்",
"link": {
"edit": "தொடுப்பைத் திருத்து",
"create": "தொடுப்பைப் படை",
"label": "தொடுப்பு"
}
},
"buttons": {
"clearReset": "கித்தானை அகரமாக்கு",
@@ -156,7 +162,7 @@
"decryptFailed": "தரவை மறைநீக்க முடியவில்லை.",
"uploadedSecurly": "பதிவேற்றம் இருமுனை மறையாகத்தால் பாதுகாக்கப்பட்டுள்ளது, எனவே எக்ஸ்கேலிட்ரா சேவையகமும் மூன்றாம் தரப்பினரும் உள்ளடக்கத்தை வாசிக்கமுடியாது.",
"loadSceneOverridePrompt": "வெளிப்புறச்சித்திரமேற்றல் இருக்கிற உள்ளடக்கத்தை இடங்கொள்ளும். தொடர விருப்பமா?",
"collabStopOverridePrompt": "",
"collabStopOverridePrompt": "அமர்வை நிறுத்துதல் முன்னர் அகமாக தேக்கிய உம் சித்திரத்தை மேலெழுதும். நீங்கள் உறுதியா?\n\n(உம் அக சித்திரத்தை வைக்கவேண்டுமெனில், சும்மா உலாவி தாவலை மூடுக அதற்குபதிலாக.)",
"errorLoadingLibrary": "மூன்றாம் தரப்பு நூலகத்தை ஏற்றுவதில் பிழை.",
"errorAddingToLibrary": "உருப்படியை நூலகத்தில் சேர்க்க இயலா",
"errorRemovingFromLibrary": "உருப்படியை நூலகத்திலிருந்து நீக்க இயலா",
@@ -186,7 +192,9 @@
"freedraw": "வரை",
"text": "உரை",
"library": "நூலகம்",
"lock": "தேர்ந்த கருவியை வரைந்த பின்பும் வைத்திரு"
"lock": "தேர்ந்த கருவியை வரைந்த பின்பும் வைத்திரு",
"penMode": "கிள்ளிப்பெரிதாக்குவதைத் தவிர் மற்றும் பேனாவிலிருந்து மட்டும் கட்டற்றவரைவை ஏல்",
"link": "தேர்தெடுத்த வடிவத்திற்குத் தொடுப்பைச் சேர்/ புதுப்பி"
},
"headings": {
"canvasActions": "கித்தான் செயல்கள்",
@@ -201,17 +209,17 @@
"text_selected": "உரையைத் திருத்த இரு-சொடுக்கு அ ENTERஐ அழுத்து",
"text_editing": "திருத்துவதை முடிக்க Escape அ CtrlOrCmd+ENTERஐ அழுத்து",
"linearElementMulti": "கடைசி புள்ளியில் சொடுக்கு அ முடிக்க Escape அ Enter அழுத்து",
"lockAngle": "",
"resize": "",
"lockAngle": "SHIFTஐ அழுத்திப்பிடித்து கோணத்தை வற்புறுத்தலாம்",
"resize": "மறுஅளவிடுகையில் SHIFTஐ அழுத்திப்பிடித்து விகிதசமத்தை வற்புறுத்தலாம்,\nமையத்திலிருந்து மறுஅளவிட ALTஐ அழுத்திப்பிடி",
"resizeImage": "SHIFTஐ நீண்டழுத்தி கட்டற்று அளவுமாற்றலாம்,\nமையத்திலிருந்து அளவுமாற்ற ALTஐ நீண்டழுத்துக",
"rotate": "",
"rotate": "சுழற்றுகையில் SHIFTஐ அழுத்திப்பிடித்து கோணங்களை வற்புறுத்தலாம்",
"lineEditor_info": "புள்ளிகளைத் திருத்த இரு-சொடுக்கு அ Enterஐ அழுத்து",
"lineEditor_pointSelected": "புள்ளி(கள்)ஐ நீக்க Deleteஐ அழுத்து,\nநகலாக்க CtrlOrCmd+D, அ நகர்த்த பிடித்திழு",
"lineEditor_nothingSelected": "திருத்த புள்ளியைத் தேர்ந்தெடு (பலவற்றை தேர SHIFTஐ அழுத்திப்பிடி),\nஅ புதிய புள்ளிகளைச் சேர்க்க Altஐ அழுத்திப்பிடித்துச் சொடுக்கு",
"placeImage": "படத்தை வைக்கச் சொடுக்கு, அ கைமுறையாக அளவு அமைக்க சொடுக்கி பிடித்திழு",
"publishLibrary": "உம் சொந்த நூலகத்தைப் பிரசுரி",
"bindTextToElement": "உரையைச் சேர்க்க enterஐ அழுத்து",
"deepBoxSelect": ""
"deepBoxSelect": "ஆழ்ந்துத் தேரவும் பிடித்திழுத்தலைத் தவிர்க்கவும் CtrlOrCmdஐ அழுத்திப்பிடி"
},
"canvasError": {
"cannotShowPreview": "முன்னோட்டம் காட்ட இயலவில்லை",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "Kişisel Kitaplık",
"excalidrawLib": "Excalidraw Kitaplığı",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "Tuvali sıfırla",
@@ -186,7 +192,9 @@
"freedraw": "Çiz",
"text": "Yazı",
"library": "Kütüphane",
"lock": "Seçilen aracı çizimden sonra aktif tut"
"lock": "Seçilen aracı çizimden sonra aktif tut",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "Tuval eylemleri",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "",
"excalidrawLib": "",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "Очистити полотно",
@@ -186,7 +192,9 @@
"freedraw": "Малювати",
"text": "Текст",
"library": "Бібліотека",
"lock": "Залишити обраний інструмент після креслення"
"lock": "Залишити обраний інструмент після креслення",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "Дії з полотном",
+11 -3
View File
@@ -104,7 +104,13 @@
"personalLib": "个人素材库",
"excalidrawLib": "Excalidraw 素材库",
"decreaseFontSize": "缩小字体大小",
"increaseFontSize": "放大字体大小"
"increaseFontSize": "放大字体大小",
"unbindText": "取消文本绑定",
"link": {
"edit": "编辑链接",
"create": "新建链接",
"label": "链接"
}
},
"buttons": {
"clearReset": "重置画布",
@@ -186,7 +192,9 @@
"freedraw": "自由书写",
"text": "文字",
"library": "素材库",
"lock": "绘制后保持所选的工具栏状态"
"lock": "绘制后保持所选的工具栏状态",
"penMode": "禁用手势缩放并只接收来自触控笔的输入",
"link": "为选中的形状添加/更新链接"
},
"headings": {
"canvasActions": "画布动作",
@@ -312,7 +320,7 @@
"noteGuidelines": {
"pre": "提交的素材库需先经人工审核。在提交之前,请先阅读 ",
"link": "指南",
"post": " 后续沟通和对库的修改需要 GitHub 号,但这不是必须的。"
"post": " 后续沟通和对库的修改需要 GitHub 号,但这不是必须的。"
},
"noteLicense": {
"pre": "提交即表明您已同意素材库将遵循 ",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "",
"excalidrawLib": "",
"decreaseFontSize": "",
"increaseFontSize": ""
"increaseFontSize": "",
"unbindText": "",
"link": {
"edit": "",
"create": "",
"label": ""
}
},
"buttons": {
"clearReset": "清空畫布",
@@ -186,7 +192,9 @@
"freedraw": "",
"text": "",
"library": "",
"lock": ""
"lock": "",
"penMode": "",
"link": ""
},
"headings": {
"canvasActions": "畫布動作",
+10 -2
View File
@@ -104,7 +104,13 @@
"personalLib": "個人資料庫",
"excalidrawLib": "Excalidraw 資料庫",
"decreaseFontSize": "縮小文字",
"increaseFontSize": "放大文字"
"increaseFontSize": "放大文字",
"unbindText": "取消綁定文字",
"link": {
"edit": "編輯連結",
"create": "建立連結",
"label": "連結"
}
},
"buttons": {
"clearReset": "重置 canvas",
@@ -186,7 +192,9 @@
"freedraw": "繪圖",
"text": "文字",
"library": "資料庫",
"lock": "可連續使用選取的工具"
"lock": "可連續使用選取的工具",
"penMode": "停止使用手勢縮放並接受以繪圖筆繪圖輸入",
"link": "為所選的形狀增加\b/更新連結"
},
"headings": {
"canvasActions": "canvas 動作",
+288 -19
View File
@@ -11,30 +11,29 @@ The change should be grouped under one of the below section and must contain PR
Please add the latest change on the top under the correct section.
-->
## Unreleased
## 0.11.0 (2022-02-17)
## Excalidraw API
- [`exportToBlob`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#exportToBlob) now automatically sets `appState.exportBackground` to `true` if exporting to `image/jpeg` MIME type (to ensure that alpha channel is not compressed to black color).
### Features
- Add `onLinkOpen` prop which will be triggered when clicked on element hyperlink if present [#4694](https://github.com/excalidraw/excalidraw/pull/4694).
- Support updating library using [`updateScene`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#updateScene) API [#4546](https://github.com/excalidraw/excalidraw/pull/4546).
- Introduced primary colors to the app. The colors can be overriden. Check [readme](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#customizing-styles) on how to do so.
- Introduced primary colors to the app. The colors can be overriden. Check [readme](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#customizing-styles) on how to do so [#4387](https://github.com/excalidraw/excalidraw/pull/4387).
- #### BREAKING CHANGE
- [`exportToBlob`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#exportToBlob) now automatically sets `appState.exportBackground` to `true` if exporting to `image/jpeg` MIME type (to ensure that alpha channel is not compressed to black color) [#4342](https://github.com/excalidraw/excalidraw/pull/4342).
Removed `getElementMap` util method.
#### BREAKING CHANGE
- Changes to [`exportToCanvas`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#exportToCanvas) util function:
Remove `getElementMap` util [#4306](https://github.com/excalidraw/excalidraw/pull/4306).
- Changes to [`exportToCanvas`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#exportToCanvas) util function [#4321](https://github.com/excalidraw/excalidraw/pull/4321):
- Add `maxWidthOrHeight?: number` attribute.
- `scale` returned from `getDimensions()` is now optional (default to `1`).
- Image support.
NOTE: the unreleased API is highly unstable and may change significantly before the next stable release. As such it's largely undocumented at this point. You are encouraged to read through the [PR](https://github.com/excalidraw/excalidraw/pull/4011) description if you want to know more about the internals.
- Image support added for host [PR](https://github.com/excalidraw/excalidraw/pull/4011)
General notes:
@@ -54,13 +53,13 @@ Please add the latest change on the top under the correct section.
Other notes:
- `.excalidraw` files may now contain top-level `files` key in format of `Record<FileId, BinaryFileData>` when exporting any (image) elements.
- Changes were made to various export utilityies exported from the package so that they take `files`. For now, TypeScript should help you figure the changes out.
- Changes were made to various export utilities exported from the package so that they take `files`, you can refer to the docs for the same.
- Export [`isLinearElement`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#isLinearElement) and [`getNonDeletedElements`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#getNonDeletedElements).
- Export [`isLinearElement`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#isLinearElement) and [`getNonDeletedElements`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#getNonDeletedElements) [#4072](https://github.com/excalidraw/excalidraw/pull/4072).
- Support [`renderTopRightUI`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#renderTopRightUI) in mobile UI.
- Support [`renderTopRightUI`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#renderTopRightUI) in mobile UI [#4065](https://github.com/excalidraw/excalidraw/pull/4065).
- Export `THEME` constant from the package so host can use this when passing the theme.
- Export `THEME` constant from the package so host can use this when passing the theme [#4055](https://github.com/excalidraw/excalidraw/pull/4055).
#### BREAKING CHANGE
@@ -70,15 +69,285 @@ Please add the latest change on the top under the correct section.
- Reset `unmounted` state on the component once component mounts to fix the mounting/unmounting repeatedly when used with `useEffect` [#4682](https://github.com/excalidraw/excalidraw/pull/4682).
- Panning the canvas using `mousewheel-drag` and `space-drag` now prevents the browser from scrolling the container/page [#4489](https://github.com/excalidraw/excalidraw/pull/4489).
- Scope drag and drop events to Excalidraw container to prevent overriding host application drag and drop events.
- Scope drag and drop events to Excalidraw container to prevent overriding host application drag and drop events [#4445](https://github.com/excalidraw/excalidraw/pull/4445).
### Build
- Added an example to test and develop the package [locally](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#Development) using `yarn start`
- Release preview package [@excalidraw/excalidraw-preview](https://www.npmjs.com/package/@excalidraw/excalidraw-preview) when triggered via comment
- Remove `file-loader` so font assets are not duplicated by webpack and use webpack asset modules for font generation [#4380](https://github.com/excalidraw/excalidraw/pull/4380)
```
@excalibot trigger release
```
- We're now compiling to `es2017` target. Notably, `async/await` is not compiled down to generators. [#4341](https://github.com/excalidraw/excalidraw/pull/4341)
[#4750](https://github.com/excalidraw/excalidraw/pull/4750).
- Added an example to test and develop the package [locally](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#Development) using `yarn start` [#4488](https://github.com/excalidraw/excalidraw/pull/4488)
- Remove `file-loader` so font assets are not duplicated by webpack and use webpack asset modules for font generation [#4380](https://github.com/excalidraw/excalidraw/pull/4380).
- We're now compiling to `es2017` target. Notably, `async/await` is not compiled down to generators. [#4341](https://github.com/excalidraw/excalidraw/pull/4341).
---
## Excalidraw Library
**_This section lists the updates made to the excalidraw library and will not affect the integration._**
### Features
- Show group/group and link action in mobile [#4795](https://github.com/excalidraw/excalidraw/pull/4795)
- Support background fill for freedraw shapes [#4610](https://github.com/excalidraw/excalidraw/pull/4610)
- Keep selected tool on canvas reset [#4728](https://github.com/excalidraw/excalidraw/pull/4728)
- Make whole element clickable in view mode when it has hyperlink [#4735](https://github.com/excalidraw/excalidraw/pull/4735)
- Allow any precision when zooming [#4730](https://github.com/excalidraw/excalidraw/pull/4730)
- Throttle `pointermove` events per framerate [#4727](https://github.com/excalidraw/excalidraw/pull/4727)
- Support hyperlinks 🔥 [#4620](https://github.com/excalidraw/excalidraw/pull/4620)
- Added penMode for palm rejection [#4657](https://github.com/excalidraw/excalidraw/pull/4657)
- Support unbinding bound text [#4686](https://github.com/excalidraw/excalidraw/pull/4686)
- Sync local storage state across tabs when out of sync [#4545](https://github.com/excalidraw/excalidraw/pull/4545)
- Support contextMenuLabel to be of function type to support dynmaic labels [#4654](https://github.com/excalidraw/excalidraw/pull/4654)
- Support decreasing/increasing `fontSize` via keyboard [#4553](https://github.com/excalidraw/excalidraw/pull/4553)
- Link to new LP for excalidraw plus [#4549](https://github.com/excalidraw/excalidraw/pull/4549)
- Update stroke color of bounded text along with container [#4541](https://github.com/excalidraw/excalidraw/pull/4541)
- Hints and shortcuts help around deep selection [#4502](https://github.com/excalidraw/excalidraw/pull/4502)
- Support updating text properties by clicking on container [#4499](https://github.com/excalidraw/excalidraw/pull/4499)
- Bind text to shapes when pressing enter and support sticky notes 🎉 [#4343](https://github.com/excalidraw/excalidraw/pull/4343)
- Change `boundElementIds``boundElements` [#4404](https://github.com/excalidraw/excalidraw/pull/4404)
- Support selecting multiple points when editing line [#4373](https://github.com/excalidraw/excalidraw/pull/4373)
- Horizontally center toolbar menu [commit link](https://github.com/excalidraw/excalidraw/commit/9b8ee3cacfec239617c357693cf2a3ca9972d2cb)
- Add support for rounded corners in diamond [#4369](https://github.com/excalidraw/excalidraw/pull/4369)
- Allow zooming up to 3000% [#4358](https://github.com/excalidraw/excalidraw/pull/4358)
- Stop discarding precision when rendering [#4357](https://github.com/excalidraw/excalidraw/pull/4357)
- Support Image binding [#4347](https://github.com/excalidraw/excalidraw/pull/4347)
- Add `element.updated` [#4070](https://github.com/excalidraw/excalidraw/pull/4070)
- Compress shareLink data when uploading to json server [#4225](https://github.com/excalidraw/excalidraw/pull/4225)
- Supply `version` param when installing libraries [#4305](https://github.com/excalidraw/excalidraw/pull/4305)
- Log FS abortError to console [#4279](https://github.com/excalidraw/excalidraw/pull/4279)
- Add validation for website and remove validation for library item name [#4269](https://github.com/excalidraw/excalidraw/pull/4269)
- Allow publishing libraries from UI [#4115](https://github.com/excalidraw/excalidraw/pull/4115)
- Create confirm dialog to use instead of window.confirm [#4256](https://github.com/excalidraw/excalidraw/pull/4256)
- Allow letters in IDs for storing files in backend [#4224](https://github.com/excalidraw/excalidraw/pull/4224)
- Remove support for V1 unencrypted backend [#4189](https://github.com/excalidraw/excalidraw/pull/4189)
- Use separate backend for local storage [#4187](https://github.com/excalidraw/excalidraw/pull/4187)
- Add hint around canvas panning [#4159](https://github.com/excalidraw/excalidraw/pull/4159)
- Stop using production services for development [#4113](https://github.com/excalidraw/excalidraw/pull/4113)
- Add triangle arrowhead [#4024](https://github.com/excalidraw/excalidraw/pull/4024)
- Add rewrite to webex landing page [#4102](https://github.com/excalidraw/excalidraw/pull/4102)
- Switch collab server [#4092](https://github.com/excalidraw/excalidraw/pull/4092)
- Use dialog component for clear canvas instead of window confirm [#4075](https://github.com/excalidraw/excalidraw/pull/4075)
### Fixes
- Rename --color-primary-chubb to --color-primary-contrast-offset and fallback to primary color if not present [#4803](https://github.com/excalidraw/excalidraw/pull/4803)
- Add commits directly pushed to master in changelog [#4798](https://github.com/excalidraw/excalidraw/pull/4798)
- Don't bump element version when adding files data [#4794](https://github.com/excalidraw/excalidraw/pull/4794)
- Mobile link click [#4742](https://github.com/excalidraw/excalidraw/pull/4742)
- ContextMenu timer & pointers not correctly reset on iOS [#4765](https://github.com/excalidraw/excalidraw/pull/4765)
- Use absolute coords when rendering link popover [#4753](https://github.com/excalidraw/excalidraw/pull/4753)
- Changing font size when text is not selected or edited [#4751](https://github.com/excalidraw/excalidraw/pull/4751)
- Disable contextmenu on non-secondary `pen` events or `touch` [#4675](https://github.com/excalidraw/excalidraw/pull/4675)
- Mobile context menu won't show on long press [#4741](https://github.com/excalidraw/excalidraw/pull/4741)
- Do not open links twice [#4738](https://github.com/excalidraw/excalidraw/pull/4738)
- Make link icon clickable in mobile [#4736](https://github.com/excalidraw/excalidraw/pull/4736)
- Apple Pen missing strokes [#4705](https://github.com/excalidraw/excalidraw/pull/4705)
- Freedraw slow movement jittery lines [#4726](https://github.com/excalidraw/excalidraw/pull/4726)
- Disable three finger pinch zoom in penMode [#4725](https://github.com/excalidraw/excalidraw/pull/4725)
- Remove click listener for opening popup [#4700](https://github.com/excalidraw/excalidraw/pull/4700)
- Link popup position not accounting for offsets [#4695](https://github.com/excalidraw/excalidraw/pull/4695)
- PenMode darkmode style [#4692](https://github.com/excalidraw/excalidraw/pull/4692)
- Typing `_+` in wysiwyg not working [#4681](https://github.com/excalidraw/excalidraw/pull/4681)
- Keyboard-zooming in wysiwyg should zoom canvas [#4676](https://github.com/excalidraw/excalidraw/pull/4676)
- SceneCoordsToViewportCoords, jumping text when there is an offset [#4413](https://github.com/excalidraw/excalidraw/pull/4413) (#4630)
- Right-click object menu displays partially off-screen [#4572](https://github.com/excalidraw/excalidraw/pull/4572) (#4631)
- Support collaboration in bound text [#4573](https://github.com/excalidraw/excalidraw/pull/4573)
- Cmd/ctrl native browser behavior blocked in inputs [#4589](https://github.com/excalidraw/excalidraw/pull/4589)
- Use cached width when calculating min width during resize [#4585](https://github.com/excalidraw/excalidraw/pull/4585)
- Support collaboration in bounded text [#4580](https://github.com/excalidraw/excalidraw/pull/4580)
- Port for collab server and update docs [#4569](https://github.com/excalidraw/excalidraw/pull/4569)
- Don't mutate the bounded text if not updated when submitted [#4543](https://github.com/excalidraw/excalidraw/pull/4543)
- Prevent canvas drag while editing text [#4552](https://github.com/excalidraw/excalidraw/pull/4552)
- Support shift+P for freedraw [#4550](https://github.com/excalidraw/excalidraw/pull/4550)
- Prefer spreadsheet data over image [#4533](https://github.com/excalidraw/excalidraw/pull/4533)
- Show text properties button states correctly for bounded text [#4542](https://github.com/excalidraw/excalidraw/pull/4542)
- Rotate bounded text when container is rotated before typing [#4535](https://github.com/excalidraw/excalidraw/pull/4535)
- Undo should work when selecting bounded textr [#4537](https://github.com/excalidraw/excalidraw/pull/4537)
- Reduce padding to 5px for bounded text [#4530](https://github.com/excalidraw/excalidraw/pull/4530)
- Bound text doesn't inherit container [#4521](https://github.com/excalidraw/excalidraw/pull/4521)
- Text wrapping with grid [#4505](https://github.com/excalidraw/excalidraw/pull/4505) (#4506)
- Check if process is defined before using so it works in browser [#4497](https://github.com/excalidraw/excalidraw/pull/4497)
- Pending review fixes for sticky notes [#4493](https://github.com/excalidraw/excalidraw/pull/4493)
- Pasted elements except binded text once paste action is complete [#4472](https://github.com/excalidraw/excalidraw/pull/4472)
- Don't select binded text when ungrouping [#4470](https://github.com/excalidraw/excalidraw/pull/4470)
- Set height correctly when text properties updated while editing in container until first submit [#4469](https://github.com/excalidraw/excalidraw/pull/4469)
- Align and distribute binded text in container and cleanup [#4468](https://github.com/excalidraw/excalidraw/pull/4468)
- Move binded text when moving container using keyboard [#4466](https://github.com/excalidraw/excalidraw/pull/4466)
- Support dragging binded text in container selected in a group [#4462](https://github.com/excalidraw/excalidraw/pull/4462)
- Vertically align single line when deleting text in bounded container [#4460](https://github.com/excalidraw/excalidraw/pull/4460)
- Update height correctly when updating text properties in binded text [#4459](https://github.com/excalidraw/excalidraw/pull/4459)
- Align library item previews to center [#4447](https://github.com/excalidraw/excalidraw/pull/4447)
- Vertically center align text when text deleted [#4457](https://github.com/excalidraw/excalidraw/pull/4457)
- Vertically center the first line as user starts typing in container [#4454](https://github.com/excalidraw/excalidraw/pull/4454)
- Switch cursor to center of container when adding text when dimensions are too small [#4452](https://github.com/excalidraw/excalidraw/pull/4452)
- Vertically center align the bounded text correctly when zoomed [#4444](https://github.com/excalidraw/excalidraw/pull/4444)
- Support updating stroke color for text by typing in color picker input [#4415](https://github.com/excalidraw/excalidraw/pull/4415)
- Bound text not atomic with container when changing z-index [#4414](https://github.com/excalidraw/excalidraw/pull/4414)
- Update viewport coords correctly when editing text [#4416](https://github.com/excalidraw/excalidraw/pull/4416)
- Use word-break break-word only and update text editor height only when binded to container [#4410](https://github.com/excalidraw/excalidraw/pull/4410)
- Husky not able to execute pre-commit on windows [#4370](https://github.com/excalidraw/excalidraw/pull/4370)
- Make firebase config parsing not fail on undefined env [#4381](https://github.com/excalidraw/excalidraw/pull/4381)
- Adding to library via contextmenu when no image is selected [#4356](https://github.com/excalidraw/excalidraw/pull/4356)
- Export scale quality regression [#4316](https://github.com/excalidraw/excalidraw/pull/4316)
- Remove `100%` height from tooltip container to fix layout issues [#3980](https://github.com/excalidraw/excalidraw/pull/3980)
- Inline ENV variables when building excalidraw package [#4311](https://github.com/excalidraw/excalidraw/pull/4311)
- SVG export in dark mode with embedded bitmap image [#4285](https://github.com/excalidraw/excalidraw/pull/4285)
- New FS API not working on Linux [#4280](https://github.com/excalidraw/excalidraw/pull/4280)
- Url -> URL for consistency [#4277](https://github.com/excalidraw/excalidraw/pull/4277)
- Prevent adding images to library via contextMenu [#4264](https://github.com/excalidraw/excalidraw/pull/4264)
- Account for libraries v2 when prompting [#4263](https://github.com/excalidraw/excalidraw/pull/4263)
- Skia rendering issues [#4200](https://github.com/excalidraw/excalidraw/pull/4200)
- Ellipse roughness when `0` [#4194](https://github.com/excalidraw/excalidraw/pull/4194)
- Proper string for invalid SVG [#4191](https://github.com/excalidraw/excalidraw/pull/4191)
- Images not initialized correctly [#4157](https://github.com/excalidraw/excalidraw/pull/4157)
- Image-related fixes [#4147](https://github.com/excalidraw/excalidraw/pull/4147)
- Rewrite collab element reconciliation to fix z-index issues [#4076](https://github.com/excalidraw/excalidraw/pull/4076)
- Redirect excalidraw.com/about to for-webex.excalidraw.com [#4104](https://github.com/excalidraw/excalidraw/pull/4104)
- Redirect to webex LP instead of rewrite to fix SW [#4103](https://github.com/excalidraw/excalidraw/pull/4103)
- Clear image/shape cache of affected elements when adding files [#4089](https://github.com/excalidraw/excalidraw/pull/4089)
- Clear `LibraryUnit` DOM on unmount [#4084](https://github.com/excalidraw/excalidraw/pull/4084)
- Pasting images on firefox [#4085](https://github.com/excalidraw/excalidraw/pull/4085)
### Refactor
- Simplify zoom by removing `zoom.translation` [#4477](https://github.com/excalidraw/excalidraw/pull/4477)
- Deduplicate encryption helpers [#4146](https://github.com/excalidraw/excalidraw/pull/4146)
### Performance
- Cache approx line height in textwysiwg [#4651](https://github.com/excalidraw/excalidraw/pull/4651)
### Build
- Rename release command to 'release package' [#4783](https://github.com/excalidraw/excalidraw/pull/4783)
- Deploy excalidraw package example [#4762](https://github.com/excalidraw/excalidraw/pull/4762)
- Allow package.json changes when autoreleasing next [#4068](https://github.com/excalidraw/excalidraw/pull/4068)
---
@@ -88,7 +357,7 @@ Please add the latest change on the top under the correct section.
### Fixes
- Don't show save file to disk button in export dialog when `saveFileToDisk` passed as `false` in [`UIOptions.canvasActions.export`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#exportOpts).
- Don't show save file to disk button in export dialog when `saveFileToDisk` passed as `false` in [`UIOptions.canvasActions.export`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#exportOpts) [#4073](https://github.com/excalidraw/excalidraw/pull/4073).
- [`onPaste`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#onPaste) prop should return false to prevent the native excalidraw paste action [#3974](https://github.com/excalidraw/excalidraw/pull/3974).
+255 -109
View File
@@ -347,6 +347,31 @@ To view the full example visit :point_down:
</details>
### Customizing styles
Excalidraw is using CSS variables to style certain components. To override them, you should set your own on the `.excalidraw` and `.excalidraw.theme--dark` (for dark mode variables) selectors.
Make sure the selector has higher specificity, e.g. by prefixing it with your app's selector:
```css
.your-app .excalidraw {
--color-primary: red;
}
.your-app .excalidraw.theme--dark {
--color-primary: pink;
}
```
Most notably, you can customize the primary colors, by overriding these variables:
- `--color-primary`
- `--color-primary-darker`
- `--color-primary-darkest`
- `--color-primary-light`
- `--color-primary-contrast-offset` — a slightly darker (in light mode), or lighter (in dark mode) `--color-primary` color to fix contrast issues (see [Chubb illusion](https://en.wikipedia.org/wiki/Chubb_illusion)). It will fall back to `--color-primary` if not present.
For a complete list of variables, check [theme.scss](https://github.com/excalidraw/excalidraw/blob/master/src/css/theme.scss), though most of them will not make sense to override.
### Props
| Name | Type | Default | Description |
@@ -365,14 +390,16 @@ To view the full example visit :point_down:
| [`zenModeEnabled`](#zenModeEnabled) | boolean | | This implies if the zen mode is enabled |
| [`gridModeEnabled`](#gridModeEnabled) | boolean | | This implies 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` or `dark` | | The theme of the Excalidraw component |
| [`theme`](#theme) | [THEME.LIGHT](#THEME-1) &#124; [THEME.LIGHT](#THEME-1) | [THEME.LIGHT](#THEME-1) | The theme of the Excalidraw component |
| [`name`](#name) | string | | Name of the drawing |
| [`UIOptions`](#UIOptions) | <pre>{ canvasActions: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L208"> CanvasActions<a/> }</pre> | [DEFAULT UI OPTIONS](https://github.com/excalidraw/excalidraw/blob/master/src/constants.ts#L129) | To customise UI options. Currently we support customising [`canvas actions`](#canvasActions) |
| [`onPaste`](#onPaste) | <pre>(data: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/clipboard.ts#L17">ClipboardData</a>, event: ClipboardEvent &#124; null) => boolean</pre> | | Callback to be triggered if passed when the something is pasted in to the scene |
| [`onPaste`](#onPaste) | <pre>(data: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/clipboard.ts#L21">ClipboardData</a>, event: ClipboardEvent &#124; null) => boolean</pre> | | Callback to be triggered if passed when the something is pasted in to the scene |
| [`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. |
| [`onLibraryChange`](#onLibraryChange) | <pre>(items: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L200">LibraryItems</a>) => void &#124; Promise&lt;any&gt; </pre> | | The callback if supplied is triggered when the library is updated and receives the library items. |
| [`autoFocus`](#autoFocus) | boolean | false | Implies whether to focus the Excalidraw component on page load |
| [`generateIdForFile`](#generateIdForFile) | `(file: File) => string | Promise<string>` | Allows you to override `id` generation for files added on canvas |
| [`onLinkOpen`](#onLinkOpen) | <pre>(element: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">NonDeletedExcalidrawElement</a>, event: CustomEvent) </pre> | | This prop if passed will be triggered when link of an element is clicked |
### Dimensions of Excalidraw
@@ -383,12 +410,14 @@ Excalidraw takes `100%` of `width` and `height` of the containing block so make
Every time component updates, this callback if passed will get triggered and has the below signature.
```js
(excalidrawElements, appState) => void;
(excalidrawElements, appState, files) => void;
```
1.`excalidrawElements`: Array of [excalidrawElements](https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78) in the scene.
2.`appState`: [AppState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L42) of the scene
2.`appState`: [AppState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L42) of the scene.
3. `files`: The [`BinaryFiles`]([BinaryFiles](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L64) which are added to the scene.
Here you can try saving the data to your backend or local storage for example.
@@ -402,6 +431,7 @@ This helps to load Excalidraw with `initialData`. It must be an object or a [pro
| `appState` | [AppState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L42) | The App state with which Excalidraw should be mounted. |
| `scrollToContent` | boolean | This attribute implies 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#L151) | This library items with which Excalidraw should be mounted. |
| `files` | [BinaryFiles](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L64) | The files added to the scene. |
```json
{
@@ -442,7 +472,8 @@ You can pass a `ref` when you want to access some excalidraw APIs. We expose the
| --- | --- | --- |
| ready | `boolean` | This is set to true once Excalidraw is rendered |
| readyPromise | [resolvablePromise](https://github.com/excalidraw/excalidraw/blob/master/src/utils.ts#L317) | This promise will be resolved with the api once excalidraw has rendered. This will be helpful when you want do some action on the host app once this promise resolves. For this to work you will have to pass ref as shown [here](#readyPromise) |
| [updateScene](#updateScene) | <pre>(<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L207">sceneData</a>)) => void </pre> | updates the scene with the sceneData |
| [updateScene](#updateScene) | <pre>(scene: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L207">sceneData</a>) => void </pre> | updates the scene with the sceneData |
| [addFiles](#addFiles) | <pre>(files: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts">BinaryFileData</a>) => void </pre> | add files data to the appState |
| resetScene | `({ resetLoadingState: boolean }) => void` | Resets the scene. If `resetLoadingState` is passed as true then it will also force set the loading state to false. |
| getSceneElementsIncludingDeleted | <pre> () => <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a></pre> | Returns all the elements including the deleted in the scene |
| getSceneElements | <pre> () => <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a></pre> | Returns all the elements excluding the deleted in the scene |
@@ -453,6 +484,7 @@ You can pass a `ref` when you want to access some excalidraw APIs. We expose the
| [importLibrary](#importlibrary) | `(url: string, token?: string) => void` | Imports library from given URL |
| setToastMessage | `(message: string) => void` | This API can be used to show the toast with custom message. |
| [id](#id) | string | Unique ID for the excalidraw component. |
| [getFiles](#getFiles) | <pre>() => <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L64">files</a> </pre> | This API can be used to get the files present in the scene. It may contain files that aren't referenced by any element, so if you're persisting the files to a storage, you should compare them against stored elements. |
#### `readyPromise`
@@ -465,7 +497,7 @@ Since plain object is passed as a `ref`, the `readyPromise` is resolved as soon
### `updateScene`
<pre>
(<a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L207">sceneData</a>)) => void
(scene: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L207">sceneData</a>) => void
</pre>
You can use this function to update the scene with the sceneData. It accepts the below attributes.
@@ -476,6 +508,13 @@ You can use this function to update the scene with the sceneData. It accepts the
| `appState` | [`ImportedDataState["appState"]`](https://github.com/excalidraw/excalidraw/blob/master/src/data/types.ts#L18) | The `appState` to be updated in the scene. |
| `collaborators` | <pre>Map<string, <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L29">Collaborator></a></pre> | The list of collaborators to be updated in the scene. |
| `commitToHistory` | `boolean` | Implies if the `history (undo/redo)` should be recorded. Defaults to `false`. |
| `libraryItems` | [LibraryItems](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L258) | The `libraryItems` to be update in the scene. |
### `addFiles`
<pre>(files: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts">BinaryFileData</a>) => void </pre>
Adds supplied files data to the `appState.files` cache on top of existing files present in the cache.
#### `onCollabButtonClick`
@@ -558,7 +597,7 @@ If supplied, this URL will be used when user tries to install a library from [li
#### `theme`
This prop controls Excalidraw's theme. When supplied, the value takes precedence over `intialData.appState.theme`, the theme will be fully controlled by the host app, and users won't be able to toggle it from within the app.
This prop controls Excalidraw's theme. When supplied, the value takes precedence over `intialData.appState.theme`, the theme will be fully controlled by the host app, and users won't be able to toggle it from within the app. You can use [`THEME`](#THEME-1) to specify the theme.
#### `name`
@@ -599,18 +638,14 @@ The below attributes can be set in `UIOptions.canvasActions.export` to customize
This callback is triggered if passed when something is pasted into the scene. You can use this callback in case you want to do something additional when the paste event occurs.
<pre>
(data: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/clipboard.ts#L17">ClipboardData</a>, event: ClipboardEvent &#124; null) => boolean
(data: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/clipboard.ts#L21">ClipboardData</a>, event: ClipboardEvent &#124; null) => boolean
</pre>
This callback must return a `boolean` value or a [promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise) which resolves to a boolean value.
In case you want to prevent the excalidraw paste action you must return `false`, it will stop the native excalidraw clipboard management flow (nothing will be pasted into the scene).
### Does it support collaboration ?
No, Excalidraw package doesn't come with collaboration built in, since the implementation is specific to each host app. We expose APIs which you can use to communicate with Excalidraw which you can use to implement it. You can check our own implementation [here](https://github.com/excalidraw/excalidraw/blob/master/src/excalidraw-app/index.tsx).
### importLibrary
#### `importLibrary`
Imports library from given URL. You should call this on `hashchange`, passing the `addLibrary` value if you detect it as shown below. Optionally pass a CSRF `token` to skip prompting during installation (retrievable via `token` key from the url coming from [https://libraries.excalidraw.com](https://libraries.excalidraw.com/)).
@@ -632,17 +667,17 @@ useEffect(() => {
Try out the [Demo](#Demo) to see it in action.
### detectScroll
#### `detectScroll`
Indicates whether Excalidraw should listen for `scroll` event on the nearest scrollable container in the DOM tree and recompute the coordinates (e.g. to correctly handle the cursor) when the component's position changes. You can disable this when you either know this doesn't affect your app or you want to take care of it yourself (calling the [`refresh()`](#ref) method).
### handleKeyboardGlobally
#### `handleKeyboardGlobally`
Indicates whether to bind keyboard events to `document`. Disabled by default, meaning the keyboard events are bound to the Excalidraw component. This allows for multiple Excalidraw components to live on the same page, and ensures that Excalidraw keyboard handling doesn't collide with your app's (or the browser) when the component isn't focused.
Enable this if you want Excalidraw to handle keyboard even if the component isn't focused (e.g. a user is interacting with the navbar, sidebar, or similar).
### onLibraryChange
#### `onLibraryChange`
Ths callback if supplied will get triggered when the library is updated and has the below signature.
@@ -652,58 +687,58 @@ Ths callback if supplied will get triggered when the library is updated and has
It is invoked with empty items when user clears the library. You can use this callback when you want to do something additional when library is updated for example persisting it to local storage.
### id
#### `id`
The unique id of the excalidraw component. This can be used to identify the excalidraw component, for example importing the library items to the excalidraw component from where it was initiated when you have multiple excalidraw components rendered on the same page as shown in [multiple excalidraw demo](https://codesandbox.io/s/multiple-excalidraw-k1xx5).
### autoFocus
#### `autoFocus`
This prop implies whether to focus the Excalidraw component on page load. Defaults to false.
### Extra API's
#### `generateIdForFile`
#### `getSceneVersion`
Allows you to override `id` generation for files added on canvas (images). By default, an SHA-1 digest of the file is used.
**How to use**
<pre>
import { getSceneVersion } from "@excalidraw/excalidraw";
getSceneVersion(elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>)
</pre>
This function returns the current scene version.
#### `isInvisiblySmallElement`
**_Signature_**
<pre>
isInvisiblySmallElement(element: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement</a>): boolean
</pre>
**How to use**
```js
import { isInvisiblySmallElement } from "@excalidraw/excalidraw";
```
(file: File) => string | Promise<string>
```
Returns `true` if element is invisibly small (e.g. width & height are zero).
#### `onLinkOpen`
#### `getElementMap`
This prop if passed will be triggered when clicked on link. To handle the redirect yourself (such as when using your own router for internal links), you must call `event.preventDefault()`.
**_Signature_**
<pre>
getElementsMap(elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>): {[id: string]: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement</a>}
</pre>
**How to use**
```js
import { getElementsMap } from "@excalidraw/excalidraw";
```
(element: ExcalidrawElement, event: CustomEvent<{ nativeEvent: MouseEvent }>) => void
```
This function returns an object where each element is mapped to its id.
Example:
```ts
const history = useHistory();
// open internal links using the app's router, but opens external links in
// a new tab/window
const onLinkOpen: ExcalidrawProps["onLinkOpen"] = useCallback(
(element, event) => {
const link = element.link;
const { nativeEvent } = event.detail;
const isNewTab = nativeEvent.ctrlKey || nativeEvent.metaKey;
const isNewWindow = nativeEvent.shiftKey;
const isInternalLink =
link.startsWith("/") || link.includes(window.location.origin);
if (isInternalLink && !isNewTab && !isNewWindow) {
history.push(link.replace(window.location.origin, ""));
// signal that we're handling the redirect ourselves
event.preventDefault();
}
},
[history],
);
```
### Does it support collaboration ?
No, Excalidraw package doesn't come with collaboration built in, since the implementation is specific to each host app. We expose APIs which you can use to communicate with Excalidraw which you can use to implement it. You can check our own implementation [here](https://github.com/excalidraw/excalidraw/blob/master/src/excalidraw-app/index.tsx).
### Restore utilities
@@ -761,19 +796,6 @@ import { restore } from "@excalidraw/excalidraw";
This function makes sure elements and state is set to appropriate values and set to default value if not present. It is a combination of [restoreElements](#restoreElements) and [restoreAppState](#restoreAppState).
#### `serializeAsJSON`
**_Signature_**
<pre>
serializeAsJSON({
elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>,
appState: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L42">AppState</a>,
}): string
</pre>
Takes the scene elements and state and returns a JSON string. Deleted `elements`as well as most properties from `AppState` are removed from the resulting JSON. (see [`serializeAsJSON()`](https://github.com/excalidraw/excalidraw/blob/master/src/data/json.ts#L16) source for details).
### Export utilities
#### `exportToCanvas`
@@ -785,14 +807,17 @@ Takes the scene elements and state and returns a JSON string. Deleted `elements`
elements,
appState
getDimensions,
}: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/packages/utils.ts#L10">ExportOpts</a>
files
}: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/packages/utils.ts#L12">ExportOpts</a>
</pre>
| Name | Type | Default | Description |
| --- | --- | --- | --- |
| elements | [Excalidraw Element []](https://github.com/excalidraw/excalidraw/blob/master/src/element/types) | | The elements to be exported to canvas |
| appState | [AppState](https://github.com/excalidraw/excalidraw/blob/master/src/packages/utils.ts#L12) | [defaultAppState](https://github.com/excalidraw/excalidraw/blob/master/src/appState.ts#L11) | The app state of the scene |
| getDimensions | `(width: number, height: number) => {width: number, height: number, scale: number)` | `(width, height) => ({ width, height, scale: 1 })` | A function which returns the width, height and scale with which canvas is to be exported. |
| getDimensions | `(width: number, height: number) => { width: number, height: number, scale?: number }` | undefined | A function which returns the `width`, `height`, and optionally `scale` (defaults `1`), with which canvas is to be exported. |
| maxWidthOrHeight | `number` | undefined | The maximum width or height of the exported image. If provided, `getDimensions` is ignored. |
| files | [BinaryFiles](The [`BinaryFiles`](<[BinaryFiles](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L64)>) | undefined | The files added to the scene. |
**How to use**
@@ -828,8 +853,6 @@ import { exportToBlob } from "@excalidraw/excalidraw";
Returns a promise which resolves with a [blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob). It internally uses [canvas.ToBlob](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob).
Note: `appState.exportBackground` is always set to `true` if exporting to `image/jpeg` to ensure the alpha channel isn't compressed to black.
#### `exportToSvg`
**_Signature_**
@@ -840,6 +863,7 @@ exportToSvg({
appState: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L42">AppState</a>,
exportPadding?: number,
metadata?: string,
files?: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L64">BinaryFiles</a>
})
</pre>
@@ -848,6 +872,7 @@ exportToSvg({
| elements | [Excalidraw Element []](https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78) | | The elements to exported as svg |
| appState | [AppState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L42) | [defaultAppState](https://github.com/excalidraw/excalidraw/blob/master/src/appState.ts#L11) | The app state of the scene |
| exportPadding | number | 10 | The padding to be added on canvas |
| files | [BinaryFiles](The [`BinaryFiles`](<[BinaryFiles](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L64)>) | undefined | The files added to the scene. |
This function returns a promise which resolves to svg of the exported drawing.
@@ -860,7 +885,129 @@ This function returns a promise which resolves to svg of the exported drawing.
| exportWithDarkMode | boolean | false | Indicates whether to export with dark mode |
| exportEmbedScene | boolean | false | Indicates whether scene data should be embedded in svg. This will increase the svg size. |
### FONT_FAMILY
### Extra API's
#### `serializeAsJSON`
**_Signature_**
<pre>
serializeAsJSON({
elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>,
appState: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L42">AppState</a>,
}): string
</pre>
Takes the scene elements and state and returns a JSON string. Deleted `elements`as well as most properties from `AppState` are removed from the resulting JSON. (see [`serializeAsJSON()`](https://github.com/excalidraw/excalidraw/blob/master/src/data/json.ts#L16) source for details).
#### `getSceneVersion`
**How to use**
<pre>
import { getSceneVersion } from "@excalidraw/excalidraw";
getSceneVersion(elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement[]</a>)
</pre>
This function returns the current scene version.
#### `isInvisiblySmallElement`
**_Signature_**
<pre>
isInvisiblySmallElement(element: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">ExcalidrawElement</a>): boolean
</pre>
**How to use**
```js
import { isInvisiblySmallElement } from "@excalidraw/excalidraw";
```
Returns `true` if element is invisibly small (e.g. width & height are zero).
#### `loadLibraryFromBlob`
```js
import { loadLibraryFromBlob } from "@excalidraw/excalidraw";
```
**_Signature_**
<pre>
loadLibraryFromBlob(blob: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Blob">Blob</a>)
</pre>
This function loads the library from the blob.
#### `loadFromBlob`
**How to use**
```js
import { loadFromBlob } from "@excalidraw/excalidraw";
```
**Signature**
<pre>
loadFromBlob(blob: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Blob">Blob</a>, localAppState: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L42">AppState</a> | null)
</pre>
This function loads the scene data from the blob. If you pass `localAppState`, `localAppState` value will be preferred over the `appState` derived from `blob`
#### `getFreeDrawSvgPath`
**How to use**
```js
import { getFreeDrawSvgPath } from "@excalidraw/excalidraw";
```
**Signature**
<pre>
getFreeDrawSvgPath(element: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L127">ExcalidrawFreeDrawElement</a>
</pre>
This function returns the free draw svg path for the element.
#### `isLinearElement`
**How to use**
```js
import { isLinearElement } from "@excalidraw/excalidraw";
```
**Signature**
<pre>
isLinearElement(elementType?: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L80">ExcalidrawElement</a>): boolean
</pre>
This function returns true if the element is linear type (`arrow` |`line`) else returns false.
#### `getNonDeletedElements`
**How to use**
```js
import { getNonDeletedElements } from "@excalidraw/excalidraw";
```
**Signature**
<pre>
getNonDeletedElements(elements: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L80"> readonly ExcalidrawElement[]</a>): as readonly <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L90">NonDeletedExcalidrawElement[]</a>
</pre>
This function returns an array of deleted elements.
### Exported constants
#### `FONT_FAMILY`
**How to use**
@@ -878,52 +1025,51 @@ import { FONT_FAMILY } from "@excalidraw/excalidraw";
Defaults to `FONT_FAMILY.Virgil` unless passed in `initialData.appState.currentItemFontFamily`.
### loadLibraryFromBlob
```js
import { loadLibraryFromBlob } from "@excalidraw/excalidraw";
```
**_Signature_**
<pre>
loadLibraryFromBlob(blob: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Blob">Blob</a>)
</pre>
This function loads the library from the blob.
### loadFromBlob
#### `THEME`
**How to use**
```js
import { loadFromBlob } from "@excalidraw/excalidraw";
import { THEME } from "@excalidraw/excalidraw";
```
**Signature**
`THEME` contains all the themes supported by `Excalidraw` as explained below
<pre>
loadFromBlob(blob: <a href="https://developer.mozilla.org/en-US/docs/Web/API/Blob">Blob</a>, localAppState: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L42">AppState</a> | null)
</pre>
| Theme | Description |
| ----- | --------------- |
| LIGHT | The light theme |
| DARK | The Dark theme |
This function loads the scene data from the blob. If you pass `localAppState`, `localAppState` value will be preferred over the `appState` derived from `blob`
### getFreeDrawSvgPath
**How to use**
```js
import { getFreeDrawSvgPath } from "@excalidraw/excalidraw";
```
**Signature**
<pre>
getFreeDrawSvgPath(element: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L127">ExcalidrawFreeDrawElement</a>
</pre>
This function returns the free draw svg path for the element.
Defaults to `THEME.LIGHT` unless passed in `initialData.appState.theme`
## Need help?
Check out the existing [Q&A](https://github.com/excalidraw/excalidraw/discussions?discussions_q=label%3Apackage%3Aexcalidraw). If you have any queries or need help, ask us [here](https://github.com/excalidraw/excalidraw/discussions?discussions_q=label%3Apackage%3Aexcalidraw).
### Development
#### Install the dependencies
```bash
yarn
```
#### Start the server
```bash
yarn start
```
[http://localhost:3001](http://localhost:3001) will open in your default browser.
The example is same as the [codesandbox example](https://ehlz3.csb.app/)
#### Create a test release
You can create a test release by posting the below comment in your pull request
```
@excalibot release package
```
Once the version is released `@excalibot` will post a comment with the release version.
+59 -7
View File
@@ -374,7 +374,7 @@ Most notably, you can customize the primary colors, by overriding these variable
- `--color-primary-darker`
- `--color-primary-darkest`
- `--color-primary-light`
- `--color-primary-chubb` — a slightly darker (in light mode), or lighter (in dark mode) `--color-primary` color to account for [Chubb illusion](https://en.wikipedia.org/wiki/Chubb_illusion).
- `--color-primary-contrast-offset` — a slightly darker (in light mode), or lighter (in dark mode) `--color-primary` color to fix contrast issues (see [Chubb illusion](https://en.wikipedia.org/wiki/Chubb_illusion)). It will fall back to `--color-primary` if not present.
For a complete list of variables, check [theme.scss](https://github.com/excalidraw/excalidraw/blob/master/src/css/theme.scss), though most of them will not make sense to override.
@@ -399,12 +399,13 @@ For a complete list of variables, check [theme.scss](https://github.com/excalidr
| [`theme`](#theme) | [THEME.LIGHT](#THEME-1) &#124; [THEME.LIGHT](#THEME-1) | [THEME.LIGHT](#THEME-1) | The theme of the Excalidraw component |
| [`name`](#name) | string | | Name of the drawing |
| [`UIOptions`](#UIOptions) | <pre>{ canvasActions: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L208"> CanvasActions<a/> }</pre> | [DEFAULT UI OPTIONS](https://github.com/excalidraw/excalidraw/blob/master/src/constants.ts#L129) | To customise UI options. Currently we support customising [`canvas actions`](#canvasActions) |
| [`onPaste`](#onPaste) | <pre>(data: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/clipboard.ts#L17">ClipboardData</a>, event: ClipboardEvent &#124; null) => boolean</pre> | | Callback to be triggered if passed when the something is pasted in to the scene |
| [`onPaste`](#onPaste) | <pre>(data: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/clipboard.ts#L21">ClipboardData</a>, event: ClipboardEvent &#124; null) => boolean</pre> | | Callback to be triggered if passed when the something is pasted in to the scene |
| [`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. |
| [`onLibraryChange`](#onLibraryChange) | <pre>(items: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L200">LibraryItems</a>) => void &#124; Promise&lt;any&gt; </pre> | | The callback if supplied is triggered when the library is updated and receives the library items. |
| [`autoFocus`](#autoFocus) | boolean | false | Implies whether to focus the Excalidraw component on page load |
| [`generateIdForFile`](#generateIdForFile) | `(file: File) => string | Promise<string>` | Allows you to override `id` generation for files added on canvas |
| [`onLinkOpen`](#onLinkOpen) | <pre>(element: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78">NonDeletedExcalidrawElement</a>, event: CustomEvent) </pre> | | This prop if passed will be triggered when link of an element is clicked |
### Dimensions of Excalidraw
@@ -415,12 +416,14 @@ Excalidraw takes `100%` of `width` and `height` of the containing block so make
Every time component updates, this callback if passed will get triggered and has the below signature.
```js
(excalidrawElements, appState) => void;
(excalidrawElements, appState, files) => void;
```
1.`excalidrawElements`: Array of [excalidrawElements](https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78) in the scene.
2.`appState`: [AppState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L42) of the scene
2.`appState`: [AppState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L42) of the scene.
3. `files`: The [`BinaryFiles`]([BinaryFiles](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L64) which are added to the scene.
Here you can try saving the data to your backend or local storage for example.
@@ -434,6 +437,7 @@ This helps to load Excalidraw with `initialData`. It must be an object or a [pro
| `appState` | [AppState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L42) | The App state with which Excalidraw should be mounted. |
| `scrollToContent` | boolean | This attribute implies 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#L151) | This library items with which Excalidraw should be mounted. |
| `files` | [BinaryFiles](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L64) | The files added to the scene. |
```json
{
@@ -486,6 +490,7 @@ You can pass a `ref` when you want to access some excalidraw APIs. We expose the
| [importLibrary](#importlibrary) | `(url: string, token?: string) => void` | Imports library from given URL |
| setToastMessage | `(message: string) => void` | This API can be used to show the toast with custom message. |
| [id](#id) | string | Unique ID for the excalidraw component. |
| [getFiles](#getFiles) | <pre>() => <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L64">files</a> </pre> | This API can be used to get the files present in the scene. It may contain files that aren't referenced by any element, so if you're persisting the files to a storage, you should compare them against stored elements. |
#### `readyPromise`
@@ -515,7 +520,7 @@ You can use this function to update the scene with the sceneData. It accepts the
<pre>(files: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts">BinaryFileData</a>) => void </pre>
Adds supplied files data to the `appState.files` cache, on top of existing files present in the cache.
Adds supplied files data to the `appState.files` cache on top of existing files present in the cache.
#### `onCollabButtonClick`
@@ -639,7 +644,7 @@ The below attributes can be set in `UIOptions.canvasActions.export` to customize
This callback is triggered if passed when something is pasted into the scene. You can use this callback in case you want to do something additional when the paste event occurs.
<pre>
(data: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/clipboard.ts#L17">ClipboardData</a>, event: ClipboardEvent &#124; null) => boolean
(data: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/clipboard.ts#L21">ClipboardData</a>, event: ClipboardEvent &#124; null) => boolean
</pre>
This callback must return a `boolean` value or a [promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise) which resolves to a boolean value.
@@ -704,6 +709,39 @@ Allows you to override `id` generation for files added on canvas (images). By de
(file: File) => string | Promise<string>
```
#### `onLinkOpen`
This prop if passed will be triggered when clicked on link. To handle the redirect yourself (such as when using your own router for internal links), you must call `event.preventDefault()`.
```
(element: ExcalidrawElement, event: CustomEvent<{ nativeEvent: MouseEvent }>) => void
```
Example:
```ts
const history = useHistory();
// open internal links using the app's router, but opens external links in
// a new tab/window
const onLinkOpen: ExcalidrawProps["onLinkOpen"] = useCallback(
(element, event) => {
const link = element.link;
const { nativeEvent } = event.detail;
const isNewTab = nativeEvent.ctrlKey || nativeEvent.metaKey;
const isNewWindow = nativeEvent.shiftKey;
const isInternalLink =
link.startsWith("/") || link.includes(window.location.origin);
if (isInternalLink && !isNewTab && !isNewWindow) {
history.push(link.replace(window.location.origin, ""));
// signal that we're handling the redirect ourselves
event.preventDefault();
}
},
[history],
);
```
### Does it support collaboration ?
No, Excalidraw package doesn't come with collaboration built in, since the implementation is specific to each host app. We expose APIs which you can use to communicate with Excalidraw which you can use to implement it. You can check our own implementation [here](https://github.com/excalidraw/excalidraw/blob/master/src/excalidraw-app/index.tsx).
@@ -775,7 +813,8 @@ This function makes sure elements and state is set to appropriate values and set
elements,
appState
getDimensions,
}: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/packages/utils.ts#L10">ExportOpts</a>
files
}: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/packages/utils.ts#L12">ExportOpts</a>
</pre>
| Name | Type | Default | Description |
@@ -784,6 +823,7 @@ This function makes sure elements and state is set to appropriate values and set
| appState | [AppState](https://github.com/excalidraw/excalidraw/blob/master/src/packages/utils.ts#L12) | [defaultAppState](https://github.com/excalidraw/excalidraw/blob/master/src/appState.ts#L11) | The app state of the scene |
| getDimensions | `(width: number, height: number) => { width: number, height: number, scale?: number }` | undefined | A function which returns the `width`, `height`, and optionally `scale` (defaults `1`), with which canvas is to be exported. |
| maxWidthOrHeight | `number` | undefined | The maximum width or height of the exported image. If provided, `getDimensions` is ignored. |
| files | [BinaryFiles](The [`BinaryFiles`](<[BinaryFiles](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L64)>) | undefined | The files added to the scene. |
**How to use**
@@ -829,6 +869,7 @@ exportToSvg({
appState: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L42">AppState</a>,
exportPadding?: number,
metadata?: string,
files?: <a href="https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L64">BinaryFiles</a>
})
</pre>
@@ -837,6 +878,7 @@ exportToSvg({
| elements | [Excalidraw Element []](https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78) | | The elements to exported as svg |
| appState | [AppState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L42) | [defaultAppState](https://github.com/excalidraw/excalidraw/blob/master/src/appState.ts#L11) | The app state of the scene |
| exportPadding | number | 10 | The padding to be added on canvas |
| files | [BinaryFiles](The [`BinaryFiles`](<[BinaryFiles](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L64)>) | undefined | The files added to the scene. |
This function returns a promise which resolves to svg of the exported drawing.
@@ -1027,3 +1069,13 @@ yarn start
[http://localhost:3001](http://localhost:3001) will open in your default browser.
The example is same as the [codesandbox example](https://ehlz3.csb.app/)
#### Create a test release
You can create a test release by posting the below comment in your pull request
```
@excalibot release package
```
Once the version is released `@excalibot` will post a comment with the release version.
+62 -16
View File
@@ -1,16 +1,29 @@
import { useEffect, useState, useRef } from "react";
import { useEffect, useState, useRef, useCallback } from "react";
import InitialData from "./initialData";
import Sidebar from "./sidebar/Sidebar";
import "./App.scss";
import initialData from "./initialData";
import { MIME_TYPES } from "../../../constants";
// This is so that we use the bundled excalidraw.developement.js file instead
// of the actual source code
const { exportToCanvas, exportToSvg, exportToBlob } = window.Excalidraw;
const Excalidraw = window.Excalidraw.default;
const resolvablePromise = () => {
let resolve;
let reject;
const promise = new Promise((_resolve, _reject) => {
resolve = _resolve;
reject = _reject;
});
promise.resolve = resolve;
promise.reject = reject;
return promise;
};
const renderTopRightUI = () => {
return (
<button onClick={() => alert("This is dummy top right UI")}>
@@ -38,10 +51,35 @@ export default function App() {
const [blobUrl, setBlobUrl] = useState(null);
const [canvasUrl, setCanvasUrl] = useState(null);
const [exportWithDarkMode, setExportWithDarkMode] = useState(false);
const [shouldAddWatermark, setShouldAddWatermark] = useState(false);
const [theme, setTheme] = useState("light");
const initialStatePromiseRef = useRef({ promise: null });
if (!initialStatePromiseRef.current.promise) {
initialStatePromiseRef.current.promise = resolvablePromise();
}
useEffect(() => {
const fetchData = async () => {
const res = await fetch("/rocket.jpeg");
const imageData = await res.blob();
const reader = new FileReader();
reader.readAsDataURL(imageData);
reader.onload = function () {
const imagesArray = [
{
id: "rocket",
dataURL: reader.result,
mimeType: MIME_TYPES.jpg,
created: 1644915140367,
},
];
initialStatePromiseRef.current.promise.resolve(InitialData);
excalidrawRef.current.addFiles(imagesArray);
};
};
fetchData();
const onHashChange = () => {
const hash = new URLSearchParams(window.location.hash.slice(1));
const libraryUrl = hash.get("addLibrary");
@@ -87,6 +125,21 @@ export default function App() {
excalidrawRef.current.updateScene(sceneData);
};
const onLinkOpen = useCallback((element, event) => {
const link = element.link;
const { nativeEvent } = event.detail;
const isNewTab = nativeEvent.ctrlKey || nativeEvent.metaKey;
const isNewWindow = nativeEvent.shiftKey;
const isInternalLink =
link.startsWith("/") || link.includes(window.location.origin);
if (isInternalLink && !isNewTab && !isNewWindow) {
// signal that we're handling the redirect ourselves
event.preventDefault();
// do a custom redirect, such as passing to react-router
// ...
}
}, []);
return (
<div className="App">
<h1> Excalidraw Example</h1>
@@ -163,7 +216,7 @@ export default function App() {
<div className="excalidraw-wrapper">
<Excalidraw
ref={excalidrawRef}
initialData={InitialData}
initialData={initialStatePromiseRef.current.promise}
onChange={(elements, state) =>
console.info("Elements :", elements, "State : ", state)
}
@@ -179,6 +232,7 @@ export default function App() {
UIOptions={{ canvasActions: { loadScene: false } }}
renderTopRightUI={renderTopRightUI}
renderFooter={renderFooter}
onLinkOpen={onLinkOpen}
/>
</div>
@@ -191,14 +245,6 @@ export default function App() {
/>
Export with dark mode
</label>
<label className="export-wrapper__checkbox">
<input
type="checkbox"
checked={shouldAddWatermark}
onChange={() => setShouldAddWatermark(!shouldAddWatermark)}
/>
Add Watermark
</label>
<button
onClick={async () => {
const svg = await exportToSvg({
@@ -206,11 +252,11 @@ export default function App() {
appState: {
...initialData.appState,
exportWithDarkMode,
shouldAddWatermark,
width: 300,
height: 100,
},
embedScene: true,
files: excalidrawRef.current.getFiles(),
});
document.querySelector(".export-svg").innerHTML = svg.outerHTML;
}}
@@ -227,8 +273,8 @@ export default function App() {
appState: {
...initialData.appState,
exportWithDarkMode,
shouldAddWatermark,
},
files: excalidrawRef.current.getFiles(),
});
setBlobUrl(window.URL.createObjectURL(blob));
}}
@@ -240,14 +286,14 @@ export default function App() {
</div>
<button
onClick={() => {
const canvas = exportToCanvas({
onClick={async () => {
const canvas = await exportToCanvas({
elements: excalidrawRef.current.getSceneElements(),
appState: {
...initialData.appState,
exportWithDarkMode,
shouldAddWatermark,
},
files: excalidrawRef.current.getFiles(),
});
const ctx = canvas.getContext("2d");
ctx.font = "30px Virgil";
+7
View File
@@ -40,3 +40,10 @@
display: flex;
}
}
.excalidraw {
--color-primary: #faa2c1;
--color-primary-darker: #f783ac;
--color-primary-darkest: #e64980;
--color-primary-light: #fcc2d7;
}
@@ -42,6 +42,33 @@ export default {
versionNonce: 1128618623,
isDeleted: false,
},
{
fileId: "rocket",
type: "image",
x: 606.1042326312408,
y: 153.57729779411773,
width: 231.30325348751828,
height: 231.64340533088227,
angle: 0,
strokeColor: "transparent",
backgroundColor: "transparent",
fillStyle: "hachure",
strokeWidth: 1,
strokeStyle: "solid",
roughness: 1,
opacity: 100,
groupIds: [],
strokeSharpness: "round",
seed: 707269846,
version: 143,
versionNonce: 2028982666,
isDeleted: false,
boundElements: null,
updated: 1644914782403,
link: null,
status: "pending",
scale: [1, 1],
},
],
appState: { viewBackgroundColor: "#AFEEEE", currentItemFontFamily: 1 },
scrollToContent: true,
Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

+2
View File
@@ -35,6 +35,7 @@ const Excalidraw = (props: ExcalidrawProps) => {
onLibraryChange,
autoFocus = false,
generateIdForFile,
onLinkOpen,
} = props;
const canvasActions = props.UIOptions?.canvasActions;
@@ -96,6 +97,7 @@ const Excalidraw = (props: ExcalidrawProps) => {
onLibraryChange={onLibraryChange}
autoFocus={autoFocus}
generateIdForFile={generateIdForFile}
onLinkOpen={onLinkOpen}
/>
</InitializeApp>
);
+9 -7
View File
@@ -1,6 +1,6 @@
{
"name": "@excalidraw/excalidraw",
"version": "0.10.0",
"version": "0.11.0",
"main": "main.js",
"types": "types/packages/excalidraw/index.d.ts",
"files": [
@@ -44,7 +44,7 @@
"react-dom": "^17.0.2"
},
"devDependencies": {
"@babel/core": "7.16.7",
"@babel/core": "7.17.0",
"@babel/plugin-transform-arrow-functions": "7.16.7",
"@babel/plugin-transform-async-to-generator": "7.16.0",
"@babel/plugin-transform-runtime": "7.16.8",
@@ -56,17 +56,17 @@
"babel-loader": "8.2.3",
"babel-plugin-transform-class-properties": "6.24.1",
"cross-env": "7.0.3",
"css-loader": "6.5.1",
"css-loader": "6.6.0",
"mini-css-extract-plugin": "2.4.6",
"postcss-loader": "6.2.1",
"sass-loader": "12.4.0",
"terser-webpack-plugin": "5.3.0",
"terser-webpack-plugin": "5.3.1",
"ts-loader": "9.2.6",
"typescript": "4.5.4",
"webpack": "5.65.0",
"webpack-bundle-analyzer": "4.5.0",
"webpack-cli": "4.9.1",
"webpack-dev-server": "4.7.3",
"webpack-cli": "4.9.2",
"webpack-dev-server": "4.7.4",
"webpack-merge": "5.8.0"
},
"bugs": "https://github.com/excalidraw/excalidraw/issues",
@@ -76,7 +76,9 @@
"build:umd": "rm -rf dist && cross-env NODE_ENV=production webpack --config webpack.prod.config.js && cross-env NODE_ENV=development webpack --config webpack.dev.config.js && yarn gen:types",
"build:umd:withAnalyzer": "cross-env NODE_ENV=production ANALYZER=true webpack --config webpack.prod.config.js",
"pack": "yarn build:umd && yarn pack",
"start": "webpack serve --config webpack.dev-server.config.js "
"start": "webpack serve --config webpack.dev-server.config.js",
"install:deps": "yarn install --frozen-lockfile && yarn --cwd ../../../",
"build:example": "EXAMPLE=true webpack --config webpack.dev-server.config.js"
},
"dependencies": {
"dotenv": "10.0.0"
@@ -14,7 +14,7 @@ const devServerConfig = {
hot: true,
compress: true,
static: {
directory: path.join(__dirname, "example"),
directory: path.join(__dirname, "./example/public"),
},
client: {
progress: true,
@@ -3,6 +3,7 @@ const webpack = require("webpack");
const autoprefixer = require("autoprefixer");
const { parseEnvVariables } = require("./env");
const outputDir = process.env.EXAMPLE === "true" ? "example/public" : "dist";
module.exports = {
mode: "development",
devtool: false,
@@ -10,7 +11,7 @@ module.exports = {
"excalidraw.development": "./entry.js",
},
output: {
path: path.resolve(__dirname, "dist"),
path: path.resolve(__dirname, outputDir),
library: "Excalidraw",
libraryTarget: "umd",
filename: "[name].js",
+138 -124
View File
@@ -2,6 +2,14 @@
# yarn lockfile v1
"@ampproject/remapping@^2.0.0":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.0.3.tgz#899999b5b7a5ce570d6d9bafdcc1e62cea466cf3"
integrity sha512-DmIAguV77yFP0MGVFWknCMgSLAtsLR3VlRTteR6xgMpIfYtwaZuMvjGv5YlpiqN7S/5q87DHyuIx8oa15kiyag==
dependencies:
"@jridgewell/sourcemap-codec" "^1.4.9"
"@jridgewell/trace-mapping" "^0.2.7"
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789"
@@ -14,33 +22,33 @@
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.4.tgz#081d6bbc336ec5c2435c6346b2ae1fb98b5ac68e"
integrity sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==
"@babel/core@7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.7.tgz#db990f931f6d40cb9b87a0dc7d2adc749f1dcbcf"
integrity sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==
"@babel/core@7.17.0":
version "7.17.0"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.0.tgz#16b8772b0a567f215839f689c5ded6bb20e864d5"
integrity sha512-x/5Ea+RO5MvF9ize5DeVICJoVrNv0Mi2RnIABrZEKYvPEpldXwauPkgvYA17cKa6WpU3LoYvYbuEMFtSNFsarA==
dependencies:
"@ampproject/remapping" "^2.0.0"
"@babel/code-frame" "^7.16.7"
"@babel/generator" "^7.16.7"
"@babel/generator" "^7.17.0"
"@babel/helper-compilation-targets" "^7.16.7"
"@babel/helper-module-transforms" "^7.16.7"
"@babel/helpers" "^7.16.7"
"@babel/parser" "^7.16.7"
"@babel/helpers" "^7.17.0"
"@babel/parser" "^7.17.0"
"@babel/template" "^7.16.7"
"@babel/traverse" "^7.16.7"
"@babel/types" "^7.16.7"
"@babel/traverse" "^7.17.0"
"@babel/types" "^7.17.0"
convert-source-map "^1.7.0"
debug "^4.1.0"
gensync "^1.0.0-beta.2"
json5 "^2.1.2"
semver "^6.3.0"
source-map "^0.5.0"
"@babel/generator@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.7.tgz#b42bf46a3079fa65e1544135f32e7958f048adbb"
integrity sha512-/ST3Sg8MLGY5HVYmrjOgL60ENux/HfO/CsUh7y4MalThufhE/Ff/6EibFDHi4jiDCaWfJKoqbE6oTh21c5hrRg==
"@babel/generator@^7.17.0":
version "7.17.0"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.0.tgz#7bd890ba706cd86d3e2f727322346ffdbf98f65e"
integrity sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw==
dependencies:
"@babel/types" "^7.16.7"
"@babel/types" "^7.17.0"
jsesc "^2.5.1"
source-map "^0.5.0"
@@ -327,14 +335,14 @@
"@babel/traverse" "^7.16.7"
"@babel/types" "^7.16.7"
"@babel/helpers@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.7.tgz#7e3504d708d50344112767c3542fc5e357fffefc"
integrity sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==
"@babel/helpers@^7.17.0":
version "7.17.0"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.0.tgz#79cdf6c66a579f3a7b5e739371bc63ca0306886b"
integrity sha512-Xe/9NFxjPwELUvW2dsukcMZIp6XwPSbI4ojFBJuX5ramHuVE22SVcZIwqzdWo5uCgeTXW8qV97lMvSOjq+1+nQ==
dependencies:
"@babel/template" "^7.16.7"
"@babel/traverse" "^7.16.7"
"@babel/types" "^7.16.7"
"@babel/traverse" "^7.17.0"
"@babel/types" "^7.17.0"
"@babel/highlight@^7.16.7":
version "7.16.7"
@@ -345,10 +353,10 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
"@babel/parser@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.7.tgz#d372dda9c89fcec340a82630a9f533f2fe15877e"
integrity sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA==
"@babel/parser@^7.16.7", "@babel/parser@^7.17.0":
version "7.17.0"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.0.tgz#f0ac33eddbe214e4105363bb17c3341c5ffcc43c"
integrity sha512-VKXSCQx5D8S04ej+Dqsr1CzYvvWgf20jIw2D+YhQCrIlr2UZGaDds23Y0xg75/skOxpLCRpUZvk/1EAVkGoDOw==
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7":
version "7.16.7"
@@ -1063,26 +1071,26 @@
"@babel/parser" "^7.16.7"
"@babel/types" "^7.16.7"
"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.0", "@babel/traverse@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.7.tgz#dac01236a72c2560073658dd1a285fe4e0865d76"
integrity sha512-8KWJPIb8c2VvY8AJrydh6+fVRo2ODx1wYBU2398xJVq0JomuLBZmVQzLPBblJgHIGYG4znCpUZUZ0Pt2vdmVYQ==
"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.17.0":
version "7.17.0"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.0.tgz#3143e5066796408ccc880a33ecd3184f3e75cd30"
integrity sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg==
dependencies:
"@babel/code-frame" "^7.16.7"
"@babel/generator" "^7.16.7"
"@babel/generator" "^7.17.0"
"@babel/helper-environment-visitor" "^7.16.7"
"@babel/helper-function-name" "^7.16.7"
"@babel/helper-hoist-variables" "^7.16.7"
"@babel/helper-split-export-declaration" "^7.16.7"
"@babel/parser" "^7.16.7"
"@babel/types" "^7.16.7"
"@babel/parser" "^7.17.0"
"@babel/types" "^7.17.0"
debug "^4.1.0"
globals "^11.1.0"
"@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.4.4":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.7.tgz#4ed19d51f840ed4bd5645be6ce40775fecf03159"
integrity sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg==
"@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.17.0", "@babel/types@^7.4.4":
version "7.17.0"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b"
integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==
dependencies:
"@babel/helper-validator-identifier" "^7.16.7"
to-fast-properties "^2.0.0"
@@ -1092,6 +1100,24 @@
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz#8f03a22a04de437254e8ce8cc84ba39689288752"
integrity sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg==
"@jridgewell/resolve-uri@^3.0.3":
version "3.0.4"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.4.tgz#b876e3feefb9c8d3aa84014da28b5e52a0640d72"
integrity sha512-cz8HFjOFfUBtvN+NXYSFMHYRdxZMaEl0XypVrhzxBgadKIXhIkRd8aMeHhmF56Sl7SuS8OnUpQ73/k9LE4VnLg==
"@jridgewell/sourcemap-codec@^1.4.9":
version "1.4.10"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.10.tgz#baf57b4e2a690d4f38560171f91783656b7f8186"
integrity sha512-Ht8wIW5v165atIX1p+JvKR5ONzUyF4Ac8DZIQ5kZs9zrb6M8SJNXpx1zn04rn65VjBMygRoMXcyYwNK0fT7bEg==
"@jridgewell/trace-mapping@^0.2.7":
version "0.2.7"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.2.7.tgz#d45be64544788e32c7ea5c8faa16a7000d840b5b"
integrity sha512-ZKfRhw6eK2vvdWqpU7DQq49+BZESqh5rmkYpNhuzkz01tapssl2sNNy6uMUIgrTtUWQDijomWJzJRCoevVrfgw==
dependencies:
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.9"
"@nodelib/fs.scandir@2.1.5":
version "2.1.5"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
@@ -1178,7 +1204,7 @@
"@types/qs" "*"
"@types/range-parser" "*"
"@types/express@*":
"@types/express@*", "@types/express@^4.17.13":
version "4.17.13"
resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.13.tgz#a76e2995728999bab51a33fabce1d705a3709034"
integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==
@@ -1390,22 +1416,22 @@
"@webassemblyjs/ast" "1.11.1"
"@xtuc/long" "4.2.2"
"@webpack-cli/configtest@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.1.0.tgz#8342bef0badfb7dfd3b576f2574ab80c725be043"
integrity sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg==
"@webpack-cli/configtest@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.1.1.tgz#9f53b1b7946a6efc2a749095a4f450e2932e8356"
integrity sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==
"@webpack-cli/info@^1.4.0":
version "1.4.0"
resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.4.0.tgz#b9179c3227ab09cbbb149aa733475fcf99430223"
integrity sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw==
"@webpack-cli/info@^1.4.1":
version "1.4.1"
resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.4.1.tgz#2360ea1710cbbb97ff156a3f0f24556e0fc1ebea"
integrity sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA==
dependencies:
envinfo "^7.7.3"
"@webpack-cli/serve@^1.6.0":
version "1.6.0"
resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.6.0.tgz#2c275aa05c895eccebbfc34cfb223c6e8bd591a2"
integrity sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA==
"@webpack-cli/serve@^1.6.1":
version "1.6.1"
resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.6.1.tgz#0de2875ac31b46b6c5bb1ae0a7d7f0ba5678dffe"
integrity sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==
"@xtuc/ieee754@^1.2.0":
version "1.2.0"
@@ -1851,10 +1877,10 @@ chalk@^4.1.0:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
chokidar@^3.5.2:
version "3.5.2"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75"
integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==
chokidar@^3.5.3:
version "3.5.3"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
dependencies:
anymatch "~3.1.2"
braces "~3.0.2"
@@ -1911,11 +1937,6 @@ color-name@~1.1.4:
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
colorette@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
colorette@^2.0.10, colorette@^2.0.14:
version "2.0.16"
resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da"
@@ -2048,18 +2069,18 @@ cross-spawn@^7.0.1, cross-spawn@^7.0.3:
shebang-command "^2.0.0"
which "^2.0.1"
css-loader@6.5.1:
version "6.5.1"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.5.1.tgz#0c43d4fbe0d97f699c91e9818cb585759091d1b1"
integrity sha512-gEy2w9AnJNnD9Kuo4XAP9VflW/ujKoS9c/syO+uWMlm5igc7LysKzPXaDoR2vroROkSwsTS2tGr1yGGEbZOYZQ==
css-loader@6.6.0:
version "6.6.0"
resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-6.6.0.tgz#c792ad5510bd1712618b49381bd0310574fafbd3"
integrity sha512-FK7H2lisOixPT406s5gZM1S3l8GrfhEBT3ZiL2UX1Ng1XWs0y2GPllz/OTyvbaHe12VgQrIXIzuEGVlbUhodqg==
dependencies:
icss-utils "^5.1.0"
postcss "^8.2.15"
postcss "^8.4.5"
postcss-modules-extract-imports "^3.0.0"
postcss-modules-local-by-default "^4.0.0"
postcss-modules-scope "^3.0.0"
postcss-modules-values "^4.0.0"
postcss-value-parser "^4.1.0"
postcss-value-parser "^4.2.0"
semver "^7.3.5"
cssesc@^3.0.0:
@@ -2419,9 +2440,9 @@ find-up@^4.0.0:
path-exists "^4.0.0"
follow-redirects@^1.0.0:
version "1.14.7"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685"
integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==
version "1.14.8"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc"
integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==
forwarded@0.2.0:
version "0.2.0"
@@ -2853,10 +2874,10 @@ isobject@^3.0.1:
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
jest-worker@^27.4.1:
version "27.4.5"
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.5.tgz#d696e3e46ae0f24cff3fa7195ffba22889262242"
integrity sha512-f2s8kEdy15cv9r7q4KkzGXvlY0JTcmCbMHZBfSQDwW77REr45IDWwd0lksDFeVHH2jJ5pqb90T77XscrjeGzzg==
jest-worker@^27.4.5:
version "27.5.0"
resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.0.tgz#99ee77e4d06168107c27328bd7f54e74c3a48d59"
integrity sha512-8OEHiPNOPTfaWnJ2SUHM8fmgeGq37uuGsQBvGKQJl1f+6WIy6g7G3fE2ruI5294bUKUI9FaCWt5hDvO8HSwsSg==
dependencies:
"@types/node" "*"
merge-stream "^2.0.0"
@@ -2988,10 +3009,10 @@ media-typer@0.3.0:
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
memfs@^3.2.2:
version "3.4.0"
resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.4.0.tgz#8bc12062b973be6b295d4340595736a656f0a257"
integrity sha512-o/RfP0J1d03YwsAxyHxAYs2kyJp55AFkMazlFAZFR2I2IXkxiUTXRabJ6RmNNCQ83LAD2jy52Khj0m3OffpNdA==
memfs@^3.4.1:
version "3.4.1"
resolved "https://registry.yarnpkg.com/memfs/-/memfs-3.4.1.tgz#b78092f466a0dce054d63d39275b24c71d3f1305"
integrity sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw==
dependencies:
fs-monkey "1.0.3"
@@ -3129,7 +3150,7 @@ multicast-dns@^6.0.1:
dns-packet "^1.3.1"
thunky "^1.0.2"
nanoid@^3.1.23:
nanoid@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.2.0.tgz#62667522da6673971cca916a6d3eff3f415ff80c"
integrity sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==
@@ -3408,14 +3429,14 @@ postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0:
resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
postcss@^8.2.15:
version "8.3.0"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.0.tgz#b1a713f6172ca427e3f05ef1303de8b65683325f"
integrity sha512-+ogXpdAjWGa+fdYY5BQ96V/6tAo+TdSSIMP5huJBIygdWwKtVoB5JWZ7yUd4xZ8r+8Kvvx4nyg/PQ071H4UtcQ==
postcss@^8.4.5:
version "8.4.6"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.6.tgz#c5ff3c3c457a23864f32cb45ac9b741498a09ae1"
integrity sha512-OovjwIzs9Te46vlEx7+uXB0PLijpwjXGKXjVGGPIGubGpq7uh5Xgf6D6FiJ/SzJMBosHDp6a2hiXOS97iBXcaA==
dependencies:
colorette "^1.2.2"
nanoid "^3.1.23"
source-map-js "^0.6.2"
nanoid "^3.2.0"
picocolors "^1.0.0"
source-map-js "^1.0.2"
process-nextick-args@~2.0.0:
version "2.0.1"
@@ -3809,10 +3830,10 @@ sockjs@^0.3.21:
uuid "^8.3.2"
websocket-driver "^0.7.4"
source-map-js@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e"
integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==
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==
source-map-support@~0.5.20:
version "0.5.20"
@@ -3929,12 +3950,12 @@ tapable@^2.1.1, tapable@^2.2.0:
resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.0.tgz#5c373d281d9c672848213d0e037d1c4165ab426b"
integrity sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==
terser-webpack-plugin@5.3.0, terser-webpack-plugin@^5.1.3:
version "5.3.0"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.0.tgz#21641326486ecf91d8054161c816e464435bae9f"
integrity sha512-LPIisi3Ol4chwAaPP8toUJ3L4qCM1G0wao7L3qNv57Drezxj6+VEyySpPw4B1HSO2Eg/hDY/MNF5XihCAoqnsQ==
terser-webpack-plugin@5.3.1, terser-webpack-plugin@^5.1.3:
version "5.3.1"
resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz#0320dcc270ad5372c1e8993fabbd927929773e54"
integrity sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==
dependencies:
jest-worker "^27.4.1"
jest-worker "^27.4.5"
schema-utils "^3.1.1"
serialize-javascript "^6.0.0"
source-map "^0.6.1"
@@ -4099,15 +4120,15 @@ webpack-bundle-analyzer@4.5.0:
sirv "^1.0.7"
ws "^7.3.1"
webpack-cli@4.9.1:
version "4.9.1"
resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.9.1.tgz#b64be825e2d1b130f285c314caa3b1ba9a4632b3"
integrity sha512-JYRFVuyFpzDxMDB+v/nanUdQYcZtqFPGzmlW4s+UkPMFhSpfRNmf1z4AwYcHJVdvEFAM7FFCQdNTpsBYhDLusQ==
webpack-cli@4.9.2:
version "4.9.2"
resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.9.2.tgz#77c1adaea020c3f9e2db8aad8ea78d235c83659d"
integrity sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ==
dependencies:
"@discoveryjs/json-ext" "^0.5.0"
"@webpack-cli/configtest" "^1.1.0"
"@webpack-cli/info" "^1.4.0"
"@webpack-cli/serve" "^1.6.0"
"@webpack-cli/configtest" "^1.1.1"
"@webpack-cli/info" "^1.4.1"
"@webpack-cli/serve" "^1.6.1"
colorette "^2.0.14"
commander "^7.0.0"
execa "^5.0.0"
@@ -4117,30 +4138,31 @@ webpack-cli@4.9.1:
rechoir "^0.7.0"
webpack-merge "^5.7.3"
webpack-dev-middleware@^5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.0.tgz#8fc02dba6e72e1d373eca361623d84610f27be7c"
integrity sha512-MouJz+rXAm9B1OTOYaJnn6rtD/lWZPy2ufQCH3BPs8Rloh/Du6Jze4p7AeLYHkVi0giJnYLaSGDC7S+GM9arhg==
webpack-dev-middleware@^5.3.1:
version "5.3.1"
resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-5.3.1.tgz#aa079a8dedd7e58bfeab358a9af7dab304cee57f"
integrity sha512-81EujCKkyles2wphtdrnPg/QqegC/AtqNH//mQkBYSMqwFVCQrxM6ktB2O/SPlZy7LqeEfTbV3cZARGQz6umhg==
dependencies:
colorette "^2.0.10"
memfs "^3.2.2"
memfs "^3.4.1"
mime-types "^2.1.31"
range-parser "^1.2.1"
schema-utils "^4.0.0"
webpack-dev-server@4.7.3:
version "4.7.3"
resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.7.3.tgz#4e995b141ff51fa499906eebc7906f6925d0beaa"
integrity sha512-mlxq2AsIw2ag016nixkzUkdyOE8ST2GTy34uKSABp1c4nhjZvH90D5ZRR+UOLSsG4Z3TFahAi72a3ymRtfRm+Q==
webpack-dev-server@4.7.4:
version "4.7.4"
resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-4.7.4.tgz#d0ef7da78224578384e795ac228d8efb63d5f945"
integrity sha512-nfdsb02Zi2qzkNmgtZjkrMOcXnYZ6FLKcQwpxT7MvmHKc+oTtDsBju8j+NMyAygZ9GW1jMEUpy3itHtqgEhe1A==
dependencies:
"@types/bonjour" "^3.5.9"
"@types/connect-history-api-fallback" "^1.3.5"
"@types/express" "^4.17.13"
"@types/serve-index" "^1.9.1"
"@types/sockjs" "^0.3.33"
"@types/ws" "^8.2.2"
ansi-html-community "^0.0.8"
bonjour "^3.5.0"
chokidar "^3.5.2"
chokidar "^3.5.3"
colorette "^2.0.10"
compression "^1.7.4"
connect-history-api-fallback "^1.6.0"
@@ -4160,10 +4182,10 @@ webpack-dev-server@4.7.3:
sockjs "^0.3.21"
spdy "^4.0.2"
strip-ansi "^7.0.0"
webpack-dev-middleware "^5.3.0"
ws "^8.1.0"
webpack-dev-middleware "^5.3.1"
ws "^8.4.2"
webpack-merge@5.8.0:
webpack-merge@5.8.0, webpack-merge@^5.7.3:
version "5.8.0"
resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.8.0.tgz#2b39dbf22af87776ad744c390223731d30a68f61"
integrity sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==
@@ -4171,14 +4193,6 @@ webpack-merge@5.8.0:
clone-deep "^4.0.1"
wildcard "^2.0.0"
webpack-merge@^5.7.3:
version "5.7.3"
resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.7.3.tgz#2a0754e1877a25a8bbab3d2475ca70a052708213"
integrity sha512-6/JUQv0ELQ1igjGDzHkXbVDRxkfA57Zw7PfiupdLFJYrgFqY5ZP8xxbpp2lU3EPwYx89ht5Z/aDkD40hFCm5AA==
dependencies:
clone-deep "^4.0.1"
wildcard "^2.0.0"
webpack-sources@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.2.tgz#d88e3741833efec57c4c789b6010db9977545260"
@@ -4250,10 +4264,10 @@ ws@^7.3.1:
resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c"
integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==
ws@^8.1.0:
version "8.4.0"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.4.0.tgz#f05e982a0a88c604080e8581576e2a063802bed6"
integrity sha512-IHVsKe2pjajSUIl4KYMQOdlyliovpEPquKkqbwswulszzI7r0SfQrxnXdWAEqOlDCLrVSJzo+O1hAwdog2sKSQ==
ws@^8.4.2:
version "8.4.2"
resolved "https://registry.yarnpkg.com/ws/-/ws-8.4.2.tgz#18e749868d8439f2268368829042894b6907aa0b"
integrity sha512-Kbk4Nxyq7/ZWqr/tarI9yIt/+iNNFOjBXEWgTb4ydaNHBNGgvf2QHbS9fdfsndfjFlFwEd4Al+mw83YkaD10ZA==
yallist@^4.0.0:
version "4.0.0"
+1 -1
View File
@@ -34,7 +34,7 @@
]
},
"devDependencies": {
"@babel/core": "7.16.7",
"@babel/core": "7.17.2",
"@babel/plugin-transform-arrow-functions": "7.16.0",
"@babel/plugin-transform-async-to-generator": "7.16.5",
"@babel/plugin-transform-runtime": "^7.14.5",
+61 -36
View File
@@ -2,6 +2,13 @@
# yarn lockfile v1
"@ampproject/remapping@^2.0.0":
version "2.1.0"
resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.1.0.tgz#72becdf17ee44b2d1ac5651fb12f1952c336fe23"
integrity sha512-d5RysTlJ7hmw5Tw4UxgxcY3lkMe92n8sXCcuLPAyIAHK6j8DefDwtGnVVDgOnv+RnEosulDJ9NPKQL27bDId0g==
dependencies:
"@jridgewell/trace-mapping" "^0.3.0"
"@babel/code-frame@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789"
@@ -14,33 +21,33 @@
resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.4.tgz#081d6bbc336ec5c2435c6346b2ae1fb98b5ac68e"
integrity sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==
"@babel/core@7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.7.tgz#db990f931f6d40cb9b87a0dc7d2adc749f1dcbcf"
integrity sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==
"@babel/core@7.17.2":
version "7.17.2"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.2.tgz#2c77fc430e95139d816d39b113b31bf40fb22337"
integrity sha512-R3VH5G42VSDolRHyUO4V2cfag8WHcZyxdq5Z/m8Xyb92lW/Erm/6kM+XtRFGf3Mulre3mveni2NHfEUws8wSvw==
dependencies:
"@ampproject/remapping" "^2.0.0"
"@babel/code-frame" "^7.16.7"
"@babel/generator" "^7.16.7"
"@babel/generator" "^7.17.0"
"@babel/helper-compilation-targets" "^7.16.7"
"@babel/helper-module-transforms" "^7.16.7"
"@babel/helpers" "^7.16.7"
"@babel/parser" "^7.16.7"
"@babel/helpers" "^7.17.2"
"@babel/parser" "^7.17.0"
"@babel/template" "^7.16.7"
"@babel/traverse" "^7.16.7"
"@babel/types" "^7.16.7"
"@babel/traverse" "^7.17.0"
"@babel/types" "^7.17.0"
convert-source-map "^1.7.0"
debug "^4.1.0"
gensync "^1.0.0-beta.2"
json5 "^2.1.2"
semver "^6.3.0"
source-map "^0.5.0"
"@babel/generator@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.7.tgz#b42bf46a3079fa65e1544135f32e7958f048adbb"
integrity sha512-/ST3Sg8MLGY5HVYmrjOgL60ENux/HfO/CsUh7y4MalThufhE/Ff/6EibFDHi4jiDCaWfJKoqbE6oTh21c5hrRg==
"@babel/generator@^7.17.0":
version "7.17.0"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.0.tgz#7bd890ba706cd86d3e2f727322346ffdbf98f65e"
integrity sha512-I3Omiv6FGOC29dtlZhkfXO6pgkmukJSlT26QjVvS1DGZe/NzSVCPG41X0tS21oZkJYlovfj9qDWgKP+Cn4bXxw==
dependencies:
"@babel/types" "^7.16.7"
"@babel/types" "^7.17.0"
jsesc "^2.5.1"
source-map "^0.5.0"
@@ -284,14 +291,14 @@
"@babel/traverse" "^7.16.7"
"@babel/types" "^7.16.7"
"@babel/helpers@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.7.tgz#7e3504d708d50344112767c3542fc5e357fffefc"
integrity sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==
"@babel/helpers@^7.17.2":
version "7.17.2"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.2.tgz#23f0a0746c8e287773ccd27c14be428891f63417"
integrity sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==
dependencies:
"@babel/template" "^7.16.7"
"@babel/traverse" "^7.16.7"
"@babel/types" "^7.16.7"
"@babel/traverse" "^7.17.0"
"@babel/types" "^7.17.0"
"@babel/highlight@^7.16.7":
version "7.16.7"
@@ -302,10 +309,10 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
"@babel/parser@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.7.tgz#d372dda9c89fcec340a82630a9f533f2fe15877e"
integrity sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA==
"@babel/parser@^7.16.7", "@babel/parser@^7.17.0":
version "7.17.0"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.0.tgz#f0ac33eddbe214e4105363bb17c3341c5ffcc43c"
integrity sha512-VKXSCQx5D8S04ej+Dqsr1CzYvvWgf20jIw2D+YhQCrIlr2UZGaDds23Y0xg75/skOxpLCRpUZvk/1EAVkGoDOw==
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7":
version "7.16.7"
@@ -959,26 +966,26 @@
"@babel/parser" "^7.16.7"
"@babel/types" "^7.16.7"
"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.5", "@babel/traverse@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.7.tgz#dac01236a72c2560073658dd1a285fe4e0865d76"
integrity sha512-8KWJPIb8c2VvY8AJrydh6+fVRo2ODx1wYBU2398xJVq0JomuLBZmVQzLPBblJgHIGYG4znCpUZUZ0Pt2vdmVYQ==
"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.5", "@babel/traverse@^7.16.7", "@babel/traverse@^7.17.0":
version "7.17.0"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.0.tgz#3143e5066796408ccc880a33ecd3184f3e75cd30"
integrity sha512-fpFIXvqD6kC7c7PUNnZ0Z8cQXlarCLtCUpt2S1Dx7PjoRtCFffvOkHHSom+m5HIxMZn5bIBVb71lhabcmjEsqg==
dependencies:
"@babel/code-frame" "^7.16.7"
"@babel/generator" "^7.16.7"
"@babel/generator" "^7.17.0"
"@babel/helper-environment-visitor" "^7.16.7"
"@babel/helper-function-name" "^7.16.7"
"@babel/helper-hoist-variables" "^7.16.7"
"@babel/helper-split-export-declaration" "^7.16.7"
"@babel/parser" "^7.16.7"
"@babel/types" "^7.16.7"
"@babel/parser" "^7.17.0"
"@babel/types" "^7.17.0"
debug "^4.1.0"
globals "^11.1.0"
"@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.4.4":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.7.tgz#4ed19d51f840ed4bd5645be6ce40775fecf03159"
integrity sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg==
"@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.17.0", "@babel/types@^7.4.4":
version "7.17.0"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b"
integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==
dependencies:
"@babel/helper-validator-identifier" "^7.16.7"
to-fast-properties "^2.0.0"
@@ -988,6 +995,24 @@
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz#8f03a22a04de437254e8ce8cc84ba39689288752"
integrity sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg==
"@jridgewell/resolve-uri@^3.0.3":
version "3.0.4"
resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.4.tgz#b876e3feefb9c8d3aa84014da28b5e52a0640d72"
integrity sha512-cz8HFjOFfUBtvN+NXYSFMHYRdxZMaEl0XypVrhzxBgadKIXhIkRd8aMeHhmF56Sl7SuS8OnUpQ73/k9LE4VnLg==
"@jridgewell/sourcemap-codec@^1.4.10":
version "1.4.10"
resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.10.tgz#baf57b4e2a690d4f38560171f91783656b7f8186"
integrity sha512-Ht8wIW5v165atIX1p+JvKR5ONzUyF4Ac8DZIQ5kZs9zrb6M8SJNXpx1zn04rn65VjBMygRoMXcyYwNK0fT7bEg==
"@jridgewell/trace-mapping@^0.3.0":
version "0.3.4"
resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz#f6a0832dffd5b8a6aaa633b7d9f8e8e94c83a0c3"
integrity sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==
dependencies:
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
"@polka/url@^1.0.0-next.9":
version "1.0.0-next.11"
resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.11.tgz#aeb16f50649a91af79dbe36574b66d0f9e4d9f71"
+63 -20
View File
@@ -196,7 +196,7 @@ const drawElementOnCanvas = (
case "ellipse": {
context.lineJoin = "round";
context.lineCap = "round";
rc.draw(getShapeForElement(element) as Drawable);
rc.draw(getShapeForElement(element)!);
break;
}
case "arrow":
@@ -204,7 +204,7 @@ const drawElementOnCanvas = (
context.lineJoin = "round";
context.lineCap = "round";
(getShapeForElement(element) as Drawable[]).forEach((shape) => {
getShapeForElement(element)!.forEach((shape) => {
rc.draw(shape);
});
break;
@@ -215,6 +215,11 @@ const drawElementOnCanvas = (
context.fillStyle = element.strokeColor;
const path = getFreeDrawPath2D(element) as Path2D;
const fillShape = getShapeForElement(element);
if (fillShape) {
rc.draw(fillShape);
}
context.fillStyle = element.strokeColor;
context.fill(path);
@@ -290,13 +295,29 @@ const elementWithCanvasCache = new WeakMap<
ExcalidrawElementWithCanvas
>();
const shapeCache = new WeakMap<
ExcalidrawElement,
Drawable | Drawable[] | null
>();
const shapeCache = new WeakMap<ExcalidrawElement, ElementShape>();
export const getShapeForElement = (element: ExcalidrawElement) =>
shapeCache.get(element);
type ElementShape = Drawable | Drawable[] | null;
type ElementShapes = {
freedraw: Drawable | null;
arrow: Drawable[];
line: Drawable[];
text: null;
image: null;
};
export const getShapeForElement = <T extends ExcalidrawElement>(element: T) =>
shapeCache.get(element) as T["type"] extends keyof ElementShapes
? ElementShapes[T["type"]] | undefined
: Drawable | null | undefined;
export const setShapeForElement = <T extends ExcalidrawElement>(
element: T,
shape: T["type"] extends keyof ElementShapes
? ElementShapes[T["type"]]
: Drawable,
) => shapeCache.set(element, shape);
export const invalidateShapeForElement = (element: ExcalidrawElement) =>
shapeCache.delete(element);
@@ -346,7 +367,8 @@ export const generateRoughOptions = (
}
return options;
}
case "line": {
case "line":
case "freedraw": {
if (isPathALoop(element.points)) {
options.fillStyle = element.fillStyle;
options.fill =
@@ -356,7 +378,6 @@ export const generateRoughOptions = (
}
return options;
}
case "freedraw":
case "arrow":
return options;
default: {
@@ -374,9 +395,11 @@ const generateElementShape = (
element: NonDeletedExcalidrawElement,
generator: RoughGenerator,
) => {
let shape = shapeCache.get(element) || null;
let shape = shapeCache.get(element);
if (!shape) {
// `null` indicates no rc shape applicable for this element type
// (= do not generate anything)
if (shape === undefined) {
elementWithCanvasCache.delete(element);
switch (element.type) {
@@ -402,6 +425,8 @@ const generateElementShape = (
generateRoughOptions(element),
);
}
setShapeForElement(element, shape);
break;
case "diamond": {
const [topX, topY, rightX, rightY, bottomX, bottomY, leftX, leftY] =
@@ -445,6 +470,8 @@ const generateElementShape = (
generateRoughOptions(element),
);
}
setShapeForElement(element, shape);
break;
}
case "ellipse":
@@ -455,6 +482,8 @@ const generateElementShape = (
element.height,
generateRoughOptions(element),
);
setShapeForElement(element, shape);
break;
case "line":
case "arrow": {
@@ -578,21 +607,32 @@ const generateElementShape = (
}
}
setShapeForElement(element, shape);
break;
}
case "freedraw": {
generateFreeDrawShape(element);
shape = [];
if (isPathALoop(element.points)) {
// generate rough polygon to fill freedraw shape
shape = generator.polygon(element.points as [number, number][], {
...generateRoughOptions(element),
stroke: "none",
});
} else {
shape = null;
}
setShapeForElement(element, shape);
break;
}
case "text":
case "image": {
// just to ensure we don't regenerate element.canvas on rerenders
shape = [];
setShapeForElement(element, null);
break;
}
}
shapeCache.set(element, shape);
}
};
@@ -808,7 +848,7 @@ export const renderElementToSvg = (
generateElementShape(element, generator);
const node = roughSVGDrawWithPrecision(
rsvg,
getShapeForElement(element) as Drawable,
getShapeForElement(element)!,
MAX_DECIMALS_FOR_SVG_EXPORT,
);
const opacity = element.opacity / 100;
@@ -833,7 +873,7 @@ export const renderElementToSvg = (
const opacity = element.opacity / 100;
group.setAttribute("stroke-linecap", "round");
(getShapeForElement(element) as Drawable[]).forEach((shape) => {
getShapeForElement(element)!.forEach((shape) => {
const node = roughSVGDrawWithPrecision(
rsvg,
shape,
@@ -864,7 +904,10 @@ export const renderElementToSvg = (
case "freedraw": {
generateFreeDrawShape(element);
const opacity = element.opacity / 100;
const node = svgRoot.ownerDocument!.createElementNS(SVG_NS, "g");
const shape = getShapeForElement(element);
const node = shape
? roughSVGDrawWithPrecision(rsvg, shape, MAX_DECIMALS_FOR_SVG_EXPORT)
: svgRoot.ownerDocument!.createElementNS(SVG_NS, "g");
if (opacity !== 1) {
node.setAttribute("stroke-opacity", `${opacity}`);
node.setAttribute("fill-opacity", `${opacity}`);
@@ -875,9 +918,9 @@ export const renderElementToSvg = (
offsetY || 0
}) rotate(${degree} ${cx} ${cy})`,
);
const path = svgRoot.ownerDocument!.createElementNS(SVG_NS, "path");
node.setAttribute("stroke", "none");
node.setAttribute("fill", element.strokeColor);
const path = svgRoot.ownerDocument!.createElementNS(SVG_NS, "path");
path.setAttribute("fill", element.strokeColor);
path.setAttribute("d", getFreeDrawSvgPath(element));
node.appendChild(path);
svgRoot.appendChild(node);
+2 -1
View File
@@ -9,7 +9,8 @@ export const hasBackground = (type: string) =>
type === "rectangle" ||
type === "ellipse" ||
type === "diamond" ||
type === "line";
type === "line" ||
type === "freedraw";
export const hasStrokeColor = (type: string) => type !== "image";
+1 -3
View File
@@ -1,9 +1,7 @@
import { AppState, NormalizedZoomValue } from "../types";
export const getNormalizedZoom = (zoom: number): NormalizedZoomValue => {
const normalizedZoom = parseFloat(zoom.toFixed(2));
const clampedZoom = Math.max(0.1, Math.min(normalizedZoom, 30));
return clampedZoom as NormalizedZoomValue;
return Math.max(0.1, Math.min(zoom, 30)) as NormalizedZoomValue;
};
export const getStateForZoom = (
+25 -1
View File
@@ -1,8 +1,10 @@
import { render, waitFor } from "./test-utils";
import { queryByTestId, render, waitFor } from "./test-utils";
import ExcalidrawApp from "../excalidraw-app";
import { API } from "./helpers/api";
import { getDefaultAppState } from "../appState";
import { EXPORT_DATA_TYPES, MIME_TYPES } from "../constants";
import { Pointer, UI } from "./helpers/ui";
import { ExcalidrawTextElement } from "../element/types";
const { h } = window;
@@ -48,4 +50,26 @@ describe("appState", () => {
expect(h.state.viewBackgroundColor).toBe("#000");
});
});
it("changing fontSize with text tool selected (no element created yet)", async () => {
const { container } = await render(<ExcalidrawApp />, {
localStorageData: {
appState: {
currentItemFontSize: 30,
},
},
});
UI.clickTool("text");
expect(h.state.currentItemFontSize).toBe(30);
queryByTestId(container, "fontSize-small")!.click();
expect(h.state.currentItemFontSize).toBe(16);
const mouse = new Pointer("mouse");
mouse.clickAt(100, 100);
expect((h.elements[0] as ExcalidrawTextElement).fontSize).toBe(16);
});
});
+8 -2
View File
@@ -20,7 +20,7 @@ import { LinearElementEditor } from "./element/linearElementEditor";
import { SuggestedBinding } from "./element/binding";
import { ImportedDataState } from "./data/types";
import type App from "./components/App";
import type { ResolvablePromise } from "./utils";
import type { ResolvablePromise, throttleRAF } from "./utils";
import { Spreadsheet } from "./charts";
import { Language } from "./i18n";
import { ClipboardData } from "./clipboard";
@@ -247,6 +247,12 @@ export interface ExcalidrawProps {
onLibraryChange?: (libraryItems: LibraryItems) => void | Promise<any>;
autoFocus?: boolean;
generateIdForFile?: (file: File) => string | Promise<string>;
onLinkOpen?: (
element: NonDeletedExcalidrawElement,
event: CustomEvent<{
nativeEvent: MouseEvent | React.PointerEvent<HTMLCanvasElement>;
}>,
) => void;
}
export type SceneData = {
@@ -367,7 +373,7 @@ export type PointerDownState = Readonly<{
// We need to have these in the state so that we can unsubscribe them
eventListeners: {
// It's defined on the initial pointer down event
onMove: null | ((event: PointerEvent) => void);
onMove: null | ReturnType<typeof throttleRAF>;
// It's defined on the initial pointer down event
onUp: null | ((event: PointerEvent) => void);
// It's defined on the initial pointer down event
+72
View File
@@ -2,6 +2,7 @@ import colors from "./colors";
import {
CURSOR_TYPE,
DEFAULT_VERSION,
EVENT,
FONT_FAMILY,
WINDOWS_EMOJI_FALLBACK_FONT,
} from "./constants";
@@ -119,6 +120,53 @@ export const debounce = <T extends any[]>(
return ret;
};
// throttle callback to execute once per animation frame
export const throttleRAF = <T extends any[]>(fn: (...args: T) => void) => {
let handle: number | null = null;
let lastArgs: T | null = null;
let callback: ((...args: T) => void) | null = null;
const ret = (...args: T) => {
if (process.env.NODE_ENV === "test") {
fn(...args);
return;
}
lastArgs = args;
callback = fn;
if (handle === null) {
handle = window.requestAnimationFrame(() => {
handle = null;
lastArgs = null;
callback = null;
fn(...args);
});
}
};
ret.flush = () => {
if (handle !== null) {
cancelAnimationFrame(handle);
handle = null;
}
if (lastArgs) {
const _lastArgs = lastArgs;
const _callback = callback;
lastArgs = null;
callback = null;
if (_callback !== null) {
_callback(..._lastArgs);
}
}
};
ret.cancel = () => {
lastArgs = null;
callback = null;
if (handle !== null) {
cancelAnimationFrame(handle);
handle = null;
}
};
return ret;
};
// https://github.com/lodash/lodash/blob/es/chunk.js
export const chunk = <T extends any>(
array: readonly T[],
@@ -356,6 +404,21 @@ export const withBatchedUpdates = <
unstable_batchedUpdates(func as TFunction, event);
}) as TFunction;
/**
* barches React state updates and throttles the calls to a single call per
* animation frame
*/
export const withBatchedUpdatesThrottled = <
TFunction extends ((event: any) => void) | (() => void),
>(
func: Parameters<TFunction>["length"] extends 0 | 1 ? TFunction : never,
) => {
// @ts-ignore
return throttleRAF<Parameters<TFunction>>(((event) => {
unstable_batchedUpdates(func, event);
}) as TFunction);
};
//https://stackoverflow.com/a/9462382/8418
export const nFormatter = (num: number, digits: number): string => {
const si = [
@@ -461,3 +524,12 @@ export const arrayToMap = <T extends { id: string } | string>(
export const isTestEnv = () =>
typeof process !== "undefined" && process.env?.NODE_ENV === "test";
export const wrapEvent = <T extends Event>(name: EVENT, nativeEvent: T) => {
return new CustomEvent(name, {
detail: {
nativeEvent,
},
cancelable: true,
});
};
+80 -59
View File
@@ -2136,10 +2136,10 @@
lz-string "^1.4.4"
pretty-format "^27.0.2"
"@testing-library/jest-dom@5.16.1":
version "5.16.1"
resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.16.1.tgz#3db7df5ae97596264a7da9696fe14695ba02e51f"
integrity sha512-ajUJdfDIuTCadB79ukO+0l8O+QwN0LiSxDaYUTI4LndbbUsGi6rWU1SCexXzBA2NSjlVB9/vbkasQIL3tmPBjw==
"@testing-library/jest-dom@5.16.2":
version "5.16.2"
resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.16.2.tgz#f329b36b44aa6149cd6ced9adf567f8b6aa1c959"
integrity sha512-6ewxs1MXWwsBFZXIk4nKKskWANelkdUehchEOokHsN8X7c2eKXGw+77aRV63UU8f/DTSVUPLaGxdrj4lN7D/ug==
dependencies:
"@babel/runtime" "^7.9.2"
"@types/testing-library__jest-dom" "^5.9.1"
@@ -2375,10 +2375,10 @@
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@17.0.38":
version "17.0.38"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.38.tgz#f24249fefd89357d5fa71f739a686b8d7c7202bd"
integrity sha512-SI92X1IA+FMnP3qM5m4QReluXzhcmovhZnLNm3pyeQlooi02qI7sLiepEYqT678uNiyc25XfCqxREFpy3W7YhQ==
"@types/react@*", "@types/react@17.0.39":
version "17.0.39"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.39.tgz#d0f4cde092502a6db00a1cded6e6bf2abb7633ce"
integrity sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
@@ -2540,18 +2540,18 @@
resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.19.0.tgz"
integrity sha512-A4iAlexVvd4IBsSTNxdvdepW0D4uR/fwxDrKUa+iEY9UWvGREu2ZyB8ylTENM1SH8F7bVC9ac9+si3LWNxcBuA==
"@typescript-eslint/types@5.3.0":
version "5.3.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.3.0.tgz#af29fd53867c2df0028c57c36a655bd7e9e05416"
integrity sha512-fce5pG41/w8O6ahQEhXmMV+xuh4+GayzqEogN24EK+vECA3I6pUwKuLi5QbXO721EMitpQne5VKXofPonYlAQg==
"@typescript-eslint/types@5.10.2":
version "5.10.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.10.2.tgz#604d15d795c4601fffba6ecb4587ff9fdec68ce8"
integrity sha512-Qfp0qk/5j2Rz3p3/WhWgu4S1JtMcPgFLnmAKAW061uXxKSa7VWKZsDXVaMXh2N60CX9h6YLaBoy9PJAfCOjk3w==
"@typescript-eslint/typescript-estree@3.10.1", "@typescript-eslint/typescript-estree@4.19.0", "@typescript-eslint/typescript-estree@5.3.0":
version "5.3.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.3.0.tgz#4f68ddd46dc2983182402d2ab21fb44ad94988cf"
integrity sha512-FJ0nqcaUOpn/6Z4Jwbtf+o0valjBLkqc3MWkMvrhA2TvzFXtcclIM8F4MBEmYa2kgcI8EZeSAzwoSrIC8JYkug==
"@typescript-eslint/typescript-estree@3.10.1", "@typescript-eslint/typescript-estree@4.19.0", "@typescript-eslint/typescript-estree@5.10.2":
version "5.10.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.10.2.tgz#810906056cd3ddcb35aa333fdbbef3713b0fe4a7"
integrity sha512-WHHw6a9vvZls6JkTgGljwCsMkv8wu8XU8WaYKeYhxhWXH/atZeiMW6uDFPLZOvzNOGmuSMvHtZKd6AuC8PrwKQ==
dependencies:
"@typescript-eslint/types" "5.3.0"
"@typescript-eslint/visitor-keys" "5.3.0"
"@typescript-eslint/types" "5.10.2"
"@typescript-eslint/visitor-keys" "5.10.2"
debug "^4.3.2"
globby "^11.0.4"
is-glob "^4.0.3"
@@ -2566,12 +2566,12 @@
"@typescript-eslint/types" "4.19.0"
eslint-visitor-keys "^2.0.0"
"@typescript-eslint/visitor-keys@5.3.0":
version "5.3.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.3.0.tgz#a6258790f3b7b2547f70ed8d4a1e0c3499994523"
integrity sha512-oVIAfIQuq0x2TFDNLVavUn548WL+7hdhxYn+9j3YdJJXB7mH9dAmZNJsPDa7Jc+B9WGqoiex7GUDbyMxV0a/aw==
"@typescript-eslint/visitor-keys@5.10.2":
version "5.10.2"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.10.2.tgz#fdbf272d8e61c045d865bd6c8b41bea73d222f3d"
integrity sha512-zHIhYGGGrFJvvyfwHk5M08C5B5K4bewkm+rrvNTKk1/S15YHR+SA/QUF8ZWscXSfEaB8Nn2puZj+iHcoxVOD/Q==
dependencies:
"@typescript-eslint/types" "5.3.0"
"@typescript-eslint/types" "5.10.2"
eslint-visitor-keys "^3.0.0"
"@webassemblyjs/ast@1.9.0":
@@ -2780,6 +2780,11 @@ acorn-walk@^7.1.1:
resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz"
integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
acorn-walk@^8.2.0:
version "8.2.0"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
acorn@^6.4.1:
version "6.4.2"
resolved "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz"
@@ -2790,6 +2795,11 @@ acorn@^7.1.0, acorn@^7.1.1, acorn@^7.4.0:
resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
acorn@^8.7.0:
version "8.7.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf"
integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==
address@1.1.2, address@^1.0.1:
version "1.1.2"
resolved "https://registry.npmjs.org/address/-/address-1.1.2.tgz"
@@ -4106,15 +4116,16 @@ caseless@~0.12.0:
resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz"
integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
chai@4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.4.tgz#b55e655b31e1eac7099be4c08c21964fce2e6c49"
integrity sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA==
chai@4.3.6:
version "4.3.6"
resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.6.tgz#ffe4ba2d9fa9d6680cc0b370adae709ec9011e9c"
integrity sha512-bbcp3YfHCUzMOvKqsztczerVgBKSsEijCySNlHHbX3VG1nskvqjz5Rfso1gGwD6w6oOV3eI60pKuMOV5MV7p3Q==
dependencies:
assertion-error "^1.1.0"
check-error "^1.0.2"
deep-eql "^3.0.1"
get-func-name "^2.0.0"
loupe "^2.3.1"
pathval "^1.1.1"
type-detect "^4.0.5"
@@ -6794,9 +6805,9 @@ fn.name@1.x.x:
integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==
follow-redirects@^1.0.0:
version "1.14.7"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.7.tgz#2004c02eb9436eee9a21446a6477debf17e81685"
integrity sha512-+hbxoLbFMbRKDwohX8GkTataGqO6Jb7jGwpAlwgy2bIz25XtRm7KEzJM76R1WiNT5SwZkX4Y75SwBolkpmE7iQ==
version "1.14.8"
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.8.tgz#016996fb9a11a100566398b1c6839337d7bfa8fc"
integrity sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==
for-in@^1.0.2:
version "1.0.2"
@@ -9276,10 +9287,10 @@ lines-and-columns@^1.1.6:
resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz"
integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
lint-staged@12.1.7:
version "12.1.7"
resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-12.1.7.tgz#fe9137992ac18a456422bb8484dd30be0140629f"
integrity sha512-bltv/ejiLWtowExpjU+s5z8j1Byjg9AlmaAjMmqNbIicY69u6sYIwXGg0dCn0TlkrrY2CphtHIXAkbZ+1VoWQQ==
lint-staged@12.3.3:
version "12.3.3"
resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-12.3.3.tgz#0a465962fe53baa2b4b9da50801ead49a910e03b"
integrity sha512-OqcLsqcPOqzvsfkxjeBpZylgJ3SRG1RYqc9LxC6tkt6tNsq1bNVkAixBwX09f6CobcHswzqVOCBpFR1Fck0+ag==
dependencies:
cli-truncate "^3.1.0"
colorette "^2.0.16"
@@ -9287,10 +9298,10 @@ lint-staged@12.1.7:
debug "^4.3.3"
execa "^5.1.1"
lilconfig "2.0.4"
listr2 "^3.13.5"
listr2 "^4.0.1"
micromatch "^4.0.4"
normalize-path "^3.0.0"
object-inspect "^1.11.1"
object-inspect "^1.12.0"
string-argv "^0.3.1"
supports-color "^9.2.1"
yaml "^1.10.2"
@@ -9300,17 +9311,17 @@ listenercount@~1.0.1:
resolved "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz"
integrity sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=
listr2@^3.13.5:
version "3.13.5"
resolved "https://registry.yarnpkg.com/listr2/-/listr2-3.13.5.tgz#105a813f2eb2329c4aae27373a281d610ee4985f"
integrity sha512-3n8heFQDSk+NcwBn3CgxEibZGaRzx+pC64n3YjpMD1qguV4nWus3Al+Oo3KooqFKTQEJ1v7MmnbnyyNspgx3NA==
listr2@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/listr2/-/listr2-4.0.2.tgz#04d66f8c8694a14920d7df08ebe01568948fb500"
integrity sha512-YcgwfCWpvPbj9FLUGqvdFvd3hrFWKpOeuXznRgfWEJ7RNr8b/IKKIKZABHx3aU+4CWN/iSAFFSReziQG6vTeIA==
dependencies:
cli-truncate "^2.1.0"
colorette "^2.0.16"
log-update "^4.0.0"
p-map "^4.0.0"
rfdc "^1.3.0"
rxjs "^7.4.0"
rxjs "^7.5.2"
through "^2.3.8"
wrap-ansi "^7.0.0"
@@ -9601,6 +9612,13 @@ loose-envify@^1.1.0, loose-envify@^1.4.0:
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
loupe@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.1.tgz#a2e1192c9f452e4e85089766da10ac8288383947"
integrity sha512-EN1D3jyVmaX4tnajVlfbREU4axL647hLec1h/PXAb8CPDMJiYitcWF2UeLVNttRqaIqQs4x+mRvXf+d+TlDrCA==
dependencies:
get-func-name "^2.0.0"
lower-case@^2.0.2:
version "2.0.2"
resolved "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz"
@@ -10403,7 +10421,7 @@ object-copy@^0.1.0:
define-property "^0.2.5"
kind-of "^3.0.3"
object-inspect@^1.11.1, object-inspect@^1.9.0:
object-inspect@^1.12.0, object-inspect@^1.9.0:
version "1.12.0"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0"
integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==
@@ -12850,12 +12868,12 @@ rxjs@^6.4.0, rxjs@^6.6.0:
dependencies:
tslib "^1.9.0"
rxjs@^7.4.0:
version "7.4.0"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.4.0.tgz#a12a44d7eebf016f5ff2441b87f28c9a51cebc68"
integrity sha512-7SQDi7xeTMCJpqViXh8gL/lebcwlp3d831F05+9B44A4B0WfsEwUQHR64gsH1kvJ+Ep/J9K2+n1hVl1CsGN23w==
rxjs@^7.5.2:
version "7.5.2"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.2.tgz#11e4a3a1dfad85dbf7fb6e33cbba17668497490b"
integrity sha512-PwDt186XaL3QN5qXj/H9DGyHhP3/RYYgZZwqBv9Tv8rsAaiwFH1IsJJlcgD37J7UW5a6O67qX0KWKS3/pu0m4w==
dependencies:
tslib "~2.1.0"
tslib "^2.1.0"
safari-14-idb-fix@^3.0.0:
version "3.0.0"
@@ -12915,10 +12933,10 @@ sass-loader@^10.0.5:
schema-utils "^3.0.0"
semver "^7.3.2"
sass@1.47.0:
version "1.47.0"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.47.0.tgz#c22dd0eed2e4a991430dae0b03c8e694bc41c2b4"
integrity sha512-GtXwvwgD7/6MLUZPnlA5/8cdRgC9SzT5kAnnJMRmEZQFRE3J56Foswig4NyyyQGsnmNvg6EUM/FP0Pe9Y2zywQ==
sass@1.49.7:
version "1.49.7"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.49.7.tgz#22a86a50552b9b11f71404dfad1b9ff44c6b0c49"
integrity sha512-13dml55EMIR2rS4d/RDHHP0sXMY3+30e1TKsyXaSz3iLWVoDWEoboY8WzJd5JMnxrRHffKO3wq2mpJ0jxRJiEQ==
dependencies:
chokidar ">=3.0.0 <4.0.0"
immutable "^4.0.0"
@@ -14266,7 +14284,7 @@ tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@~2.1.0:
tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz"
integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
@@ -14392,10 +14410,10 @@ typedarray@^0.0.6:
resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
typescript@4.5.4:
version "4.5.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.4.tgz#a17d3a0263bf5c8723b9c52f43c5084edf13c2e8"
integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==
typescript@4.5.5:
version "4.5.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.5.tgz#d8c953832d28924a9e3d37c73d729c846c5896f3"
integrity sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==
typeson-registry@^1.0.0-alpha.20:
version "1.0.0-alpha.39"
@@ -14742,9 +14760,12 @@ vm-browserify@^1.0.1:
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
vm2@^3.9.3:
version "3.9.5"
resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.5.tgz#5288044860b4bbace443101fcd3bddb2a0aa2496"
integrity sha512-LuCAHZN75H9tdrAiLFf030oW7nJV5xwNMuk1ymOZwopmuK3d2H4L1Kv4+GFHgarKiLfXXLFU+7LDABHnwOkWng==
version "3.9.7"
resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.7.tgz#bb87aa677c97c61e23a6cb6547e44e990517a6f6"
integrity sha512-g/GZ7V0Mlmch3eDVOATvAXr1GsJNg6kQ5PjvYy3HbJMCRn5slNbo/u73Uy7r5yUej1cRa3ZjtoVwcWSQuQ/fow==
dependencies:
acorn "^8.7.0"
acorn-walk "^8.2.0"
w3c-hr-time@^1.0.2:
version "1.0.2"