Compare commits

...

48 Commits

Author SHA1 Message Date
ad1992 52a129c4dd rename 2022-01-05 17:41:45 +05:30
ad1992 f41515b8bc fix: show text properties button states correctly for bounded text 2022-01-05 15:03:58 +05:30
Aakansha Doshi a2e8806f57 fix: rotate bounded text when container is rotated before typing (#4535) 2022-01-04 18:03:24 +05:30
Aakansha Doshi b71e702991 fix: undo should work when selecting bounded textr (#4537) 2022-01-04 18:02:16 +05:30
Aakansha Doshi 5c67329be6 fix: Reduce padding to 5px for bounded text (#4530)
* fix: Reduce padding to 5px

* reduce width by 50 to fix tests

* Push the word if appending space exceeds max width when breaking words

* fix spec
2022-01-03 17:59:26 +05:30
David Luzar 28546fbb55 fix: bound text doesn't inherit container (#4521) 2021-12-31 14:55:02 +01:00
dependabot[bot] b0cccbb9e8 chore(deps): bump @tldraw/vec from 1.2.9 to 1.4.0 (#4517)
Bumps [@tldraw/vec](https://github.com/tldraw/tldraw) from 1.2.9 to 1.4.0.
- [Release notes](https://github.com/tldraw/tldraw/releases)
- [Commits](https://github.com/tldraw/tldraw/compare/v1.2.9...v1.4.0)

---
updated-dependencies:
- dependency-name: "@tldraw/vec"
  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>
2021-12-31 14:44:44 +02:00
David Luzar b621d065de feat: hints and shortcuts help around deep selection (#4502) 2021-12-31 11:00:20 +01:00
dependabot[bot] 96580c92a5 chore(deps-dev): bump @babel/plugin-transform-arrow-functions (#4515)
Bumps [@babel/plugin-transform-arrow-functions](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-arrow-functions) from 7.16.5 to 7.16.7.
- [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.16.7/packages/babel-plugin-transform-arrow-functions)

---
updated-dependencies:
- dependency-name: "@babel/plugin-transform-arrow-functions"
  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>
2021-12-31 12:42:29 +05:30
dependabot[bot] 975441549b chore(deps): bump sass from 1.43.5 to 1.45.2 (#4518)
Bumps [sass](https://github.com/sass/dart-sass) from 1.43.5 to 1.45.2.
- [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.43.5...1.45.2)

---
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>
2021-12-31 12:42:04 +05:30
dependabot[bot] 4be701416a chore(deps-dev): bump @babel/preset-react in /src/packages/excalidraw (#4519)
Bumps [@babel/preset-react](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-react) from 7.16.0 to 7.16.7.
- [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.16.7/packages/babel-preset-react)

---
updated-dependencies:
- dependency-name: "@babel/preset-react"
  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>
2021-12-31 12:41:31 +05:30
dependabot[bot] 1acb1e33f1 chore(deps-dev): bump @babel/preset-env in /src/packages/excalidraw (#4516)
Bumps [@babel/preset-env](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-env) from 7.16.4 to 7.16.7.
- [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.16.7/packages/babel-preset-env)

---
updated-dependencies:
- dependency-name: "@babel/preset-env"
  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>
2021-12-31 01:11:22 +00:00
dependabot[bot] 986e1e40d3 chore(deps-dev): bump @babel/preset-typescript (#4514)
Bumps [@babel/preset-typescript](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-typescript) from 7.16.0 to 7.16.7.
- [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.16.7/packages/babel-preset-typescript)

---
updated-dependencies:
- dependency-name: "@babel/preset-typescript"
  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>
2021-12-31 01:00:57 +00:00
dependabot[bot] fab4a0e060 chore(deps-dev): bump @babel/plugin-transform-runtime (#4508)
Bumps [@babel/plugin-transform-runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-runtime) from 7.16.4 to 7.16.7.
- [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.16.7/packages/babel-plugin-transform-runtime)

---
updated-dependencies:
- dependency-name: "@babel/plugin-transform-runtime"
  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>
2021-12-31 02:59:42 +02:00
dependabot[bot] b265ebf88f chore(deps): bump @tldraw/vec from 1.1.5 to 1.2.9 (#4479)
Bumps [@tldraw/vec](https://github.com/tldraw/tldraw) from 1.1.5 to 1.2.9.
- [Release notes](https://github.com/tldraw/tldraw/releases)
- [Commits](https://github.com/tldraw/tldraw/compare/v1.1.5...v1.2.9)

---
updated-dependencies:
- dependency-name: "@tldraw/vec"
  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>
2021-12-31 02:52:36 +02:00
dependabot[bot] 351845019e chore(deps-dev): bump @types/pako from 1.0.2 to 1.0.3 (#4481)
Bumps [@types/pako](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/pako) from 1.0.2 to 1.0.3.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/pako)

---
updated-dependencies:
- dependency-name: "@types/pako"
  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>
2021-12-31 02:51:20 +02:00
dependabot[bot] c0fcce6f27 chore(deps): bump @testing-library/jest-dom from 5.15.1 to 5.16.1 (#4395)
Bumps [@testing-library/jest-dom](https://github.com/testing-library/jest-dom) from 5.15.1 to 5.16.1.
- [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.15.1...v5.16.1)

---
updated-dependencies:
- dependency-name: "@testing-library/jest-dom"
  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>
2021-12-31 02:50:30 +02:00
dependabot[bot] b093d2d2b6 chore(deps-dev): bump prettier from 2.5.0 to 2.5.1 (#4360)
Bumps [prettier](https://github.com/prettier/prettier) from 2.5.0 to 2.5.1.
- [Release notes](https://github.com/prettier/prettier/releases)
- [Changelog](https://github.com/prettier/prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/prettier/compare/2.5.0...2.5.1)

---
updated-dependencies:
- dependency-name: prettier
  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>
2021-12-31 02:49:43 +02:00
dependabot[bot] 69548c5502 chore(deps): bump @types/react from 17.0.37 to 17.0.38 (#4483)
Bumps [@types/react](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/react) from 17.0.37 to 17.0.38.
- [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>
2021-12-31 02:49:15 +02:00
dependabot[bot] 6ca0afa6e5 chore(deps-dev): bump @types/chai from 4.2.22 to 4.3.0 (#4394)
Bumps [@types/chai](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/chai) from 4.2.22 to 4.3.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/chai)

---
updated-dependencies:
- dependency-name: "@types/chai"
  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>
2021-12-31 02:48:59 +02:00
dependabot[bot] c50f81b829 chore(deps-dev): bump @babel/plugin-transform-arrow-functions (#4426)
Bumps [@babel/plugin-transform-arrow-functions](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-arrow-functions) from 7.16.0 to 7.16.5.
- [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.16.5/packages/babel-plugin-transform-arrow-functions)

---
updated-dependencies:
- dependency-name: "@babel/plugin-transform-arrow-functions"
  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>
2021-12-31 02:47:42 +02:00
dependabot[bot] b122c8c4eb chore(deps-dev): bump @babel/plugin-transform-async-to-generator (#4437)
Bumps [@babel/plugin-transform-async-to-generator](https://github.com/babel/babel/tree/HEAD/packages/babel-plugin-transform-async-to-generator) from 7.16.0 to 7.16.5.
- [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.16.5/packages/babel-plugin-transform-async-to-generator)

---
updated-dependencies:
- dependency-name: "@babel/plugin-transform-async-to-generator"
  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>
2021-12-31 02:47:16 +02:00
dependabot[bot] 9a7216fe94 chore(deps-dev): bump terser-webpack-plugin in /src/packages/excalidraw (#4423)
Bumps [terser-webpack-plugin](https://github.com/webpack-contrib/terser-webpack-plugin) from 5.2.5 to 5.3.0.
- [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.2.5...v5.3.0)

---
updated-dependencies:
- dependency-name: terser-webpack-plugin
  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>
2021-12-31 02:46:52 +02:00
dependabot[bot] 8eee749076 chore(deps-dev): bump @babel/preset-typescript in /src/packages/utils (#4430)
Bumps [@babel/preset-typescript](https://github.com/babel/babel/tree/HEAD/packages/babel-preset-typescript) from 7.16.0 to 7.16.5.
- [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.16.5/packages/babel-preset-typescript)

---
updated-dependencies:
- dependency-name: "@babel/preset-typescript"
  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>
2021-12-31 02:46:36 +02:00
dependabot[bot] 2158ad0656 chore(deps-dev): bump @babel/core in /src/packages/utils (#4435)
Bumps [@babel/core](https://github.com/babel/babel/tree/HEAD/packages/babel-core) from 7.16.0 to 7.16.5.
- [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.16.5/packages/babel-core)

---
updated-dependencies:
- dependency-name: "@babel/core"
  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>
2021-12-31 02:45:49 +02:00
dependabot[bot] 74c3fea7f5 chore(deps): bump typescript from 4.5.2 to 4.5.4 (#4442)
Bumps [typescript](https://github.com/Microsoft/TypeScript) from 4.5.2 to 4.5.4.
- [Release notes](https://github.com/Microsoft/TypeScript/releases)
- [Commits](https://github.com/Microsoft/TypeScript/compare/v4.5.2...v4.5.4)

---
updated-dependencies:
- dependency-name: typescript
  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>
2021-12-31 02:45:31 +02:00
dependabot[bot] 5e456e6d05 chore(deps-dev): bump lint-staged from 12.1.2 to 12.1.4 (#4478)
Bumps [lint-staged](https://github.com/okonet/lint-staged) from 12.1.2 to 12.1.4.
- [Release notes](https://github.com/okonet/lint-staged/releases)
- [Commits](https://github.com/okonet/lint-staged/compare/v12.1.2...v12.1.4)

---
updated-dependencies:
- dependency-name: lint-staged
  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>
2021-12-31 02:45:09 +02:00
zsviczian 477cce2ed6 fix: Text wrapping with grid (#4505) (#4506) 2021-12-30 19:10:31 +01:00
Aakansha Doshi dd8e465304 feat: Support updating text properties by clicking on container (#4499) 2021-12-29 16:49:52 +05:30
Aakansha Doshi 11396a21de fix: check if process is defined before using so it works in browser (#4497)
* refactor: use isTestEnv() utils where applicable

* check if process is defined
2021-12-28 17:17:41 +05:30
Aakansha Doshi 38236bc5e0 tests: Add tests for wrapText util (#4495) 2021-12-28 16:52:57 +05:30
Aakansha Doshi 63ce5b82d7 fix: pending review fixes for sticky notes (#4493) 2021-12-28 16:24:44 +05:30
David Luzar bae0e985b2 fix: prevent browser from scrolling when panning (#4489) 2021-12-27 14:18:11 +01:00
Aakansha Doshi 04f852a40a build: Added example folder for testing @excalidraw/excalidraw in local (#4488)
* build: Added example folder for testing @excalidraw/excalidraw in local

* remove unnecessary files

* use scss

* update docs

* newline

* remove index

* remove yarn

* use the bundled excalidraw.development.js for better testing and font will also be available

* remove src folder from example
2021-12-27 18:01:33 +05:30
Aakansha Doshi f463c047c0 fix: pasted elements except binded text once paste action is complete (#4472) 2021-12-23 22:07:16 +05:30
Aakansha Doshi 1fd347cade fix: don't select binded text when ungrouping (#4470) 2021-12-23 21:36:29 +05:30
Aakansha Doshi ef62390841 fix: set height correctly when text properties updated while editing in container until first submit (#4469)
* fix: set height correctly when text properties updated while editing in container

* rename PADDING to BOUND_TEXT_PADDING
2021-12-23 17:02:35 +05:30
Aakansha Doshi bf2bca221e fix: align and distribute binded text in container and cleanup (#4468) 2021-12-23 17:02:13 +05:30
Aakansha Doshi d0733b1960 fix: move binded text when moving container using keyboard (#4466) 2021-12-23 01:47:14 +05:30
Aakansha Doshi 64c2d76cfa fix: support dragging binded text in container selected in a group (#4462)
* fix: support moving binded text when container selected via group

* update coords of bounded text only when element doesn't belong to any group or element in group is selected

* dnt drag binded text when nested group selected

* Update src/element/dragElements.ts

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

Co-authored-by: David Luzar <luzar.david@gmail.com>
2021-12-22 19:16:49 +05:30
zsviczian c76784b774 fix: Scope drag and drop events to Excalidraw container to prevent overriding the host drag and drop events (#4445)
* cross-env

* reverting lib

https://github.com/excalidraw/excalidraw/issues/4282

* Revert "reverting lib"

This reverts commit 840726806a.

* Update package.json

* Update App.tsx

* Update App.tsx

* lint

* updated changelog

* Update src/packages/excalidraw/CHANGELOG.md

Co-authored-by: Aakansha Doshi <aakansha1216@gmail.com>

* Update src/packages/excalidraw/CHANGELOG.md

* Move fixes above build header

* Update src/packages/excalidraw/CHANGELOG.md

* lint

Co-authored-by: Aakansha Doshi <aakansha1216@gmail.com>
Co-authored-by: David Luzar <luzar.david@gmail.com>
2021-12-22 18:55:34 +05:30
Aakansha Doshi 25e54e5999 fix: vertically align single line when deleting text in bounded container (#4460) 2021-12-22 15:32:21 +05:30
Aakansha Doshi 55b7a7d554 fix: update height correctly when updating text properties in binded text (#4459)
* fix: update height correctly when updating text properties in binded text

* read height from editor style so its accurate

* fix
2021-12-22 12:08:51 +05:30
David Luzar c1c37a6ee7 fix: align library item previews to center (#4447) 2021-12-21 19:59:36 +01:00
Aakansha Doshi 25b529f519 fix: vertically center align text when text deleted (#4457) 2021-12-22 00:07:55 +05:30
Aakansha Doshi 8e6a747873 fix: vertically center the first line as user starts typing in container (#4454)
* fix: vertically center the first line as user starts typing in container

* fix
2021-12-21 23:08:36 +05:30
Aakansha Doshi 089b05db1b fix: switch cursor to center of container when adding text when dimensions are too small (#4452) 2021-12-21 19:00:01 +05:30
Aakansha Doshi 081e097cef fix: vertically center align the bounded text correctly when zoomed (#4444)
* fix: vertically center align the bounded text correctly when zoomed

* dnt add offsets since its calculated correctly

* set editor max width better when offsets present

* Update src/element/textWysiwyg.tsx

* const

* revert
2021-12-21 17:13:11 +05:30
39 changed files with 4520 additions and 861 deletions
+9 -9
View File
@@ -21,12 +21,12 @@
"dependencies": {
"@sentry/browser": "6.2.5",
"@sentry/integrations": "6.2.5",
"@testing-library/jest-dom": "5.15.1",
"@testing-library/jest-dom": "5.16.1",
"@testing-library/react": "12.1.2",
"@tldraw/vec": "1.1.5",
"@tldraw/vec": "1.4.0",
"@types/jest": "27.0.3",
"@types/pica": "5.1.3",
"@types/react": "17.0.37",
"@types/react": "17.0.38",
"@types/react-dom": "17.0.11",
"@types/socket.io-client": "1.4.36",
"browser-fs-access": "0.23.0",
@@ -50,16 +50,16 @@
"react-dom": "17.0.2",
"react-scripts": "4.0.3",
"roughjs": "4.5.2",
"sass": "1.43.5",
"sass": "1.45.2",
"socket.io-client": "2.3.1",
"typescript": "4.5.2"
"typescript": "4.5.4"
},
"devDependencies": {
"@excalidraw/eslint-config": "1.0.0",
"@excalidraw/prettier-config": "1.0.2",
"@types/chai": "4.2.22",
"@types/chai": "4.3.0",
"@types/lodash.throttle": "4.1.6",
"@types/pako": "1.0.2",
"@types/pako": "1.0.3",
"@types/resize-observer-browser": "0.1.6",
"chai": "4.3.4",
"dotenv": "10.0.0",
@@ -68,9 +68,9 @@
"firebase-tools": "9.23.0",
"husky": "7.0.4",
"jest-canvas-mock": "2.3.1",
"lint-staged": "12.1.2",
"lint-staged": "12.1.4",
"pepjs": "0.5.3",
"prettier": "2.5.0",
"prettier": "2.5.1",
"rewire": "5.0.0"
},
"resolutions": {
+19 -5
View File
@@ -17,8 +17,9 @@ import {
import { getNonDeletedElements } from "../element";
import { randomId } from "../random";
import { ToolButton } from "../components/ToolButton";
import { ExcalidrawElement } from "../element/types";
import { ExcalidrawElement, ExcalidrawTextElement } from "../element/types";
import { AppState } from "../types";
import { isBoundToContainer } from "../element/typeChecks";
const allElementsInSameGroup = (elements: readonly ExcalidrawElement[]) => {
if (elements.length >= 2) {
@@ -151,7 +152,12 @@ export const actionUngroup = register({
if (groupIds.length === 0) {
return { appState, elements, commitToHistory: false };
}
const boundTextElementIds: ExcalidrawTextElement["id"][] = [];
const nextElements = elements.map((element) => {
if (isBoundToContainer(element)) {
boundTextElementIds.push(element.id);
}
const nextGroupIds = removeFromSelectedGroups(
element.groupIds,
appState.selectedGroupIds,
@@ -163,11 +169,19 @@ export const actionUngroup = register({
groupIds: nextGroupIds,
});
});
const updateAppState = selectGroupsForSelectedElements(
{ ...appState, selectedGroupIds: {} },
getNonDeletedElements(nextElements),
);
// remove binded text elements from selection
boundTextElementIds.forEach(
(id) => (updateAppState.selectedElementIds[id] = false),
);
return {
appState: selectGroupsForSelectedElements(
{ ...appState, selectedGroupIds: {} },
getNonDeletedElements(nextElements),
),
appState: updateAppState,
elements: nextElements,
commitToHistory: true,
};
+96 -34
View File
@@ -42,6 +42,7 @@ import {
redrawTextBoundingBox,
} from "../element";
import { newElementWith } from "../element/mutateElement";
import { getBoundTextElement } from "../element/textElement";
import { isLinearElement, isLinearElementType } from "../element/typeChecks";
import {
Arrowhead,
@@ -57,20 +58,27 @@ import {
canChangeSharpness,
canHaveArrowheads,
getCommonAttributeOfSelectedElements,
getSelectedElements,
getTargetElements,
isSomeElementSelected,
} from "../scene";
import { hasStrokeColor } from "../scene/comparisons";
import Scene from "../scene/Scene";
import { arrayToMap } from "../utils";
import { register } from "./register";
const changeProperty = (
elements: readonly ExcalidrawElement[],
appState: AppState,
callback: (element: ExcalidrawElement) => ExcalidrawElement,
includeBoundText = false,
) => {
const selectedElementIds = arrayToMap(
getSelectedElements(elements, appState, includeBoundText),
);
return elements.map((element) => {
if (
appState.selectedElementIds[element.id] ||
selectedElementIds.get(element.id) ||
element.id === appState.editingElement?.id
) {
return callback(element);
@@ -426,17 +434,26 @@ export const actionChangeFontSize = register({
name: "changeFontSize",
perform: (elements, appState, value) => {
return {
elements: changeProperty(elements, appState, (el) => {
if (isTextElement(el)) {
const element: ExcalidrawTextElement = newElementWith(el, {
fontSize: value,
});
redrawTextBoundingBox(element);
return element;
}
elements: changeProperty(
elements,
appState,
(el) => {
if (isTextElement(el)) {
const element: ExcalidrawTextElement = newElementWith(el, {
fontSize: value,
});
let container = null;
if (el.containerId) {
container = Scene.getScene(el)!.getElement(el.containerId);
}
redrawTextBoundingBox(element, container, appState);
return element;
}
return el;
}),
return el;
},
true,
),
appState: {
...appState,
currentItemFontSize: value,
@@ -474,7 +491,16 @@ export const actionChangeFontSize = register({
value={getFormValue(
elements,
appState,
(element) => isTextElement(element) && element.fontSize,
(element) => {
if (isTextElement(element)) {
return element.fontSize;
}
const boundTextElement = getBoundTextElement(element);
if (boundTextElement) {
return boundTextElement.fontSize;
}
return null;
},
appState.currentItemFontSize || DEFAULT_FONT_SIZE,
)}
onChange={(value) => updateData(value)}
@@ -487,17 +513,26 @@ export const actionChangeFontFamily = register({
name: "changeFontFamily",
perform: (elements, appState, value) => {
return {
elements: changeProperty(elements, appState, (el) => {
if (isTextElement(el)) {
const element: ExcalidrawTextElement = newElementWith(el, {
fontFamily: value,
});
redrawTextBoundingBox(element);
return element;
}
elements: changeProperty(
elements,
appState,
(el) => {
if (isTextElement(el)) {
const element: ExcalidrawTextElement = newElementWith(el, {
fontFamily: value,
});
let container = null;
if (el.containerId) {
container = Scene.getScene(el)!.getElement(el.containerId);
}
redrawTextBoundingBox(element, container, appState);
return element;
}
return el;
}),
return el;
},
true,
),
appState: {
...appState,
currentItemFontFamily: value,
@@ -537,7 +572,16 @@ export const actionChangeFontFamily = register({
value={getFormValue(
elements,
appState,
(element) => isTextElement(element) && element.fontFamily,
(element) => {
if (isTextElement(element)) {
return element.fontFamily;
}
const boundTextElement = getBoundTextElement(element);
if (boundTextElement) {
return boundTextElement.fontFamily;
}
return null;
},
appState.currentItemFontFamily || DEFAULT_FONT_FAMILY,
)}
onChange={(value) => updateData(value)}
@@ -551,17 +595,26 @@ export const actionChangeTextAlign = register({
name: "changeTextAlign",
perform: (elements, appState, value) => {
return {
elements: changeProperty(elements, appState, (el) => {
if (isTextElement(el)) {
const element: ExcalidrawTextElement = newElementWith(el, {
textAlign: value,
});
redrawTextBoundingBox(element);
return element;
}
elements: changeProperty(
elements,
appState,
(el) => {
if (isTextElement(el)) {
const element: ExcalidrawTextElement = newElementWith(el, {
textAlign: value,
});
let container = null;
if (el.containerId) {
container = Scene.getScene(el)!.getElement(el.containerId);
}
redrawTextBoundingBox(element, container, appState);
return element;
}
return el;
}),
return el;
},
true,
),
appState: {
...appState,
currentItemTextAlign: value,
@@ -594,7 +647,16 @@ export const actionChangeTextAlign = register({
value={getFormValue(
elements,
appState,
(element) => isTextElement(element) && element.textAlign,
(element) => {
if (isTextElement(element)) {
return element.textAlign;
}
const boundTextElement = getBoundTextElement(element);
if (boundTextElement) {
return boundTextElement.textAlign;
}
return null;
},
appState.currentItemTextAlign,
)}
onChange={(value) => updateData(value)}
+15 -1
View File
@@ -12,6 +12,9 @@ import {
DEFAULT_FONT_FAMILY,
DEFAULT_TEXT_ALIGN,
} from "../constants";
import Scene from "../scene/Scene";
import { isBoundToContainer } from "../element/typeChecks";
import { ExcalidrawTextElement } from "../element/types";
// `copiedStyles` is exported only for tests.
export let copiedStyles: string = "{}";
@@ -61,7 +64,18 @@ export const actionPasteStyles = register({
fontFamily: pastedElement?.fontFamily || DEFAULT_FONT_FAMILY,
textAlign: pastedElement?.textAlign || DEFAULT_TEXT_ALIGN,
});
redrawTextBoundingBox(newElement);
let container = null;
if (isBoundToContainer(element)) {
container = Scene.getScene(element)!.getElement(
element.containerId,
);
}
redrawTextBoundingBox(
element as ExcalidrawTextElement,
container,
appState,
);
}
return newElement;
}
+1 -22
View File
@@ -1,6 +1,7 @@
import { ExcalidrawElement } from "./element/types";
import { newElementWith } from "./element/mutateElement";
import { Box, getCommonBoundingBox } from "./element/bounds";
import { getMaximumGroups } from "./groups";
export interface Alignment {
position: "start" | "center" | "end";
@@ -30,28 +31,6 @@ export const alignElements = (
});
};
export const getMaximumGroups = (
elements: ExcalidrawElement[],
): ExcalidrawElement[][] => {
const groups: Map<String, ExcalidrawElement[]> = new Map<
String,
ExcalidrawElement[]
>();
elements.forEach((element: ExcalidrawElement) => {
const groupId =
element.groupIds.length === 0
? element.id
: element.groupIds[element.groupIds.length - 1];
const currentGroupMembers = groups.get(groupId) || [];
groups.set(groupId, [...currentGroupMembers, element]);
});
return Array.from(groups.values());
};
const calculateTranslation = (
group: ExcalidrawElement[],
selectionBoundingBox: Box,
+42 -11
View File
@@ -123,6 +123,7 @@ import {
hasBoundTextElement,
isBindingElement,
isBindingElementType,
isBoundToContainer,
isImageElement,
isInitializedImageElement,
isLinearElement,
@@ -917,8 +918,16 @@ class App extends React.Component<AppProps, AppState> {
window.removeEventListener(EVENT.RESIZE, this.onResize, false);
window.removeEventListener(EVENT.UNLOAD, this.onUnload, false);
window.removeEventListener(EVENT.BLUR, this.onBlur, false);
window.removeEventListener(EVENT.DRAG_OVER, this.disableEvent, false);
window.removeEventListener(EVENT.DROP, this.disableEvent, false);
this.excalidrawContainerRef.current?.removeEventListener(
EVENT.DRAG_OVER,
this.disableEvent,
false,
);
this.excalidrawContainerRef.current?.removeEventListener(
EVENT.DROP,
this.disableEvent,
false,
);
document.removeEventListener(
EVENT.GESTURE_START,
@@ -987,8 +996,16 @@ class App extends React.Component<AppProps, AppState> {
window.addEventListener(EVENT.RESIZE, this.onResize, false);
window.addEventListener(EVENT.UNLOAD, this.onUnload, false);
window.addEventListener(EVENT.BLUR, this.onBlur, false);
window.addEventListener(EVENT.DRAG_OVER, this.disableEvent, false);
window.addEventListener(EVENT.DROP, this.disableEvent, false);
this.excalidrawContainerRef.current?.addEventListener(
EVENT.DRAG_OVER,
this.disableEvent,
false,
);
this.excalidrawContainerRef.current?.addEventListener(
EVENT.DROP,
this.disableEvent,
false,
);
}
componentDidUpdate(prevProps: AppProps, prevState: AppState) {
@@ -1403,7 +1420,7 @@ class App extends React.Component<AppProps, AppState> {
...this.state,
isLibraryOpen: false,
selectedElementIds: newElements.reduce((map, element) => {
if (isTextElement(element) && !element.containerId) {
if (!isBoundToContainer(element)) {
map[element.id] = true;
}
return map;
@@ -1663,9 +1680,11 @@ class App extends React.Component<AppProps, AppState> {
? ELEMENT_SHIFT_TRANSLATE_AMOUNT
: ELEMENT_TRANSLATE_AMOUNT);
const selectedElements = this.scene
.getElements()
.filter((element) => this.state.selectedElementIds[element.id]);
const selectedElements = getSelectedElements(
this.scene.getElements(),
this.state,
true,
);
let offsetX = 0;
let offsetY = 0;
@@ -1746,6 +1765,7 @@ class App extends React.Component<AppProps, AppState> {
if (event.key === KEYS.SPACE && gesture.pointers.size === 0) {
isHoldingSpace = true;
setCursor(this.canvas, CURSOR_TYPE.GRABBING);
event.preventDefault();
}
if (event.key === KEYS.G || event.key === KEYS.S) {
@@ -2066,7 +2086,7 @@ class App extends React.Component<AppProps, AppState> {
/** whether to attempt to insert at element center if applicable */
insertAtParentCenter?: boolean;
}) => {
const parentCenterPosition =
let parentCenterPosition =
insertAtParentCenter &&
this.getTextWysiwygSnappedToCenterPosition(
sceneX,
@@ -2081,10 +2101,9 @@ class App extends React.Component<AppProps, AppState> {
const container =
shouldBind || parentCenterPosition
? getElementContainingPosition(
this.scene.getElements(),
this.scene.getElements().filter((ele) => !isTextElement(ele)),
sceneX,
sceneY,
"text",
)
: null;
@@ -2111,6 +2130,15 @@ class App extends React.Component<AppProps, AppState> {
mutateElement(container, { height: newHeight, width: newWidth });
sceneX = container.x + newWidth / 2;
sceneY = container.y + newHeight / 2;
if (parentCenterPosition) {
parentCenterPosition = this.getTextWysiwygSnappedToCenterPosition(
sceneX,
sceneY,
this.state,
this.canvas,
window.devicePixelRatio,
);
}
}
const element = existingTextElement
@@ -2140,6 +2168,7 @@ class App extends React.Component<AppProps, AppState> {
? "middle"
: DEFAULT_VERTICAL_ALIGN,
containerId: container?.id ?? undefined,
groupIds: container?.groupIds ?? [],
});
this.setState({ editingElement: element });
@@ -2703,6 +2732,7 @@ class App extends React.Component<AppProps, AppState> {
return false;
}
isPanning = true;
event.preventDefault();
let nextPastePrevented = false;
const isLinux = /Linux/.test(window.navigator.platform);
@@ -3549,6 +3579,7 @@ class App extends React.Component<AppProps, AppState> {
lockDirection,
dragDistanceX,
dragDistanceY,
this.state,
);
this.maybeSuggestBindingForAll(selectedElements);
+12
View File
@@ -260,6 +260,18 @@ export const HelpDialog = ({ onClose }: { onClose?: () => void }) => {
label={t("labels.multiSelect")}
shortcuts={[getShortcutKey(`Shift+${t("helpDialog.click")}`)]}
/>
<Shortcut
label={t("helpDialog.deepSelect")}
shortcuts={[
getShortcutKey(`CtrlOrCmd+${t("helpDialog.click")}`),
]}
/>
<Shortcut
label={t("helpDialog.deepBoxSelect")}
shortcuts={[
getShortcutKey(`CtrlOrCmd+${t("helpDialog.drag")}`),
]}
/>
<Shortcut
label={t("labels.moveCanvas")}
shortcuts={[
+21 -12
View File
@@ -61,6 +61,27 @@ const getHints = ({ appState, elements, isMobile }: HintViewerProps) => {
return t("hints.rotate");
}
if (selectedElements.length === 1 && isTextElement(selectedElements[0])) {
return t("hints.text_selected");
}
if (appState.editingElement && isTextElement(appState.editingElement)) {
return t("hints.text_editing");
}
if (elementType === "selection") {
if (
appState.draggingElement?.type === "selection" &&
!appState.editingElement &&
!appState.editingLinearElement
) {
return t("hints.deepBoxSelect");
}
if (!selectedElements.length && !isMobile) {
return t("hints.canvasPanning");
}
}
if (selectedElements.length === 1) {
if (isLinearElement(selectedElements[0])) {
if (appState.editingLinearElement) {
@@ -75,18 +96,6 @@ const getHints = ({ appState, elements, isMobile }: HintViewerProps) => {
}
}
if (selectedElements.length === 1 && isTextElement(selectedElements[0])) {
return t("hints.text_selected");
}
if (appState.editingElement && isTextElement(appState.editingElement)) {
return t("hints.text_editing");
}
if (elementType === "selection" && !selectedElements.length && !isMobile) {
return t("hints.canvasPanning");
}
return null;
};
+2
View File
@@ -27,6 +27,8 @@
.library-unit__dragger {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
width: 100%;
}
+1 -1
View File
@@ -182,4 +182,4 @@ export const VERSIONS = {
excalidrawLibrary: 2,
} as const;
export const PADDING = 30;
export const BOUND_TEXT_PADDING = 5;
+2 -48
View File
@@ -1,17 +1,7 @@
import { ExcalidrawElement } from "./element/types";
import { newElementWith } from "./element/mutateElement";
import { getCommonBounds } from "./element";
interface Box {
minX: number;
minY: number;
maxX: number;
maxY: number;
midX: number;
midY: number;
width: number;
height: number;
}
import { getMaximumGroups } from "./groups";
import { getCommonBoundingBox } from "./element/bounds";
export interface Distribution {
space: "between";
@@ -98,39 +88,3 @@ export const distributeElements = (
);
});
};
export const getMaximumGroups = (
elements: ExcalidrawElement[],
): ExcalidrawElement[][] => {
const groups: Map<String, ExcalidrawElement[]> = new Map<
String,
ExcalidrawElement[]
>();
elements.forEach((element: ExcalidrawElement) => {
const groupId =
element.groupIds.length === 0
? element.id
: element.groupIds[element.groupIds.length - 1];
const currentGroupMembers = groups.get(groupId) || [];
groups.set(groupId, [...currentGroupMembers, element]);
});
return Array.from(groups.values());
};
const getCommonBoundingBox = (elements: ExcalidrawElement[]): Box => {
const [minX, minY, maxX, maxY] = getCommonBounds(elements);
return {
minX,
minY,
maxX,
maxY,
width: maxX - minX,
height: maxY - minY,
midX: (minX + maxX) / 2,
midY: (minY + maxY) / 2,
};
};
+14 -1
View File
@@ -520,11 +520,24 @@ export interface Box {
minY: number;
maxX: number;
maxY: number;
midX: number;
midY: number;
width: number;
height: number;
}
export const getCommonBoundingBox = (
elements: ExcalidrawElement[] | readonly NonDeleted<ExcalidrawElement>[],
): Box => {
const [minX, minY, maxX, maxY] = getCommonBounds(elements);
return { minX, minY, maxX, maxY };
return {
minX,
minY,
maxX,
maxY,
width: maxX - minX,
height: maxY - minY,
midX: (minX + maxX) / 2,
midY: (minY + maxY) / 2,
};
};
+1 -2
View File
@@ -46,8 +46,7 @@ const isElementDraggableFromInside = (
return true;
}
const isDraggableFromInside =
!isTransparent(element.backgroundColor) ||
(isTransparent(element.backgroundColor) && hasBoundTextElement(element));
!isTransparent(element.backgroundColor) || hasBoundTextElement(element);
if (element.type === "line") {
return isDraggableFromInside && isPathALoop(element.points);
}
+12 -2
View File
@@ -5,8 +5,9 @@ import { mutateElement } from "./mutateElement";
import { getPerfectElementSize } from "./sizeHelpers";
import Scene from "../scene/Scene";
import { NonDeletedExcalidrawElement } from "./types";
import { PointerDownState } from "../types";
import { AppState, PointerDownState } from "../types";
import { getBoundTextElementId } from "./textElement";
import { isSelectedViaGroup } from "../groups";
export const dragSelectedElements = (
pointerDownState: PointerDownState,
@@ -16,6 +17,7 @@ export const dragSelectedElements = (
lockDirection: boolean = false,
distanceX: number = 0,
distanceY: number = 0,
appState: AppState,
) => {
const [x1, y1] = getCommonBounds(selectedElements);
const offset = { x: pointerX - x1, y: pointerY - y1 };
@@ -28,7 +30,15 @@ export const dragSelectedElements = (
element,
offset,
);
if (!element.groupIds.length) {
// update coords of bound text only if we're dragging the container directly
// (we don't drag the group that it's part of)
if (
// container isn't part of any group
// (perf optim so we don't check `isSelectedViaGroup()` in every case)
!element.groupIds.length ||
// container is part of a group, but we're dragging the container directly
(appState.editingGroupId && !isSelectedViaGroup(appState, element))
) {
const boundTextElementId = getBoundTextElementId(element);
if (boundTextElementId) {
const textElement =
+7 -7
View File
@@ -13,7 +13,7 @@ import {
FontFamilyValues,
ExcalidrawRectangleElement,
} from "../element/types";
import { getFontString, getUpdatedTimestamp } from "../utils";
import { getFontString, getUpdatedTimestamp, isTestEnv } from "../utils";
import { randomInteger, randomId } from "../random";
import { mutateElement, newElementWith } from "./mutateElement";
import { getNewGroupIdsForDuplication } from "../groups";
@@ -24,7 +24,7 @@ import { getResizedElementAbsoluteCoords } from "./bounds";
import { measureText } from "./textElement";
import { isBoundToContainer } from "./typeChecks";
import Scene from "../scene/Scene";
import { PADDING } from "../constants";
import { BOUND_TEXT_PADDING } from "../constants";
type ElementConstructorOpts = MarkOptional<
Omit<ExcalidrawGenericElement, "id" | "type" | "isDeleted" | "updated">,
@@ -219,11 +219,11 @@ const getAdjustedDimensions = (
const container = Scene.getScene(element)!.getElement(element.containerId)!;
let height = container.height;
let width = container.width;
if (nextHeight > height - PADDING * 2) {
height = nextHeight + PADDING * 2;
if (nextHeight > height - BOUND_TEXT_PADDING * 2) {
height = nextHeight + BOUND_TEXT_PADDING * 2;
}
if (nextWidth > width - PADDING * 2) {
width = nextWidth + PADDING * 2;
if (nextWidth > width - BOUND_TEXT_PADDING * 2) {
width = nextWidth + BOUND_TEXT_PADDING * 2;
}
if (height !== container.height || width !== container.width) {
mutateElement(container, { height, width });
@@ -369,7 +369,7 @@ export const duplicateElement = <TElement extends Mutable<ExcalidrawElement>>(
overrides?: Partial<TElement>,
): TElement => {
let copy: TElement = deepCopyElement(element);
if (process.env.NODE_ENV === "test") {
if (isTestEnv()) {
copy.id = `${copy.id}_copy`;
// `window.h` may not be defined in some unit tests
if (
+140
View File
@@ -0,0 +1,140 @@
import { wrapText } from "./textElement";
import { FontString } from "./types";
describe("Test wrapText", () => {
const font = "20px Cascadia, width: Segoe UI Emoji" as FontString;
describe("When text doesn't contain new lines", () => {
const text = "Hello whats up";
[
{
desc: "break all words when width of each word is less than container width",
width: 90,
res: `Hello
whats
up`,
},
{
desc: "break all characters when width of each character is less than container width",
width: 25,
res: `H
e
l
l
o
w
h
a
t
s
u
p`,
},
{
desc: "break words as per the width",
width: 150,
res: `Hello whats
up`,
},
{
desc: "fit the container",
width: 250,
res: "Hello whats up",
},
].forEach((data) => {
it(`should ${data.desc}`, () => {
const res = wrapText(text, font, data.width);
expect(res).toEqual(data.res);
});
});
});
describe("When text contain new lines", () => {
const text = `Hello
whats up`;
[
{
desc: "break all words when width of each word is less than container width",
width: 90,
res: `Hello
whats
up`,
},
{
desc: "break all characters when width of each character is less than container width",
width: 25,
res: `H
e
l
l
o
w
h
a
t
s
u
p`,
},
{
desc: "break words as per the width",
width: 150,
res: `Hello
whats up`,
},
{
desc: "fit the container",
width: 250,
res: `Hello
whats up`,
},
].forEach((data) => {
it(`should respect new lines and ${data.desc}`, () => {
const res = wrapText(text, font, data.width);
expect(res).toEqual(data.res);
});
});
});
describe("When text is long", () => {
const text = `hellolongtextthisiswhatsupwithyouIamtypingggggandtypinggg break it now`;
[
{
desc: "fit characters of long string as per container width",
width: 170,
res: `hellolongtextth
isiswhatsupwith
youIamtypingggg
gandtypinggg
break it now`,
},
{
desc: "fit characters of long string as per container width and break words as per the width",
width: 130,
res: `hellolongte
xtthisiswha
tsupwithyou
Iamtypinggg
ggandtyping
gg break it
now`,
},
{
desc: "fit the long text when container width is greater than text length and move the rest to next line",
width: 600,
res: `hellolongtextthisiswhatsupwithyouIamtypingggggandtypinggg
break it now`,
},
].forEach((data) => {
it(`should ${data.desc}`, () => {
const res = wrapText(text, font, data.width);
expect(res).toEqual(data.res);
});
});
});
});
+77 -42
View File
@@ -1,20 +1,34 @@
import { getFontString, arrayToMap } from "../utils";
import { getFontString, arrayToMap, isTestEnv } from "../utils";
import {
ExcalidrawBindableElement,
ExcalidrawElement,
ExcalidrawTextElement,
ExcalidrawTextElementWithContainer,
FontString,
NonDeletedExcalidrawElement,
} from "./types";
import { mutateElement } from "./mutateElement";
import { PADDING } from "../constants";
import { BOUND_TEXT_PADDING } from "../constants";
import { MaybeTransformHandleType } from "./transformHandles";
import Scene from "../scene/Scene";
import { AppState } from "../types";
export const redrawTextBoundingBox = (element: ExcalidrawTextElement) => {
let maxWidth;
if (element.containerId) {
maxWidth = element.width;
export const redrawTextBoundingBox = (
element: ExcalidrawTextElement,
container: ExcalidrawElement | null,
appState: AppState,
) => {
const maxWidth = container
? container.width - BOUND_TEXT_PADDING * 2
: undefined;
let text = element.text;
if (container) {
text = wrapText(
element.originalText,
getFontString(element),
container.width,
);
}
const metrics = measureText(
element.originalText,
@@ -22,10 +36,24 @@ export const redrawTextBoundingBox = (element: ExcalidrawTextElement) => {
maxWidth,
);
let coordY = element.y;
// Resize container and vertically center align the text
if (container) {
coordY = container.y + container.height / 2 - metrics.height / 2;
let nextHeight = container.height;
if (metrics.height > container.height - BOUND_TEXT_PADDING * 2) {
nextHeight = metrics.height + BOUND_TEXT_PADDING * 2;
coordY = container.y + nextHeight / 2 - metrics.height / 2;
}
mutateElement(container, { height: nextHeight });
}
mutateElement(element, {
width: metrics.width,
height: metrics.height,
baseline: metrics.baseline,
y: coordY,
text,
});
};
@@ -82,20 +110,12 @@ export const handleBindTextResize = (
let containerHeight = element.height;
let nextBaseLine = textElement.baseline;
if (transformHandleType !== "n" && transformHandleType !== "s") {
let minCharWidthTillNow = 0;
if (text) {
minCharWidthTillNow = getMinCharWidth(getFontString(textElement));
// check if the diff has exceeded min char width needed
const diff = Math.abs(
element.width - textElement.width + PADDING * 2,
text = wrapText(
textElement.originalText,
getFontString(textElement),
element.width,
);
if (diff >= minCharWidthTillNow) {
text = wrapText(
textElement.originalText,
getFontString(textElement),
element.width,
);
}
}
const dimensions = measureText(
@@ -107,8 +127,8 @@ export const handleBindTextResize = (
nextBaseLine = dimensions.baseline;
}
// increase height in case text element height exceeds
if (nextHeight > element.height - PADDING * 2) {
containerHeight = nextHeight + PADDING * 2;
if (nextHeight > element.height - BOUND_TEXT_PADDING * 2) {
containerHeight = nextHeight + BOUND_TEXT_PADDING * 2;
const diff = containerHeight - element.height;
// fix the y coord when resizing from ne/nw/n
const updatedY =
@@ -127,9 +147,9 @@ export const handleBindTextResize = (
mutateElement(textElement, {
text,
// preserve padding and set width correctly
width: element.width - PADDING * 2,
width: element.width - BOUND_TEXT_PADDING * 2,
height: nextHeight,
x: element.x + PADDING,
x: element.x + BOUND_TEXT_PADDING,
y: updatedY,
baseline: nextBaseLine,
});
@@ -198,6 +218,12 @@ const getTextWidth = (text: string, font: FontString) => {
canvas2dContext.font = font;
const metrics = canvas2dContext.measureText(text);
// since in test env the canvas measureText algo
// doesn't measure text and instead just returns number of
// characters hence we assume that each letteris 10px
if (isTestEnv()) {
return metrics.width * 10;
}
return metrics.width;
};
@@ -207,7 +233,7 @@ export const wrapText = (
font: FontString,
containerWidth: number,
) => {
const maxWidth = containerWidth - PADDING * 2;
const maxWidth = containerWidth - BOUND_TEXT_PADDING * 2;
const lines: Array<string> = [];
const originalLines = text.split("\n");
@@ -226,7 +252,7 @@ export const wrapText = (
const currentWordWidth = getTextWidth(words[index], font);
// Start breaking longer words exceeding max width
if (currentWordWidth > maxWidth) {
if (currentWordWidth >= maxWidth) {
// push current line since the current word exceeds the max width
// so will be appended in next line
if (currentLine) {
@@ -257,7 +283,7 @@ export const wrapText = (
}
}
// push current line if appending space exceeds max width
if (currentLineWidthTillNow + spaceWidth > maxWidth) {
if (currentLineWidthTillNow + spaceWidth >= maxWidth) {
lines.push(currentLine);
currentLine = "";
currentLineWidthTillNow = 0;
@@ -285,8 +311,15 @@ export const wrapText = (
}
index++;
currentLine += `${word} `;
}
// Push the word if appending space exceeds max width
if (currentLineWidthTillNow + spaceWidth >= maxWidth) {
lines.push(currentLine.slice(0, -1));
currentLine = "";
currentLineWidthTillNow = 0;
break;
}
}
if (currentLineWidthTillNow === maxWidth) {
currentLine = "";
currentLineWidthTillNow = 0;
@@ -320,34 +353,23 @@ export const charWidth = (() => {
return cachedCharWidth[font][ascii];
};
const updateCache = (char: string, font: FontString) => {
const ascii = char.charCodeAt(0);
if (!cachedCharWidth[font][ascii]) {
cachedCharWidth[font][ascii] = calculate(char, font);
}
};
const clearCacheforFont = (font: FontString) => {
cachedCharWidth[font] = [];
};
const getCache = (font: FontString) => {
return cachedCharWidth[font];
};
return {
calculate,
updateCache,
clearCacheforFont,
getCache,
};
})();
export const getApproxMinLineWidth = (font: FontString) => {
return measureText(DUMMY_TEXT.split("").join("\n"), font).width + PADDING * 2;
return (
measureText(DUMMY_TEXT.split("").join("\n"), font).width +
BOUND_TEXT_PADDING * 2
);
};
export const getApproxMinLineHeight = (font: FontString) => {
return getApproxLineHeight(font) + PADDING * 2;
return getApproxLineHeight(font) + BOUND_TEXT_PADDING * 2;
};
export const getMinCharWidth = (font: FontString) => {
@@ -387,3 +409,16 @@ export const getApproxCharsToFitInWidth = (font: FontString, width: number) => {
export const getBoundTextElementId = (container: ExcalidrawElement | null) => {
return container?.boundElements?.filter((ele) => ele.type === "text")[0]?.id;
};
export const getBoundTextElement = (element: ExcalidrawElement | null) => {
if (!element) {
return null;
}
const boundTextElementId = getBoundTextElementId(element);
if (boundTextElementId) {
return Scene.getScene(element)!.getElement(
boundTextElementId,
) as ExcalidrawTextElementWithContainer;
}
return null;
};
+87 -56
View File
@@ -2,12 +2,11 @@ import { CODES, KEYS } from "../keys";
import {
isWritableElement,
getFontString,
viewportCoordsToSceneCoords,
getFontFamilyString,
} from "../utils";
import Scene from "../scene/Scene";
import { isBoundToContainer, isTextElement } from "./typeChecks";
import { CLASSES, PADDING } from "../constants";
import { CLASSES, BOUND_TEXT_PADDING } from "../constants";
import {
ExcalidrawBindableElement,
ExcalidrawElement,
@@ -37,16 +36,20 @@ const getTransform = (
angle: number,
appState: AppState,
maxWidth: number,
maxHeight: number,
) => {
const { zoom, offsetTop, offsetLeft } = appState;
const degree = (180 * angle) / Math.PI;
// offsets must be multiplied by 2 to account for the division by 2 of
// the whole expression afterwards
let translateX = ((width - offsetLeft * 2) * (zoom.value - 1)) / 2;
const translateY = ((height - offsetTop * 2) * (zoom.value - 1)) / 2;
let translateY = ((height - offsetTop * 2) * (zoom.value - 1)) / 2;
if (width > maxWidth && zoom.value !== 1) {
translateX = (maxWidth / 2) * (zoom.value - 1);
}
if (height > maxHeight && zoom.value !== 1) {
translateY = ((maxHeight - offsetTop * 2) * (zoom.value - 1)) / 2;
}
return `translate(${translateX}px, ${translateY}px) scale(${zoom.value}) rotate(${degree}deg)`;
};
@@ -99,83 +102,68 @@ export const textWysiwyg = ({
if (updatedElement && isTextElement(updatedElement)) {
let coordX = updatedElement.x;
let coordY = updatedElement.y;
let container = updatedElement?.containerId
const container = updatedElement?.containerId
? Scene.getScene(updatedElement)!.getElement(updatedElement.containerId)
: null;
let maxWidth = updatedElement.width;
let maxHeight = updatedElement.height;
let width = updatedElement.width;
// Set to element height by default since thats
// what is going to be used for unbounded text
let height = updatedElement.height;
if (container && updatedElement.containerId) {
const propertiesUpdated = textPropertiesUpdated(
updatedElement,
editable,
);
// using editor.style.height to get the accurate height of text editor
const editorHeight = Number(editable.style.height.slice(0, -2));
if (editorHeight > 0) {
height = editorHeight;
}
if (propertiesUpdated) {
const currentContainer = Scene.getScene(updatedElement)?.getElement(
updatedElement.containerId,
) as ExcalidrawBindableElement;
approxLineHeight = isTextElement(updatedElement)
? getApproxLineHeight(getFontString(updatedElement))
: 0;
if (updatedElement.height > currentContainer.height - PADDING * 2) {
const nextHeight = updatedElement.height + PADDING * 2;
originalContainerHeight = nextHeight;
mutateElement(container, { height: nextHeight });
container = { ...container, height: nextHeight };
}
editable.style.height = `${updatedElement.height}px`;
originalContainerHeight = container.height;
// update height of the editor after properties updated
height = updatedElement.height;
}
if (!originalContainerHeight) {
originalContainerHeight = container.height;
}
maxWidth = container.width - PADDING * 2;
maxHeight = container.height - PADDING * 2;
maxWidth = container.width - BOUND_TEXT_PADDING * 2;
maxHeight = container.height - BOUND_TEXT_PADDING * 2;
width = maxWidth;
height = Math.min(height, maxHeight);
// The coordinates of text box set a distance of
// 30px to preserve padding
coordX = container.x + PADDING;
coordX = container.x + BOUND_TEXT_PADDING;
// autogrow container height if text exceeds
if (editable.clientHeight > maxHeight) {
const diff = Math.min(
editable.clientHeight - maxHeight,
approxLineHeight,
);
if (height > maxHeight) {
const diff = Math.min(height - maxHeight, approxLineHeight);
mutateElement(container, { height: container.height + diff });
return;
} else if (
// autoshrink container height until original container height
// is reached when text is removed
container.height > originalContainerHeight &&
editable.clientHeight < maxHeight
height < maxHeight
) {
const diff = Math.min(
maxHeight - editable.clientHeight,
approxLineHeight,
);
const diff = Math.min(maxHeight - height, approxLineHeight);
mutateElement(container, { height: container.height - diff });
}
// Start pushing text upward until a diff of 30px (padding)
// is reached
else {
const lines = editable.clientHeight / approxLineHeight;
// For some reason the scrollHeight gets set to twice the lineHeight
// when you start typing for first time and thus line count is 2
// hence this check
if (lines > 2 || propertiesUpdated) {
// vertically center align the text
coordY =
container.y + container.height / 2 - editable.clientHeight / 2;
}
// vertically center align the text
coordY = container.y + container.height / 2 - height / 2;
}
}
const [viewportX, viewportY] = getViewportCoords(coordX, coordY);
const { textAlign, angle } = updatedElement;
const { textAlign } = updatedElement;
editable.value = updatedElement.originalText || updatedElement.text;
const lines = updatedElement.originalText.split("\n");
const lineHeight = updatedElement.containerId
@@ -192,19 +180,36 @@ export const textWysiwyg = ({
).marginRight.slice(0, -2),
);
}
// Make sure text editor height doesn't go beyond viewport
const editorMaxHeight =
(appState.offsetTop + appState.height - viewportY) /
(appState.height -
viewportY -
// There is a ~14px difference which keeps on increasing
// with every zoom step when offset present hence I am subtracting it here
// However this is not the best fix and breaks in
// few scenarios
(appState.offsetTop
? ((appState.zoom.value * 100 - 100) / 10) * 14
: 0)) /
appState.zoom.value;
const angle = container ? container.angle : updatedElement.angle;
Object.assign(editable.style, {
font: getFontString(updatedElement),
// must be defined *after* font ¯\_(ツ)_/¯
lineHeight: `${lineHeight}px`,
width: `${width}px`,
height: `${Math.max(editable.clientHeight, updatedElement.height)}px`,
height: `${height}px`,
left: `${viewportX}px`,
top: `${viewportY}px`,
transform: getTransform(width, height, angle, appState, maxWidth),
transform: getTransform(
width,
height,
angle,
appState,
maxWidth,
editorMaxHeight,
),
textAlign,
color: updatedElement.strokeColor,
opacity: updatedElement.opacity / 100,
@@ -254,8 +259,37 @@ export const textWysiwyg = ({
if (onChange) {
editable.oninput = () => {
if (isBoundToContainer(element)) {
editable.style.height = "auto";
// using scrollHeight here since we need to calculate
// number of lines so cannot use editable.style.height
// as that gets updated below
const lines = editable.scrollHeight / approxLineHeight;
// auto increase height only when lines > 1 so its
// measured correctly and vertically alignes for
// first line as well as setting height to "auto"
// doubles the height as soon as user starts typing
if (isBoundToContainer(element) && lines > 1) {
let height = "auto";
if (lines === 2) {
const container = Scene.getScene(element)!.getElement(
element.containerId,
);
const actualLineCount = wrapText(
editable.value,
getFontString(element),
container!.width,
).split("\n").length;
// This is browser behaviour when setting height to "auto"
// It sets the height needed for 2 lines even if actual
// line count is 1 as mentioned above as well
// hence reducing the height by half if actual line count is 1
// so single line aligns vertically when deleting
if (actualLineCount === 1) {
height = `${editable.scrollHeight / 2}px`;
}
}
editable.style.height = height;
editable.style.height = `${editable.scrollHeight}px`;
}
onChange(normalizeText(editable.value));
@@ -416,20 +450,17 @@ export const textWysiwyg = ({
getFontString(updateElement),
container.width,
);
const { x, y } = viewportCoordsToSceneCoords(
{
clientX: Number(editable.style.left.slice(0, -2)),
clientY: Number(editable.style.top.slice(0, -2)),
},
appState,
);
if (isTextElement(updateElement) && updateElement.containerId) {
const editorHeight = Number(editable.style.height.slice(0, -2));
if (editable.value) {
mutateElement(updateElement, {
y: y + appState.offsetTop,
height: Number(editable.style.height.slice(0, -2)),
// vertically center align
y: container.y + container.height / 2 - editorHeight / 2,
height: editorHeight,
width: Number(editable.style.width.slice(0, -2)),
x: x + appState.offsetLeft,
// preserve padding
x: container.x + BOUND_TEXT_PADDING,
angle: container.angle,
});
const boundTextElementId = getBoundTextElementId(container);
if (!boundTextElementId || boundTextElementId !== element.id) {
+38 -1
View File
@@ -1,6 +1,13 @@
import { GroupId, ExcalidrawElement, NonDeleted } from "./element/types";
import {
GroupId,
ExcalidrawElement,
NonDeleted,
ExcalidrawTextElementWithContainer,
} from "./element/types";
import { AppState } from "./types";
import { getSelectedElements } from "./scene";
import { getBoundTextElementId } from "./element/textElement";
import Scene from "./scene/Scene";
export const selectGroup = (
groupId: GroupId,
@@ -158,3 +165,33 @@ export const removeFromSelectedGroups = (
groupIds: ExcalidrawElement["groupIds"],
selectedGroupIds: { [groupId: string]: boolean },
) => groupIds.filter((groupId) => !selectedGroupIds[groupId]);
export const getMaximumGroups = (
elements: ExcalidrawElement[],
): ExcalidrawElement[][] => {
const groups: Map<String, ExcalidrawElement[]> = new Map<
String,
ExcalidrawElement[]
>();
elements.forEach((element: ExcalidrawElement) => {
const groupId =
element.groupIds.length === 0
? element.id
: element.groupIds[element.groupIds.length - 1];
const currentGroupMembers = groups.get(groupId) || [];
// Include bounded text if present when grouping
const boundTextElementId = getBoundTextElementId(element);
if (boundTextElementId) {
const textElement = Scene.getScene(element)!.getElement(
boundTextElementId,
) as ExcalidrawTextElementWithContainer;
currentGroupMembers.push(textElement);
}
groups.set(groupId, [...currentGroupMembers, element]);
});
return Array.from(groups.values());
};
+4 -1
View File
@@ -208,7 +208,8 @@
"lineEditor_nothingSelected": "Select a point to edit (hold SHIFT to select multiple),\nor hold Alt and click to add new points",
"placeImage": "Click to place the image, or click and drag to set its size manually",
"publishLibrary": "Publish your own library",
"bindTextToElement": "Press enter to add text"
"bindTextToElement": "Press enter to add text",
"deepBoxSelect": "Hold CtrlOrCmd to deep select, and to prevent dragging"
},
"canvasError": {
"cannotShowPreview": "Cannot show preview",
@@ -255,6 +256,8 @@
"helpDialog": {
"blog": "Read our blog",
"click": "click",
"deepSelect": "Deep select",
"deepBoxSelect": "Deep select within box, and prevent dragging",
"curvedArrow": "Curved arrow",
"curvedLine": "Curved line",
"documentation": "Documentation",
+7
View File
@@ -64,8 +64,15 @@ Please add the latest change on the top under the correct section.
The `Appearance` type is now removed and renamed to `Theme` so `Theme` type needs to be used.
### Fixes
- 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.
### 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`
- 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)
+18
View File
@@ -1008,3 +1008,21 @@ 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/)
+249
View File
@@ -0,0 +1,249 @@
import { useEffect, useState, useRef } from "react";
import InitialData from "./initialData";
import Sidebar from "./sidebar/Sidebar";
import "./App.scss";
import initialData from "./initialData";
// 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 renderTopRightUI = () => {
return (
<button onClick={() => alert("This is dummy top right UI")}>
{" "}
Click me{" "}
</button>
);
};
const renderFooter = () => {
return (
<button onClick={() => alert("This is dummy footer")}>
{" "}
custom footer{" "}
</button>
);
};
export default function App() {
const excalidrawRef = useRef(null);
const [viewModeEnabled, setViewModeEnabled] = useState(false);
const [zenModeEnabled, setZenModeEnabled] = useState(false);
const [gridModeEnabled, setGridModeEnabled] = useState(false);
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");
useEffect(() => {
const onHashChange = () => {
const hash = new URLSearchParams(window.location.hash.slice(1));
const libraryUrl = hash.get("addLibrary");
if (libraryUrl) {
excalidrawRef.current.importLibrary(libraryUrl, hash.get("token"));
}
};
window.addEventListener("hashchange", onHashChange, false);
return () => {
window.removeEventListener("hashchange", onHashChange);
};
}, []);
const updateScene = () => {
const sceneData = {
elements: [
{
type: "rectangle",
version: 141,
versionNonce: 361174001,
isDeleted: false,
id: "oDVXy8D6rom3H1-LLH2-f",
fillStyle: "hachure",
strokeWidth: 1,
strokeStyle: "solid",
roughness: 1,
opacity: 100,
angle: 0,
x: 100.50390625,
y: 93.67578125,
strokeColor: "#c92a2a",
backgroundColor: "transparent",
width: 186.47265625,
height: 141.9765625,
seed: 1968410350,
groupIds: [],
},
],
appState: {
viewBackgroundColor: "#edf2ff",
},
};
excalidrawRef.current.updateScene(sceneData);
};
return (
<div className="App">
<h1> Excalidraw Example</h1>
<Sidebar>
<div className="button-wrapper">
<button className="update-scene" onClick={updateScene}>
Update Scene
</button>
<button
className="reset-scene"
onClick={() => {
excalidrawRef.current.resetScene();
}}
>
Reset Scene
</button>
<label>
<input
type="checkbox"
checked={viewModeEnabled}
onChange={() => setViewModeEnabled(!viewModeEnabled)}
/>
View mode
</label>
<label>
<input
type="checkbox"
checked={zenModeEnabled}
onChange={() => setZenModeEnabled(!zenModeEnabled)}
/>
Zen mode
</label>
<label>
<input
type="checkbox"
checked={gridModeEnabled}
onChange={() => setGridModeEnabled(!gridModeEnabled)}
/>
Grid mode
</label>
<label>
<input
type="checkbox"
checked={theme === "dark"}
onChange={() => {
let newTheme = "light";
if (theme === "light") {
newTheme = "dark";
}
setTheme(newTheme);
}}
/>
Switch to Dark Theme
</label>
</div>
<div className="excalidraw-wrapper">
<Excalidraw
ref={excalidrawRef}
initialData={InitialData}
onChange={(elements, state) =>
console.info("Elements :", elements, "State : ", state)
}
onPointerUpdate={(payload) => console.info(payload)}
onCollabButtonClick={() =>
window.alert("You clicked on collab button")
}
viewModeEnabled={viewModeEnabled}
zenModeEnabled={zenModeEnabled}
gridModeEnabled={gridModeEnabled}
theme={theme}
name="Custom name of drawing"
UIOptions={{ canvasActions: { loadScene: false } }}
renderTopRightUI={renderTopRightUI}
renderFooter={renderFooter}
/>
</div>
<div className="export-wrapper button-wrapper">
<label className="export-wrapper__checkbox">
<input
type="checkbox"
checked={exportWithDarkMode}
onChange={() => setExportWithDarkMode(!exportWithDarkMode)}
/>
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({
elements: excalidrawRef.current.getSceneElements(),
appState: {
...initialData.appState,
exportWithDarkMode,
shouldAddWatermark,
width: 300,
height: 100,
},
embedScene: true,
});
document.querySelector(".export-svg").innerHTML = svg.outerHTML;
}}
>
Export to SVG
</button>
<div className="export export-svg"></div>
<button
onClick={async () => {
const blob = await exportToBlob({
elements: excalidrawRef.current.getSceneElements(),
mimeType: "image/png",
appState: {
...initialData.appState,
exportWithDarkMode,
shouldAddWatermark,
},
});
setBlobUrl(window.URL.createObjectURL(blob));
}}
>
Export to Blob
</button>
<div className="export export-blob">
<img src={blobUrl} alt="" />
</div>
<button
onClick={() => {
const canvas = exportToCanvas({
elements: excalidrawRef.current.getSceneElements(),
appState: {
...initialData.appState,
exportWithDarkMode,
shouldAddWatermark,
},
});
const ctx = canvas.getContext("2d");
ctx.font = "30px Virgil";
ctx.strokeText("My custom text", 50, 60);
setCanvasUrl(canvas.toDataURL());
}}
>
Export to Canvas
</button>
<div className="export export-canvas">
<img src={canvasUrl} alt="" />
</div>
</div>
</Sidebar>
</div>
);
}
+42
View File
@@ -0,0 +1,42 @@
.App {
font-family: sans-serif;
text-align: center;
}
.button-wrapper button {
z-index: 1;
height: 40px;
max-width: 200px;
margin: 10px;
padding: 5px;
}
.excalidraw .App-menu_top .buttonList {
display: flex;
}
.excalidraw-wrapper {
height: 800px;
margin: 50px;
}
:root[dir="ltr"]
.excalidraw
.layer-ui__wrapper
.zen-mode-transition.App-menu_bottom--transition-left {
transform: none;
}
.excalidraw .panelColumn {
text-align: left;
}
.export-wrapper {
display: flex;
flex-direction: column;
margin: 50px;
&__checkbox {
display: flex;
}
}
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<meta name="theme-color" content="#000000" />
<title>React App</title>
<script>
window.name = "codesandbox";
</script>
</head>
<body>
<noscript> You need to enable JavaScript to run this app. </noscript>
<div id="root"></div>
<script src="https://unpkg.com/react@17.0.2/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17.0.2/umd/react-dom.development.js"></script>
<!-- This is so that we use the bundled excalidraw.developement.js file instead
of the actual source code -->
<script src="./excalidraw.development.js"></script>
<script src="./bundle.js"></script>
</body>
</html>
+12
View File
@@ -0,0 +1,12 @@
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
const rootElement = document.getElementById("root");
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
rootElement,
);
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,30 @@
import { useState } from "react";
import "./Sidebar.scss";
export default function Sidebar(props) {
const [open, setOpen] = useState(false);
return (
<>
<div id="mySidebar" className={`sidebar ${open ? "open" : ""}`}>
<button className="closebtn" onClick={() => setOpen(false)}>
x
</button>
<div className="sidebar-links">
<button>Dummy Home</button>
<button>Dummy About</button>{" "}
</div>
</div>
<div className={`${open ? "sidebar-open" : ""}`}>
<button
className="openbtn"
onClick={() => {
setOpen(!open);
}}
>
Open Sidebar
</button>
{props.children}
</div>
</>
);
}
@@ -0,0 +1,66 @@
.sidebar {
height: 100%;
width: 0;
position: absolute;
z-index: 1;
top: 0;
left: 0;
background-color: #111;
overflow-x: hidden;
transition: 0.5s;
padding-top: 60px;
&.open {
width: 300px;
}
&-links {
display: flex;
flex-direction: column;
padding: 20px;
button {
padding: 10px;
margin: 10px;
background: #faa2c1;
color: #fff;
border: none;
cursor: pointer;
}
}
}
.sidebar a {
padding: 8px 8px 8px 32px;
text-decoration: none;
font-size: 25px;
color: #818181;
display: block;
transition: 0.3s;
}
.sidebar a:hover {
color: #f1f1f1;
}
.sidebar .closebtn {
position: absolute;
top: 0;
right: 0;
font-size: 36px;
margin-left: 50px;
}
.openbtn {
font-size: 20px;
cursor: pointer;
background-color: #111;
color: white;
padding: 10px 15px;
border: none;
display: flex;
margin-left: 50px;
}
.sidebar-open {
margin-left: 300px;
}
+10 -7
View File
@@ -45,13 +45,13 @@
},
"devDependencies": {
"@babel/core": "7.16.0",
"@babel/plugin-transform-arrow-functions": "7.16.0",
"@babel/plugin-transform-arrow-functions": "7.16.7",
"@babel/plugin-transform-async-to-generator": "7.16.0",
"@babel/plugin-transform-runtime": "7.16.4",
"@babel/plugin-transform-typescript": "7.16.1",
"@babel/preset-env": "7.16.4",
"@babel/preset-react": "7.16.0",
"@babel/preset-typescript": "7.16.0",
"@babel/preset-env": "7.16.7",
"@babel/preset-react": "7.16.7",
"@babel/preset-typescript": "7.16.7",
"autoprefixer": "10.4.0",
"babel-loader": "8.2.3",
"babel-plugin-transform-class-properties": "6.24.1",
@@ -60,12 +60,14 @@
"mini-css-extract-plugin": "2.4.5",
"postcss-loader": "6.2.1",
"sass-loader": "12.4.0",
"terser-webpack-plugin": "5.2.5",
"terser-webpack-plugin": "5.3.0",
"ts-loader": "9.2.6",
"typescript": "4.5.3",
"webpack": "5.65.0",
"webpack-bundle-analyzer": "4.5.0",
"webpack-cli": "4.9.1"
"webpack-cli": "4.9.1",
"webpack-dev-server": "4.7.1",
"webpack-merge": "5.8.0"
},
"bugs": "https://github.com/excalidraw/excalidraw/issues",
"homepage": "https://github.com/excalidraw/excalidraw/tree/master/src/packages/excalidraw",
@@ -73,7 +75,8 @@
"gen:types": "tsc --project ../../../tsconfig-types.json",
"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"
"pack": "yarn build:umd && yarn pack",
"start": "webpack serve --config webpack.dev-server.config.js "
},
"dependencies": {
"dotenv": "10.0.0"
@@ -0,0 +1,28 @@
const path = require("path");
const { merge } = require("webpack-merge");
const devConfig = require("./webpack.dev.config");
const devServerConfig = {
entry: {
bundle: "./example/index.js",
},
// Server Configuration options
devServer: {
port: 3001,
host: "localhost",
hot: true,
compress: true,
static: {
directory: path.join(__dirname, "example"),
},
client: {
progress: true,
logging: "info",
overlay: true, //Shows a full-screen overlay in the browser when there are compiler errors or warnings.
},
open: ["./"],
},
};
module.exports = merge(devServerConfig, devConfig);
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -34,13 +34,13 @@
]
},
"devDependencies": {
"@babel/core": "7.16.0",
"@babel/core": "7.16.5",
"@babel/plugin-transform-arrow-functions": "7.16.0",
"@babel/plugin-transform-async-to-generator": "7.16.0",
"@babel/plugin-transform-async-to-generator": "7.16.5",
"@babel/plugin-transform-runtime": "^7.14.5",
"@babel/plugin-transform-typescript": "7.16.1",
"@babel/preset-env": "7.16.4",
"@babel/preset-typescript": "7.16.0",
"@babel/preset-typescript": "7.16.5",
"babel-loader": "8.2.3",
"babel-plugin-transform-class-properties": "6.24.1",
"cross-env": "7.0.3",
+93 -81
View File
@@ -14,19 +14,19 @@
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.0":
version "7.16.0"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.0.tgz#c4ff44046f5fe310525cc9eb4ef5147f0c5374d4"
integrity sha512-mYZEvshBRHGsIAiyH5PzCFTCfbWfoYbO/jcSdXQSUQu1/pW0xDZAUP7KEc32heqWTAfAHhV9j1vH8Sav7l+JNQ==
"@babel/core@7.16.5":
version "7.16.5"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.5.tgz#924aa9e1ae56e1e55f7184c8bf073a50d8677f5c"
integrity sha512-wUcenlLzuWMZ9Zt8S0KmFwGlH6QKRh3vsm/dhDA3CHkiTA45YuG1XkHRcNRl73EFPXDp/d5kVOU0/y7x2w6OaQ==
dependencies:
"@babel/code-frame" "^7.16.0"
"@babel/generator" "^7.16.0"
"@babel/helper-compilation-targets" "^7.16.0"
"@babel/helper-module-transforms" "^7.16.0"
"@babel/helpers" "^7.16.0"
"@babel/parser" "^7.16.0"
"@babel/generator" "^7.16.5"
"@babel/helper-compilation-targets" "^7.16.3"
"@babel/helper-module-transforms" "^7.16.5"
"@babel/helpers" "^7.16.5"
"@babel/parser" "^7.16.5"
"@babel/template" "^7.16.0"
"@babel/traverse" "^7.16.0"
"@babel/traverse" "^7.16.5"
"@babel/types" "^7.16.0"
convert-source-map "^1.7.0"
debug "^4.1.0"
@@ -35,10 +35,10 @@
semver "^6.3.0"
source-map "^0.5.0"
"@babel/generator@^7.16.0":
version "7.16.0"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.0.tgz#d40f3d1d5075e62d3500bccb67f3daa8a95265b2"
integrity sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew==
"@babel/generator@^7.16.5":
version "7.16.5"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.5.tgz#26e1192eb8f78e0a3acaf3eede3c6fc96d22bedf"
integrity sha512-kIvCdjZqcdKqoDbVVdt5R99icaRtrtYhYK/xux5qiWCBmfdvEYMFZ68QCrpE5cbFM1JsuArUNs1ZkuKtTtUcZA==
dependencies:
"@babel/types" "^7.16.0"
jsesc "^2.5.1"
@@ -103,6 +103,13 @@
resolve "^1.14.2"
semver "^6.1.2"
"@babel/helper-environment-visitor@^7.16.5":
version "7.16.5"
resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.5.tgz#f6a7f38b3c6d8b07c88faea083c46c09ef5451b8"
integrity sha512-ODQyc5AnxmZWm/R2W7fzhamOk1ey8gSguo5SGvF0zcB3uUzRpTRmM/jmLSm9bDMyPlvbyJ+PwPEK0BWIoZ9wjg==
dependencies:
"@babel/types" "^7.16.0"
"@babel/helper-explode-assignable-expression@^7.16.0":
version "7.16.0"
resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.0.tgz#753017337a15f46f9c09f674cff10cee9b9d7778"
@@ -140,25 +147,25 @@
dependencies:
"@babel/types" "^7.16.0"
"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.0":
version "7.16.0"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz#90538e60b672ecf1b448f5f4f5433d37e79a3ec3"
integrity sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg==
"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.0", "@babel/helper-module-imports@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437"
integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==
dependencies:
"@babel/types" "^7.16.0"
"@babel/types" "^7.16.7"
"@babel/helper-module-transforms@^7.16.0":
version "7.16.0"
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz#1c82a8dd4cb34577502ebd2909699b194c3e9bb5"
integrity sha512-My4cr9ATcaBbmaEa8M0dZNA74cfI6gitvUAskgDtAFmAqyFKDSHQo5YstxPbN+lzHl2D9l/YOEFqb2mtUh4gfA==
"@babel/helper-module-transforms@^7.16.0", "@babel/helper-module-transforms@^7.16.5":
version "7.16.5"
resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.5.tgz#530ebf6ea87b500f60840578515adda2af470a29"
integrity sha512-CkvMxgV4ZyyioElFwcuWnDCcNIeyqTkCm9BxXZi73RR1ozqlpboqsbGUNvRTflgZtFbbJ1v5Emvm+lkjMYY/LQ==
dependencies:
"@babel/helper-environment-visitor" "^7.16.5"
"@babel/helper-module-imports" "^7.16.0"
"@babel/helper-replace-supers" "^7.16.0"
"@babel/helper-simple-access" "^7.16.0"
"@babel/helper-split-export-declaration" "^7.16.0"
"@babel/helper-validator-identifier" "^7.15.7"
"@babel/template" "^7.16.0"
"@babel/traverse" "^7.16.0"
"@babel/traverse" "^7.16.5"
"@babel/types" "^7.16.0"
"@babel/helper-optimise-call-expression@^7.16.0":
@@ -168,27 +175,18 @@
dependencies:
"@babel/types" "^7.16.0"
"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
version "7.14.5"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9"
integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==
"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5"
integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA==
"@babel/helper-remap-async-to-generator@^7.16.0":
version "7.16.0"
resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.0.tgz#d5aa3b086e13a5fe05238ff40c3a5a0c2dab3ead"
integrity sha512-MLM1IOMe9aQBqMWxcRw8dcb9jlM86NIw7KA0Wri91Xkfied+dE0QuBFSBjMNvqzmS0OSIDsMNC24dBEkPUi7ew==
"@babel/helper-remap-async-to-generator@^7.16.4", "@babel/helper-remap-async-to-generator@^7.16.5":
version "7.16.5"
resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.5.tgz#e706646dc4018942acb4b29f7e185bc246d65ac3"
integrity sha512-X+aAJldyxrOmN9v3FKp+Hu1NO69VWgYgDGq6YDykwRPzxs5f2N+X988CBXS7EQahDU+Vpet5QYMqLk+nsp+Qxw==
dependencies:
"@babel/helper-annotate-as-pure" "^7.16.0"
"@babel/helper-wrap-function" "^7.16.0"
"@babel/types" "^7.16.0"
"@babel/helper-remap-async-to-generator@^7.16.4":
version "7.16.4"
resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.4.tgz#5d7902f61349ff6b963e07f06a389ce139fbfe6e"
integrity sha512-vGERmmhR+s7eH5Y/cp8PCVzj4XEjerq8jooMfxFdA5xVtAk9Sh4AQsrWgiErUEBjtGrBtOFKDUcWQFW4/dFwMA==
dependencies:
"@babel/helper-annotate-as-pure" "^7.16.0"
"@babel/helper-wrap-function" "^7.16.0"
"@babel/helper-wrap-function" "^7.16.5"
"@babel/types" "^7.16.0"
"@babel/helper-replace-supers@^7.16.0":
@@ -227,28 +225,33 @@
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389"
integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==
"@babel/helper-validator-identifier@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad"
integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==
"@babel/helper-validator-option@^7.14.5":
version "7.14.5"
resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3"
integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==
"@babel/helper-wrap-function@^7.16.0":
version "7.16.0"
resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.0.tgz#b3cf318afce774dfe75b86767cd6d68f3482e57c"
integrity sha512-VVMGzYY3vkWgCJML+qVLvGIam902mJW0FvT7Avj1zEe0Gn7D93aWdLblYARTxEw+6DhZmtzhBM2zv0ekE5zg1g==
"@babel/helper-wrap-function@^7.16.5":
version "7.16.5"
resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.5.tgz#0158fca6f6d0889c3fee8a6ed6e5e07b9b54e41f"
integrity sha512-2J2pmLBqUqVdJw78U0KPNdeE2qeuIyKoG4mKV7wAq3mc4jJG282UgjZw4ZYDnqiWQuS3Y3IYdF/AQ6CpyBV3VA==
dependencies:
"@babel/helper-function-name" "^7.16.0"
"@babel/template" "^7.16.0"
"@babel/traverse" "^7.16.0"
"@babel/traverse" "^7.16.5"
"@babel/types" "^7.16.0"
"@babel/helpers@^7.16.0":
version "7.16.0"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.0.tgz#875519c979c232f41adfbd43a3b0398c2e388183"
integrity sha512-dVRM0StFMdKlkt7cVcGgwD8UMaBfWJHl3A83Yfs8GQ3MO0LHIIIMvK7Fa0RGOGUQ10qikLaX6D7o5htcQWgTMQ==
"@babel/helpers@^7.16.5":
version "7.16.5"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.5.tgz#29a052d4b827846dd76ece16f565b9634c554ebd"
integrity sha512-TLgi6Lh71vvMZGEkFuIxzaPsyeYCHQ5jJOOX1f0xXn0uciFuE8cEk0wyBquMcCxBXZ5BJhE2aUB7pnWTD150Tw==
dependencies:
"@babel/template" "^7.16.0"
"@babel/traverse" "^7.16.0"
"@babel/traverse" "^7.16.5"
"@babel/types" "^7.16.0"
"@babel/highlight@^7.16.0":
@@ -260,10 +263,10 @@
chalk "^2.0.0"
js-tokens "^4.0.0"
"@babel/parser@^7.16.0":
version "7.16.0"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.0.tgz#cf147d7ada0a3655e79bf4b08ee846f00a00a295"
integrity sha512-TEHWXf0xxpi9wKVyBCmRcSSDjbJ/cl6LUdlbYUHEaNQUJGhreJbZrXT6sR4+fZLxVUJqNRB4KyOvjuy/D9009A==
"@babel/parser@^7.16.0", "@babel/parser@^7.16.5":
version "7.16.6"
resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.6.tgz#8f194828193e8fa79166f34a4b4e52f3e769a314"
integrity sha512-Gr86ujcNuPDnNOY8mi383Hvi8IYrJVJYuf3XcuBM/Dgd+bINn/7tHqsj+tKkoreMbmGsFLsltI/JJd8fOFWGDQ==
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.2":
version "7.16.2"
@@ -521,14 +524,14 @@
dependencies:
"@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-transform-async-to-generator@7.16.0", "@babel/plugin-transform-async-to-generator@^7.16.0":
version "7.16.0"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.0.tgz#df12637f9630ddfa0ef9d7a11bc414d629d38604"
integrity sha512-PbIr7G9kR8tdH6g8Wouir5uVjklETk91GMVSUq+VaOgiinbCkBP6Q7NN/suM/QutZkMJMvcyAriogcYAdhg8Gw==
"@babel/plugin-transform-async-to-generator@7.16.5", "@babel/plugin-transform-async-to-generator@^7.16.0":
version "7.16.5"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.5.tgz#89c9b501e65bb14c4579a6ce9563f859de9b34e4"
integrity sha512-TMXgfioJnkXU+XRoj7P2ED7rUm5jbnDWwlCuFVTpQboMfbSya5WrmubNBAMlk7KXvywpo8rd8WuYZkis1o2H8w==
dependencies:
"@babel/helper-module-imports" "^7.16.0"
"@babel/helper-plugin-utils" "^7.14.5"
"@babel/helper-remap-async-to-generator" "^7.16.0"
"@babel/helper-plugin-utils" "^7.16.5"
"@babel/helper-remap-async-to-generator" "^7.16.5"
"@babel/plugin-transform-block-scoped-functions@^7.16.0":
version "7.16.0"
@@ -712,12 +715,12 @@
"@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-transform-runtime@^7.14.5":
version "7.16.4"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.4.tgz#f9ba3c7034d429c581e1bd41b4952f3db3c2c7e8"
integrity sha512-pru6+yHANMTukMtEZGC4fs7XPwg35v8sj5CIEmE+gEkFljFiVJxEWxx/7ZDkTK+iZRYo1bFXBtfIN95+K3cJ5A==
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.16.7.tgz#1da184cb83a2287a01956c10c60e66dd503c18aa"
integrity sha512-2FoHiSAWkdq4L06uaDN3rS43i6x28desUVxq+zAFuE6kbWYQeiLPJI5IC7Sg9xKYVcrBKSQkVUfH6aeQYbl9QA==
dependencies:
"@babel/helper-module-imports" "^7.16.0"
"@babel/helper-plugin-utils" "^7.14.5"
"@babel/helper-module-imports" "^7.16.7"
"@babel/helper-plugin-utils" "^7.16.7"
babel-plugin-polyfill-corejs2 "^0.3.0"
babel-plugin-polyfill-corejs3 "^0.4.0"
babel-plugin-polyfill-regenerator "^0.3.0"
@@ -759,7 +762,7 @@
dependencies:
"@babel/helper-plugin-utils" "^7.14.5"
"@babel/plugin-transform-typescript@7.16.1", "@babel/plugin-transform-typescript@^7.16.0":
"@babel/plugin-transform-typescript@7.16.1", "@babel/plugin-transform-typescript@^7.16.1":
version "7.16.1"
resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.1.tgz#cc0670b2822b0338355bc1b3d2246a42b8166409"
integrity sha512-NO4XoryBng06jjw/qWEU2LhcLJr1tWkhpMam/H4eas/CDKMX/b2/Ylb6EI256Y7+FVPCawwSM1rrJNOpDiz+Lg==
@@ -874,14 +877,14 @@
"@babel/types" "^7.4.4"
esutils "^2.0.2"
"@babel/preset-typescript@7.16.0":
version "7.16.0"
resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.0.tgz#b0b4f105b855fb3d631ec036cdc9d1ffd1fa5eac"
integrity sha512-txegdrZYgO9DlPbv+9QOVpMnKbOtezsLHWsnsRF4AjbSIsVaujrq1qg8HK0mxQpWv0jnejt0yEoW1uWpvbrDTg==
"@babel/preset-typescript@7.16.5":
version "7.16.5"
resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.5.tgz#b86a5b0ae739ba741347d2f58c52f52e63cf1ba1"
integrity sha512-lmAWRoJ9iOSvs3DqOndQpj8XqXkzaiQs50VG/zESiI9D3eoZhGriU675xNCr0UwvsuXrhMAGvyk1w+EVWF3u8Q==
dependencies:
"@babel/helper-plugin-utils" "^7.14.5"
"@babel/helper-plugin-utils" "^7.16.5"
"@babel/helper-validator-option" "^7.14.5"
"@babel/plugin-transform-typescript" "^7.16.0"
"@babel/plugin-transform-typescript" "^7.16.1"
"@babel/runtime@^7.8.4":
version "7.12.13"
@@ -899,17 +902,18 @@
"@babel/parser" "^7.16.0"
"@babel/types" "^7.16.0"
"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.0":
version "7.16.0"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.0.tgz#965df6c6bfc0a958c1e739284d3c9fa4a6e3c45b"
integrity sha512-qQ84jIs1aRQxaGaxSysII9TuDaguZ5yVrEuC0BN2vcPlalwfLovVmCjbFDPECPXcYM/wLvNFfp8uDOliLxIoUQ==
"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.0", "@babel/traverse@^7.16.5":
version "7.16.5"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.5.tgz#d7d400a8229c714a59b87624fc67b0f1fbd4b2b3"
integrity sha512-FOCODAzqUMROikDYLYxl4nmwiLlu85rNqBML/A5hKRVXG2LV8d0iMqgPzdYTcIpjZEBB7D6UDU9vxRZiriASdQ==
dependencies:
"@babel/code-frame" "^7.16.0"
"@babel/generator" "^7.16.0"
"@babel/generator" "^7.16.5"
"@babel/helper-environment-visitor" "^7.16.5"
"@babel/helper-function-name" "^7.16.0"
"@babel/helper-hoist-variables" "^7.16.0"
"@babel/helper-split-export-declaration" "^7.16.0"
"@babel/parser" "^7.16.0"
"@babel/parser" "^7.16.5"
"@babel/types" "^7.16.0"
debug "^4.1.0"
globals "^11.1.0"
@@ -922,6 +926,14 @@
"@babel/helper-validator-identifier" "^7.15.7"
to-fast-properties "^2.0.0"
"@babel/types@^7.16.7":
version "7.16.7"
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.7.tgz#4ed19d51f840ed4bd5645be6ce40775fecf03159"
integrity sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg==
dependencies:
"@babel/helper-validator-identifier" "^7.16.7"
to-fast-properties "^2.0.0"
"@discoveryjs/json-ext@^0.5.0":
version "0.5.2"
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz#8f03a22a04de437254e8ce8cc84ba39689288752"
+2 -2
View File
@@ -1,5 +1,6 @@
import { Random } from "roughjs/bin/math";
import { nanoid } from "nanoid";
import { isTestEnv } from "./utils";
let random = new Random(Date.now());
let testIdBase = 0;
@@ -11,5 +12,4 @@ export const reseed = (seed: number) => {
testIdBase = 0;
};
export const randomId = () =>
process.env.NODE_ENV === "test" ? `id${testIdBase++}` : nanoid();
export const randomId = () => (isTestEnv() ? `id${testIdBase++}` : nanoid());
+1 -8
View File
@@ -75,7 +75,6 @@ export const getElementContainingPosition = (
elements: readonly ExcalidrawElement[],
x: number,
y: number,
excludedType?: ExcalidrawElement["type"],
) => {
let hitElement = null;
// We need to to hit testing from front (end of the array) to back (beginning of the array)
@@ -84,13 +83,7 @@ export const getElementContainingPosition = (
continue;
}
const [x1, y1, x2, y2] = getElementAbsoluteCoords(elements[index]);
if (
x1 < x &&
x < x2 &&
y1 < y &&
y < y2 &&
elements[index].type !== excludedType
) {
if (x1 < x && x < x2 && y1 < y && y < y2) {
hitElement = elements[index];
break;
}
+1 -1
View File
@@ -77,4 +77,4 @@ export const getTargetElements = (
) =>
appState.editingElement
? [appState.editingElement]
: getSelectedElements(elements, appState);
: getSelectedElements(elements, appState, true);
+4 -2
View File
@@ -443,8 +443,7 @@ export const bytesToHexString = (bytes: Uint8Array) => {
.join("");
};
export const getUpdatedTimestamp = () =>
process.env.NODE_ENV === "test" ? 1 : Date.now();
export const getUpdatedTimestamp = () => (isTestEnv() ? 1 : Date.now());
/**
* Transforms array of objects containing `id` attribute,
@@ -458,3 +457,6 @@ export const arrayToMap = <T extends { id: string } | string>(
return acc;
}, new Map());
};
export const isTestEnv = () =>
typeof process !== "undefined" && process.env?.NODE_ENV === "test";
+76 -65
View File
@@ -2136,14 +2136,14 @@
lz-string "^1.4.4"
pretty-format "^27.0.2"
"@testing-library/jest-dom@5.15.1":
version "5.15.1"
resolved "https://registry.yarnpkg.com/@testing-library/jest-dom/-/jest-dom-5.15.1.tgz#4c49ba4d244f235aec53f0a83498daeb4ee06c33"
integrity sha512-kmj8opVDRE1E4GXyLlESsQthCXK7An28dFWxhiMwD7ZUI7ZxA6sjdJRxLerD9Jd8cHX4BDc1jzXaaZKqzlUkvg==
"@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==
dependencies:
"@babel/runtime" "^7.9.2"
"@types/testing-library__jest-dom" "^5.9.1"
aria-query "^4.2.2"
aria-query "^5.0.0"
chalk "^3.0.0"
css "^3.0.0"
css.escape "^1.5.1"
@@ -2159,10 +2159,10 @@
"@babel/runtime" "^7.12.5"
"@testing-library/dom" "^8.0.0"
"@tldraw/vec@1.1.5":
version "1.1.5"
resolved "https://registry.yarnpkg.com/@tldraw/vec/-/vec-1.1.5.tgz#a0ec75742c20da43e3328f824ef7fca0f982b1fc"
integrity sha512-reEos3gJ9OiNvAYFtJzHbYWNjPTvWPmpjAY70HWHMjfhyNk6lHwwzDjwSgej4/KxVBbxB3ppNfLD9mEMq9yCOQ==
"@tldraw/vec@1.4.0":
version "1.4.0"
resolved "https://registry.yarnpkg.com/@tldraw/vec/-/vec-1.4.0.tgz#91a6d7c852c680a3288fe8bf79623252ef917281"
integrity sha512-YWkGe/IXdFB/Kts982fmtis2nJHB8KWVbkf0PlaZtQ1CL0TZKH0xdpIA/QJMk/WCj3bN4AOYuZKwEAegmWAnOA==
"@tootallnate/once@1":
version "1.1.2"
@@ -2219,10 +2219,10 @@
dependencies:
"@babel/types" "^7.3.0"
"@types/chai@4.2.22":
version "4.2.22"
resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.22.tgz#47020d7e4cf19194d43b5202f35f75bd2ad35ce7"
integrity sha512-tFfcE+DSTzWAgifkjik9AySNqIyNoYwmR+uecPwwD/XRNfvOjmC/FjCxpiUGDkDVDphPfCUecSQVFw+lN3M3kQ==
"@types/chai@4.3.0":
version "4.3.0"
resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.0.tgz#23509ebc1fa32f1b4d50d6a66c4032d5b8eaabdc"
integrity sha512-/ceqdqeRraGolFTcfoXNiqjyQhZzbINDngeoAq9GoHa8PPK1yNzTaxWjA6BFWp5Ua9JpXEMSS4s5i9tS0hOJtw==
"@types/duplexify@^3.6.0":
version "3.6.0"
@@ -2338,10 +2338,10 @@
resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz"
integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
"@types/pako@1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@types/pako/-/pako-1.0.2.tgz#17c9b136877f33d9ecc8e73cd26944f1f6dd39a1"
integrity sha512-8UJl2MjkqqS6ncpLZqRZ5LmGiFBkbYxocD4e4jmBqGvfRG1RS23gKsBQbdtV9O9GvRyjFTiRHRByjSlKCLlmZw==
"@types/pako@1.0.3":
version "1.0.3"
resolved "https://registry.yarnpkg.com/@types/pako/-/pako-1.0.3.tgz#2e61c2b02020b5f44e2e5e946dfac74f4ec33c58"
integrity sha512-EDxOsHAD5dqjbjEUM1xwa7rpKPFb8ECBE5irONTQU7/OsO3thI5YrNEWSPNMvYmvFM0l/OLQJ6Mgw7PEdXSjhg==
"@types/parse-json@^4.0.0":
version "4.0.0"
@@ -2375,10 +2375,10 @@
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@17.0.37":
version "17.0.37"
resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.37.tgz#6884d0aa402605935c397ae689deed115caad959"
integrity sha512-2FS1oTqBGcH/s0E+CjrCCR9+JMpsu9b69RTFO+40ua43ZqP5MmQ4iUde/dMjWR909KxZwmOQIFq6AV6NjEG5xg==
"@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==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
@@ -4379,11 +4379,6 @@ clone@^1.0.2:
resolved "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz"
integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4=
clone@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
integrity sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=
clsx@1.1.1:
version "1.1.1"
resolved "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz"
@@ -5163,10 +5158,10 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9:
dependencies:
ms "2.0.0"
debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2:
version "4.3.2"
resolved "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz"
integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==
debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3:
version "4.3.3"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664"
integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==
dependencies:
ms "2.1.2"
@@ -5723,7 +5718,7 @@ enhanced-resolve@^4.3.0:
memory-fs "^0.5.0"
tapable "^1.0.0"
enquirer@^2.3.5, enquirer@^2.3.6:
enquirer@^2.3.5:
version "2.3.6"
resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz"
integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==
@@ -7755,6 +7750,11 @@ immer@8.0.1:
resolved "https://registry.npmjs.org/immer/-/immer-8.0.1.tgz"
integrity sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA==
immutable@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.0.0.tgz#b86f78de6adef3608395efb269a91462797e2c23"
integrity sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==
import-cwd@^2.0.0:
version "2.1.0"
resolved "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz"
@@ -9276,24 +9276,23 @@ 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.2:
version "12.1.2"
resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-12.1.2.tgz#90c571927e1371fc133e720671dd7989eab53f74"
integrity sha512-bSMcQVqMW98HLLLR2c2tZ+vnDCnx4fd+0QJBQgN/4XkdspGRPc8DGp7UuOEBe1ApCfJ+wXXumYnJmU+wDo7j9A==
lint-staged@12.1.4:
version "12.1.4"
resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-12.1.4.tgz#a92ec8509f13018caaafade61d515c2d5873316e"
integrity sha512-RgDz9nsFsE0/5eL9Vat0AvCuk0+j5mEuzBIVfrRH5FRtt5wibYe8zTjZs2nuqLFrLAGQGYnj8+HJxolcj08i/A==
dependencies:
cli-truncate "^3.1.0"
colorette "^2.0.16"
commander "^8.3.0"
debug "^4.3.2"
enquirer "^2.3.6"
debug "^4.3.3"
execa "^5.1.1"
lilconfig "2.0.4"
listr2 "^3.13.3"
listr2 "^3.13.5"
micromatch "^4.0.4"
normalize-path "^3.0.0"
object-inspect "^1.11.0"
object-inspect "^1.11.1"
string-argv "^0.3.1"
supports-color "^9.0.2"
supports-color "^9.2.1"
yaml "^1.10.2"
listenercount@~1.0.1:
@@ -9301,16 +9300,16 @@ listenercount@~1.0.1:
resolved "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz"
integrity sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=
listr2@^3.13.3:
version "3.13.3"
resolved "https://registry.yarnpkg.com/listr2/-/listr2-3.13.3.tgz#d8f6095c9371b382c9b1c2bc33c5941d8e177f11"
integrity sha512-VqAgN+XVfyaEjSaFewGPcDs5/3hBbWVaX1VgWv2f52MF7US45JuARlArULctiB44IIcEk3JF7GtoFCLqEdeuPA==
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==
dependencies:
cli-truncate "^2.1.0"
clone "^2.1.2"
colorette "^2.0.16"
log-update "^4.0.0"
p-map "^4.0.0"
rfdc "^1.3.0"
rxjs "^7.4.0"
through "^2.3.8"
wrap-ansi "^7.0.0"
@@ -10404,10 +10403,10 @@ object-copy@^0.1.0:
define-property "^0.2.5"
kind-of "^3.0.3"
object-inspect@^1.11.0, object-inspect@^1.9.0:
version "1.11.0"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.11.0.tgz#9dceb146cedd4148a0d9e51ab88d34cf509922b1"
integrity sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==
object-inspect@^1.11.1, 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==
object-is@^1.0.1:
version "1.1.5"
@@ -11788,10 +11787,10 @@ prettier-linter-helpers@^1.0.0:
dependencies:
fast-diff "^1.1.2"
prettier@2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.0.tgz#a6370e2d4594e093270419d9cc47f7670488f893"
integrity sha512-FM/zAKgWTxj40rH03VxzIPdXmj39SwSjwG0heUcNFwI+EMZJnY93yAiKXM3dObIKAM5TA88werc8T/EwhB45eg==
prettier@2.5.1:
version "2.5.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a"
integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==
pretty-bytes@^5.3.0:
version "5.6.0"
@@ -12719,6 +12718,11 @@ rework@1.0.1:
convert-source-map "^0.3.3"
css "^2.0.0"
rfdc@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b"
integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==
rgb-regex@^1.0.1:
version "1.0.1"
resolved "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz"
@@ -12911,12 +12915,14 @@ sass-loader@^10.0.5:
schema-utils "^3.0.0"
semver "^7.3.2"
sass@1.43.5:
version "1.43.5"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.43.5.tgz#25a9d91dd098793ef7229d7b04dd3daae2fc4a65"
integrity sha512-WuNm+eAryMgQluL7Mbq9M4EruyGGMyal7Lu58FfnRMVWxgUzIvI7aSn60iNt3kn5yZBMR7G84fAGDcwqOF5JOg==
sass@1.45.2:
version "1.45.2"
resolved "https://registry.yarnpkg.com/sass/-/sass-1.45.2.tgz#130b428c1692201cfa181139835d6fc378a33323"
integrity sha512-cKfs+F9AMPAFlbbTXNsbGvg3y58nV0mXA3E94jqaySKcC8Kq3/8983zVKQ0TLMUrHw7hF9Tnd3Bz9z5Xgtrl9g==
dependencies:
chokidar ">=3.0.0 <4.0.0"
immutable "^4.0.0"
source-map-js ">=0.6.2 <2.0.0"
sax@~1.2.4:
version "1.2.4"
@@ -13348,6 +13354,11 @@ source-list-map@^2.0.0:
resolved "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz"
integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
"source-map-js@>=0.6.2 <2.0.0":
version "1.0.1"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.1.tgz#a1741c131e3c77d048252adfa24e23b908670caf"
integrity sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==
source-map-resolve@^0.5.0, source-map-resolve@^0.5.2:
version "0.5.3"
resolved "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz"
@@ -13864,10 +13875,10 @@ supports-color@^7.0.0, supports-color@^7.1.0:
dependencies:
has-flag "^4.0.0"
supports-color@^9.0.2:
version "9.1.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-9.1.0.tgz#558963681dafeff41ed68220488cbf438d29f351"
integrity sha512-lOCGOTmBSN54zKAoPWhHkjoqVQ0MqgzPE5iirtoSixhr0ZieR/6l7WZ32V53cvy9+1qghFnIk7k52p991lKd6g==
supports-color@^9.2.1:
version "9.2.1"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-9.2.1.tgz#599dc9d45acf74c6176e0d880bab1d7d718fe891"
integrity sha512-Obv7ycoCTG51N7y175StI9BlAXrmgZrFhZOb0/PyjHBher/NmsdBgbbQ1Inhq+gIhz6+7Gb+jWF2Vqi7Mf1xnQ==
supports-hyperlinks@^1.0.1:
version "1.0.1"
@@ -14381,10 +14392,10 @@ typedarray@^0.0.6:
resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
typescript@4.5.2:
version "4.5.2"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.2.tgz#8ac1fba9f52256fdb06fb89e4122fa6a346c2998"
integrity sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==
typescript@4.5.4:
version "4.5.4"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.4.tgz#a17d3a0263bf5c8723b9c52f43c5084edf13c2e8"
integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==
typeson-registry@^1.0.0-alpha.20:
version "1.0.0-alpha.39"