diff --git a/.env b/.env index ab2e34bd1..0977b9496 100644 --- a/.env +++ b/.env @@ -1,5 +1,5 @@ REACT_APP_BACKEND_V1_GET_URL=https://json.excalidraw.com/api/v1/ REACT_APP_BACKEND_V2_GET_URL=https://json.excalidraw.com/api/v2/ REACT_APP_BACKEND_V2_POST_URL=https://json.excalidraw.com/api/v2/post/ -REACT_APP_SOCKET_SERVER_URL=https://excalidraw-socket.herokuapp.com +REACT_APP_SOCKET_SERVER_URL=https://portal.excalidraw.com REACT_APP_FIREBASE_CONFIG='{"apiKey":"AIzaSyAd15pYlMci_xIp9ko6wkEsDzAAA0Dn0RU","authDomain":"excalidraw-room-persistence.firebaseapp.com","databaseURL":"https://excalidraw-room-persistence.firebaseio.com","projectId":"excalidraw-room-persistence","storageBucket":"excalidraw-room-persistence.appspot.com","messagingSenderId":"654800341332","appId":"1:654800341332:web:4a692de832b55bd57ce0c1"}' diff --git a/.env.production b/.env.production index 0a6355edd..01fb7767d 100644 --- a/.env.production +++ b/.env.production @@ -1 +1 @@ -REACT_APP_INCLUDE_GTAG=true +REACT_APP_GOOGLE_ANALYTICS_ID=UA-387204-13 diff --git a/.github/assets/logo.png b/.github/assets/logo.png index 658bd4f79..d9b8953eb 100644 Binary files a/.github/assets/logo.png and b/.github/assets/logo.png differ diff --git a/.github/workflows/cancel.yml b/.github/workflows/cancel.yml new file mode 100644 index 000000000..19496c5bf --- /dev/null +++ b/.github/workflows/cancel.yml @@ -0,0 +1,12 @@ +name: Cancel +on: [push] +jobs: + cancel: + name: "Cancel Previous Runs" + runs-on: ubuntu-latest + timeout-minutes: 3 + steps: + - uses: styfle/cancel-workflow-action@0.6.0 + with: + workflow_id: 400555, 400556, 905313, 1451724, 1710116, 3185001, 3438604 + access_token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/semantic-pr-title.yml b/.github/workflows/semantic-pr-title.yml index 505c22dc1..be84d2294 100644 --- a/.github/workflows/semantic-pr-title.yml +++ b/.github/workflows/semantic-pr-title.yml @@ -11,6 +11,6 @@ jobs: main: runs-on: ubuntu-latest steps: - - uses: amannn/action-semantic-pull-request@v2.1.0 + - uses: amannn/action-semantic-pull-request@v3.0.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.prettierrc b/.prettierrc index bf357fbbc..32ad81f35 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,3 +1,4 @@ { + "proseWrap": "never", "trailingComma": "all" } diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f85df1ad8..e3998dcc2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,8 +8,7 @@ 1. Run `npm install` to install dependencies 1. Create a branch for your PR with `git checkout -b your-branch-name` -> To keep `master` branch pointing to remote repository and make -> pull requests from branches on your fork. To do this, run: +> To keep `master` branch pointing to remote repository and make pull requests from branches on your fork. To do this, run: > > ```sh > git remote add upstream https://github.com/excalidraw/excalidraw.git @@ -25,3 +24,41 @@ 1. Tap on `Fork Sandbox` 1. Write your code 1. Commit and PR automatically + +## Pull Request Guidelines + +Don't worry if you get any of the below wrong, or if you don't know how. We'll gladly help out. + +### Title + +Make sure the title starts with a semantic prefix: + +- **feat**: A new feature +- **fix**: A bug fix +- **improvement**: An improvement to a current feature +- **docs**: Documentation only changes +- **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc) +- **refactor**: A code change that neither fixes a bug nor adds a feature +- **perf**: A code change that improves performance +- **test**: Adding missing tests or correcting existing tests +- **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm) +- **ci**: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs) +- **chore**: Other changes that don't modify src or test files +- **revert**: Reverts a previous commit + +### Changelog + +Add a brief description of your pull request to the changelog located here: [`src/packages/excalidraw/CHANGELOG.md`](src/packages/excalidraw/CHANGELOG.md) + +Notes: + +- Make sure to prepend to the section corresponding with the semantic prefix you selected in the title +- Link to your pull request - this will require updating the CHANGELOG _after_ creating the pull request + +### Testing + +Once you submit your pull request it will automatically be tested. Be sure to check the results of the test and fix any issues that arise. + +It's also a good idea to consider if your change should include additional tests. This is highly recommended for new features or bug-fixes. For example, it's good practice to create a test for each bug you fix which ensures that we don't regress the code in the future. + +Finally - always manually test your changes using the convenient staging environment deployed for each pull request. As much as local development attempts to replicate production, there can still be subtle differences in behavior. For larger features consider testing your change in multiple browsers as well. diff --git a/Dockerfile b/Dockerfile index eb9da1721..27f3a7084 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,6 @@ WORKDIR /opt/node_app COPY package.json package-lock.json ./ RUN npm i --no-optional -ARG REACT_APP_INCLUDE_GTAG=false ARG NODE_ENV=production COPY . . diff --git a/README.md b/README.md index 7688c4eac..148812e77 100644 --- a/README.md +++ b/README.md @@ -99,11 +99,9 @@ And the main source of inspiration for starting the project is the awesome [Zwib ## Testimonials - - + - - + @@ -111,8 +109,7 @@ And the main source of inspiration for starting the project is the awesome [Zwib ### Code Contributors -This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. - +This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. ### Financial Contributors @@ -126,13 +123,4 @@ Become a financial contributor and help us sustain our community. [[Contribute]( Support this project with your organization. Your logo will show up here with a link to your website. [[Contribute](https://opencollective.com/excalidraw/contribute)] - - - - - - - - - - + diff --git a/analytics.md b/analytics.md deleted file mode 100644 index 30e2ccacb..000000000 --- a/analytics.md +++ /dev/null @@ -1,64 +0,0 @@ -| Excalidraw | Category | Name | Label | Value | -| ----------------------- | -------- | ---------------------------------- | ------------------------------- | --------- | -| Shape / Selection | shape | selection, rectangle, diamond, etc | `toolbar` or `shortcut` | -| Text on double click | shape | text | `double-click` | -| Lock selection | shape | lock | `on` or `off` | -| Clear canvas | action | clear canvas | -| Zoom in | action | zoom | in | `zoom` | -| Zoom out | action | zoom | out | `zoom` | -| Zoom fit | action | zoom | fit | `zoom` | -| Zoom reset | action | zoom | reset | `zoom` | -| Scroll back to content | action | scroll to content | -| Load file | io | load | `MIME type` | -| Import from URL | io | import | -| Save | io | save | -| Save as | io | save as | -| Export to backend | io | export | backend | -| Export as SVG | io | export | `svg` or `clipboard-svg` | -| Export to PNG | io | export | `png` or `clipboard-png` | -| Canvas color | change | canvas color | `color` | -| Background color | change | background color | `color` | -| Stroke color | change | stroke color | `color` | -| Stroke width | change | stroke | width | `width` | -| Stroke style | change | style | `solid` or `dashed` or `dotted` | -| Stroke sloppiness | change | stroke | sloppiness | `value` | -| Fill | change | fill | `value` | -| Edge | change | edge | `value` | -| Opacity | change | opacity | value | `opacity` | -| Project name | change | title | -| Theme | change | theme | `light` or `dark` | -| Change language | change | language | `language` | -| Send to back | layer | move | `back` | -| Send backward | layer | move | `down` | -| Bring to front | layer | move | `front` | -| Bring forward | layer | move | `up` | -| Align left | align | align | `left` | -| Align right | align | align | `right` | -| Align top | align | align | `top` | -| Align bottom | align | align | `bottom` | -| Center horizontally | align | horizontally | `center` | -| Center vertically | align | vertically | `center` | -| Distribute horizontally | align | distribute | `horizontally` | -| Distribute vertically | align | distribute | `vertically` | -| Start session | share | session start | -| Join session | share | session join | -| Start end | share | session end | -| Copy room link | share | copy link | -| Go to collaborator | share | go to collaborator | -| Change name | share | name | -| Add to library | library | add | -| Remove from library | library | remove | -| Load library | library | load | -| Save library | library | save | -| Import library | library | import | -| Shortcuts dialog | dialog | shortcuts | -| Collaboration dialog | dialog | collaboration | -| Export dialog | dialog | export | -| Library dialog | dialog | library | -| E2EE shield | exit | e2ee shield | -| GitHub corner | exit | github | -| Excalidraw blog | exit | blog | -| Excalidraw guides | exit | guides | -| File issues | exit | issues | -| First load | load | first load | -| Load from stroage | load | storage | size | `bytes` | diff --git a/package-lock.json b/package-lock.json index 8b6254386..bee71f5ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1368,9 +1368,9 @@ } }, "@firebase/database": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.8.1.tgz", - "integrity": "sha512-/1HhR4ejpqUaM9Cn3KSeNdQvdlehWIhdfTVWFxS73ZlLYf7ayk9jITwH10H3ZOIm5yNzxF67p/U7Z/0IPhgWaQ==", + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-0.8.2.tgz", + "integrity": "sha512-E86yrom0Ii+61UScG44y1q3H3NuozzGGTGbYmiyTe1qK8Qvzuiu7yyfdDnqFW2fkeKvTRLoDeCpgZy27FgEndQ==", "requires": { "@firebase/auth-interop-types": "0.1.5", "@firebase/component": "0.1.21", @@ -1405,9 +1405,9 @@ } }, "@firebase/firestore": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-2.1.1.tgz", - "integrity": "sha512-mcKp8psdKSxujaGjyfmt/thlTG5Gk+gFdJbkx4DnGO1PsJG4H5mE0wG//7tOH7DGeRCAmiagjKhA8nQlf/UNCg==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-2.1.2.tgz", + "integrity": "sha512-8yUdBLLr6UhE+IjPR+fxLBD0bDnEqF9GalohfURZeLQPaL3b+LtqqGCLvvXC4MKT0lJAHOV8J9LA6rHj8vI0/Q==", "requires": { "@firebase/component": "0.1.21", "@firebase/firestore-types": "2.1.0", @@ -1672,9 +1672,9 @@ } }, "@grpc/grpc-js": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.2.2.tgz", - "integrity": "sha512-iK/T984Ni6VnmlQK/LJdUk+VsXSaYIWkgzJ0LyOcxN2SowAmoRjG28kS7B1ui/q/MAv42iM3051WBt5QorFxmg==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.2.3.tgz", + "integrity": "sha512-hMjS4/TiGFtvMxjmM3mgXCw6VIGeI0EWTNzdcV6R+qqCh33dLDcK1wVceAABXKZ+Fia1nETU49RBesOiukQjGA==", "requires": { "@types/node": "^12.12.47", "google-auth-library": "^6.1.1", @@ -1682,9 +1682,9 @@ }, "dependencies": { "@types/node": { - "version": "12.19.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.9.tgz", - "integrity": "sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q==" + "version": "12.19.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.12.tgz", + "integrity": "sha512-UwfL2uIU9arX/+/PRcIkT08/iBadGN2z6ExOROA2Dh5mAuWTBj6iJbQX4nekiV5H8cTrEG569LeX+HRco9Cbxw==" } } }, @@ -2663,70 +2663,70 @@ } }, "@sentry/browser": { - "version": "5.29.0", - "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.29.0.tgz", - "integrity": "sha512-kRlt1mE2wrYjspnIupNnPxqsUrRuy02SuXhbpP7J6uu8QasoEmJ78hk0hHz4jOZRmuWwfs2zIXD4tLGgWOKq8A==", + "version": "5.29.2", + "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.29.2.tgz", + "integrity": "sha512-uxZ7y7rp85tJll+RZtXRhXPbnFnOaxZqJEv05vJlXBtBNLQtlczV5iCtU9mZRLVHDtmZ5VVKUV8IKXntEqqDpQ==", "requires": { - "@sentry/core": "5.29.0", - "@sentry/types": "5.29.0", - "@sentry/utils": "5.29.0", + "@sentry/core": "5.29.2", + "@sentry/types": "5.29.2", + "@sentry/utils": "5.29.2", "tslib": "^1.9.3" } }, "@sentry/core": { - "version": "5.29.0", - "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.29.0.tgz", - "integrity": "sha512-a1sZBJ2u3NG0YDlGvOTwUCWiNjhfmDtAQiKK1o6RIIbcrWy9TlSps7CYDkBP239Y3A4pnvohjEEKEP3v3L3LZQ==", + "version": "5.29.2", + "resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.29.2.tgz", + "integrity": "sha512-7WYkoxB5IdlNEbwOwqSU64erUKH4laavPsM0/yQ+jojM76ErxlgEF0u//p5WaLPRzh3iDSt6BH+9TL45oNZeZw==", "requires": { - "@sentry/hub": "5.29.0", - "@sentry/minimal": "5.29.0", - "@sentry/types": "5.29.0", - "@sentry/utils": "5.29.0", + "@sentry/hub": "5.29.2", + "@sentry/minimal": "5.29.2", + "@sentry/types": "5.29.2", + "@sentry/utils": "5.29.2", "tslib": "^1.9.3" } }, "@sentry/hub": { - "version": "5.29.0", - "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.29.0.tgz", - "integrity": "sha512-kcDPQsRG4cFdmqDh+TzjeO7lWYxU8s1dZYAbbl1J4uGKmhNB0J7I4ak4SGwTsXLY6fhbierxr6PRaoNojCxjPw==", + "version": "5.29.2", + "resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.29.2.tgz", + "integrity": "sha512-LaAIo2hwUk9ykeh9RF0cwLy6IRw+DjEee8l1HfEaDFUM6TPGlNNGObMJNXb9/95jzWp7jWwOpQjoIE3jepdQJQ==", "requires": { - "@sentry/types": "5.29.0", - "@sentry/utils": "5.29.0", + "@sentry/types": "5.29.2", + "@sentry/utils": "5.29.2", "tslib": "^1.9.3" } }, "@sentry/integrations": { - "version": "5.29.0", - "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-5.29.0.tgz", - "integrity": "sha512-SGqpi1Qd1a7gGL6aYrJnKqU/DNJcHvnhD3qOgow23ivEpaJv1BtQSKxv17IbO/CIFn3A0o1a18wY6xef9isKEQ==", + "version": "5.29.2", + "resolved": "https://registry.npmjs.org/@sentry/integrations/-/integrations-5.29.2.tgz", + "integrity": "sha512-bH50B0xubbHrJFq8xZRxOc5BgXe1PXKfC0OqQkhhSd+Bu2WDLCHcn0CEzV+8thZTYkipAoFAFJNdEWcsM2Wcew==", "requires": { - "@sentry/types": "5.29.0", - "@sentry/utils": "5.29.0", + "@sentry/types": "5.29.2", + "@sentry/utils": "5.29.2", "localforage": "1.8.1", "tslib": "^1.9.3" } }, "@sentry/minimal": { - "version": "5.29.0", - "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.29.0.tgz", - "integrity": "sha512-nhXofdjtO41/caiF1wk1oT3p/QuhOZDYdF/b29DoD2MiAMK9IjhhOXI/gqaRpDKkXlDvd95fDTcx4t/MqqcKXA==", + "version": "5.29.2", + "resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.29.2.tgz", + "integrity": "sha512-0aINSm8fGA1KyM7PavOBe1GDZDxrvnKt+oFnU0L+bTcw8Lr+of+v6Kwd97rkLRNOLw621xP076dL/7LSIzMuhw==", "requires": { - "@sentry/hub": "5.29.0", - "@sentry/types": "5.29.0", + "@sentry/hub": "5.29.2", + "@sentry/types": "5.29.2", "tslib": "^1.9.3" } }, "@sentry/types": { - "version": "5.29.0", - "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.29.0.tgz", - "integrity": "sha512-iDkxT/9sT3UF+Xb+JyLjZ5caMXsgLfRyV9VXQEiR2J6mgpMielj184d9jeF3bm/VMuAf/VFFqrHlcVsVgmrrMw==" + "version": "5.29.2", + "resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.29.2.tgz", + "integrity": "sha512-dM9wgt8wy4WRty75QkqQgrw9FV9F+BOMfmc0iaX13Qos7i6Qs2Q0dxtJ83SoR4YGtW8URaHzlDtWlGs5egBiMA==" }, "@sentry/utils": { - "version": "5.29.0", - "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.29.0.tgz", - "integrity": "sha512-b2B1gshw2u3EHlAi84PuI5sfmLKXW1z9enMMhNuuNT/CoRp+g5kMAcUv/qYTws7UNnYSvTuVGuZG30v1e0hP9A==", + "version": "5.29.2", + "resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.29.2.tgz", + "integrity": "sha512-nEwQIDjtFkeE4k6yIk4Ka5XjGRklNLThWLs2xfXlL7uwrYOH2B9UBBOOIRUraBm/g/Xrra3xsam/kRxuiwtXZQ==", "requires": { - "@sentry/types": "5.29.0", + "@sentry/types": "5.29.2", "tslib": "^1.9.3" } }, @@ -2887,9 +2887,9 @@ } }, "@testing-library/dom": { - "version": "7.28.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.28.1.tgz", - "integrity": "sha512-acv3l6kDwZkQif/YqJjstT3ks5aaI33uxGNVIQmdKzbZ2eMKgg3EV2tB84GDdc72k3Kjhl6mO8yUt6StVIdRDg==", + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.29.2.tgz", + "integrity": "sha512-CBMELfyY1jKdtLcSRmEnZWRzRkCRVSNPTzhzrn8wY8OnzUo7Pe/W+HgLzt4TDnWIPYeusHBodf9wUjJF48kPmA==", "requires": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -2902,9 +2902,9 @@ }, "dependencies": { "@babel/code-frame": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", - "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", "requires": { "@babel/highlight": "^7.10.4" } @@ -2939,18 +2939,6 @@ "regenerator-runtime": "^0.13.4" } }, - "@jest/types": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-26.6.2.tgz", - "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^15.0.0", - "chalk": "^4.0.0" - } - }, "chalk": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", @@ -2996,32 +2984,6 @@ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" }, - "pretty-format": { - "version": "26.6.2", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-26.6.2.tgz", - "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", - "requires": { - "@jest/types": "^26.6.2", - "ansi-regex": "^5.0.0", - "ansi-styles": "^4.0.0", - "react-is": "^17.0.1" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "requires": { - "color-convert": "^2.0.1" - } - } - } - }, - "react-is": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz", - "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==" - }, "regenerator-runtime": { "version": "0.13.7", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", @@ -3030,9 +2992,9 @@ } }, "@testing-library/jest-dom": { - "version": "5.11.6", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.11.6.tgz", - "integrity": "sha512-cVZyUNRWwUKI0++yepYpYX7uhrP398I+tGz4zOlLVlUYnZS+Svuxv4fwLeCIy7TnBYKXUaOlQr3vopxL8ZfEnA==", + "version": "5.11.8", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.11.8.tgz", + "integrity": "sha512-ScyKrWQM5xNcr79PkSewnA79CLaoxVskE+f7knTOhDD9ftZSA1Jw8mj+pneqhEu3x37ncNfW84NUr7lqK+mXjA==", "requires": { "@babel/runtime": "^7.9.2", "@types/testing-library__jest-dom": "^5.9.1", @@ -3144,9 +3106,9 @@ } }, "@testing-library/react": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-11.2.2.tgz", - "integrity": "sha512-jaxm0hwUjv+hzC+UFEywic7buDC9JQ1q3cDsrWVSDAPmLotfA6E6kUHlYm/zOeGCac6g48DR36tFHxl7Zb+N5A==", + "version": "11.2.3", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-11.2.3.tgz", + "integrity": "sha512-BirBUGPkTW28ULuCwIbYo0y2+0aavHczBT6N9r3LrsswEW3pg25l1wgoE7I8QBIy1upXWkwKpYdWY7NYYP0Bxw==", "requires": { "@babel/runtime": "^7.12.5", "@testing-library/dom": "^7.28.1" @@ -3167,6 +3129,12 @@ } } }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, "@types/anymatch": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz", @@ -3287,9 +3255,9 @@ } }, "@types/jest": { - "version": "26.0.19", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.19.tgz", - "integrity": "sha512-jqHoirTG61fee6v6rwbnEuKhpSKih0tuhqeFbCmMmErhtu3BYlOZaXWjffgOstMM4S/3iQD31lI5bGLTrs97yQ==", + "version": "26.0.20", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.20.tgz", + "integrity": "sha512-9zi2Y+5USJRxd0FsahERhBwlcvFh6D2GLQnY2FH2BzK8J9s9omvNHIbvABwIluXa0fD8XVKMLTO0aOEuUfACAA==", "requires": { "jest-diff": "^26.0.0", "pretty-format": "^26.0.0" @@ -4292,6 +4260,23 @@ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" }, + "ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "requires": { + "tslib": "^2.0.1" + }, + "dependencies": { + "tslib": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", + "dev": true + } + } + }, "ast-types-flow": { "version": "0.0.7", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", @@ -6870,6 +6855,12 @@ "assert-plus": "^1.0.0" } }, + "data-uri-to-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", + "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==", + "dev": true + }, "data-urls": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", @@ -7021,6 +7012,17 @@ } } }, + "degenerator": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-2.2.0.tgz", + "integrity": "sha512-aiQcQowF01RxFI4ZLFMpzyotbQonhNpBao6dkI8JPk5a+hmSjR5ErHp2CQySmQe8os3VBqLCIh87nDBgZXvsmg==", + "dev": true, + "requires": { + "ast-types": "^0.13.2", + "escodegen": "^1.8.1", + "esprima": "^4.0.0" + } + }, "del": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/del/-/del-4.1.1.tgz", @@ -8163,9 +8165,9 @@ } }, "eslint-plugin-prettier": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.0.tgz", - "integrity": "sha512-tMTwO8iUWlSRZIwS9k7/E4vrTsfvsrcM5p1eftyuqWH25nKsz/o6/54I7jwQ/3zobISyC7wMy9ZsFwgTxOcOpQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.3.1.tgz", + "integrity": "sha512-Rq3jkcFY8RYeQLgk2cCwuc0P7SEFwDravPhsJZOQ5N4YI4DSg50NyqJ/9gdZHzQlHf8MvafSesbNJCcP/FF6pQ==", "dev": true, "requires": { "prettier-linter-helpers": "^1.0.0" @@ -9009,25 +9011,25 @@ } }, "find-versions": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz", - "integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-4.0.0.tgz", + "integrity": "sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ==", "dev": true, "requires": { - "semver-regex": "^2.0.0" + "semver-regex": "^3.1.2" } }, "firebase": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/firebase/-/firebase-8.2.1.tgz", - "integrity": "sha512-u2dvRIbyHZ2g0dziHKwXvMBubTSf+fgJcijXyy7fXcFFPd3wbDaGlHz7Sc6saOnlJtzZAYmvZUXaIxnStKOOXg==", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-8.2.2.tgz", + "integrity": "sha512-a07aW2TTAA9S7p4mx5pu8hvtVokJEjAQlAocHKOWwmRJRIduE9Vvr/3i50FtujT5gGNr0Qm+EyWyB+/7TJiwnw==", "requires": { "@firebase/analytics": "0.6.2", "@firebase/app": "0.6.13", "@firebase/app-types": "0.6.1", "@firebase/auth": "0.16.1", - "@firebase/database": "0.8.1", - "@firebase/firestore": "2.1.1", + "@firebase/database": "0.8.2", + "@firebase/firestore": "2.1.2", "@firebase/functions": "0.6.1", "@firebase/installations": "0.4.19", "@firebase/messaging": "0.7.3", @@ -9039,9 +9041,9 @@ } }, "firebase-tools": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/firebase-tools/-/firebase-tools-9.0.1.tgz", - "integrity": "sha512-OktyHgjIBJR/JPNU4Xv4NsRLWu5gDnTmYd88VUsMwzUMCkbao2NNpeBi6+0rn6U1zNhwP2WW9PngccJWg/wvSA==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/firebase-tools/-/firebase-tools-9.1.2.tgz", + "integrity": "sha512-YUiqMuQ+nbdCNpahSO0eyKxxVfT0nDdijkUEUplTGArkDwqdOKPIxVqHj1edq7GEPXTRWlk7zibnbOnCCHaedw==", "dev": true, "requires": { "@google-cloud/pubsub": "^2.7.0", @@ -9082,6 +9084,7 @@ "plist": "^3.0.1", "portfinder": "^1.0.23", "progress": "^2.0.3", + "proxy-agent": "^4.0.0", "request": "^2.87.0", "rimraf": "^3.0.0", "semver": "^5.7.1", @@ -9755,6 +9758,42 @@ "rimraf": "2" } }, + "ftp": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", + "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", + "dev": true, + "requires": { + "readable-stream": "1.1.x", + "xregexp": "2.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + } + } + }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -9892,6 +9931,54 @@ "pump": "^3.0.0" } }, + "get-uri": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-3.0.2.tgz", + "integrity": "sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "data-uri-to-buffer": "3", + "debug": "4", + "file-uri-to-path": "2", + "fs-extra": "^8.1.0", + "ftp": "^0.3.10" + }, + "dependencies": { + "file-uri-to-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz", + "integrity": "sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg==", + "dev": true + }, + "fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + } + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + } + } + }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -10040,89 +10127,28 @@ } }, "google-gax": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.9.2.tgz", - "integrity": "sha512-Pve4osEzNKpBZqFXMfGKBbKCtgnHpUe5IQMh5Ou+Xtg8nLcba94L3gF0xgM5phMdGRRqJn0SMjcuEVmOYu7EBg==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/google-gax/-/google-gax-2.10.0.tgz", + "integrity": "sha512-K+1JK5ofNl5k30LsI8UQb/DeLMEbhL/SWirCx0L9pnMcApSfAjRAO7yajXT5X1vicxDBnNSwKs+cu4elxpYraw==", "dev": true, "requires": { - "@grpc/grpc-js": "~1.1.1", + "@grpc/grpc-js": "~1.2.0", "@grpc/proto-loader": "^0.5.1", "@types/long": "^4.0.0", "abort-controller": "^3.0.0", "duplexify": "^4.0.0", + "fast-text-encoding": "^1.0.3", "google-auth-library": "^6.1.3", "is-stream-ended": "^0.1.4", "node-fetch": "^2.6.1", - "protobufjs": "^6.9.0", + "protobufjs": "^6.10.2", "retry-request": "^4.0.0" }, "dependencies": { - "@grpc/grpc-js": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.1.8.tgz", - "integrity": "sha512-64hg5rmEm6F/NvlWERhHmmgxbWU8nD2TMWE+9TvG7/WcOrFT3fzg/Uu631pXRFwmJ4aWO/kp9vVSlr8FUjBDLA==", - "dev": true, - "requires": { - "@grpc/proto-loader": "^0.6.0-pre14", - "@types/node": "^12.12.47", - "google-auth-library": "^6.0.0", - "semver": "^6.2.0" - }, - "dependencies": { - "@grpc/proto-loader": { - "version": "0.6.0-pre9", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.6.0-pre9.tgz", - "integrity": "sha512-oM+LjpEjNzW5pNJjt4/hq1HYayNeQT+eGrOPABJnYHv7TyNPDNzkQ76rDYZF86X5swJOa4EujEMzQ9iiTdPgww==", - "dev": true, - "requires": { - "@types/long": "^4.0.1", - "lodash.camelcase": "^4.3.0", - "long": "^4.0.0", - "protobufjs": "^6.9.0", - "yargs": "^15.3.1" - } - } - } - }, "@types/node": { - "version": "12.19.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.19.9.tgz", - "integrity": "sha512-yj0DOaQeUrk3nJ0bd3Y5PeDRJ6W0r+kilosLA+dzF3dola/o9hxhMSg2sFvVcA2UHS5JSOsZp4S0c1OEXc4m1Q==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "version": "13.13.39", + "resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.39.tgz", + "integrity": "sha512-wct+WgRTTkBm2R3vbrFOqyZM5w0g+D8KnhstG9463CJBVC3UVZHMToge7iMBR1vDl/I+NWFHUeK9X+JcF0rWKw==", "dev": true }, "duplexify": { @@ -10137,87 +10163,25 @@ "stream-shift": "^1.0.0" } }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "protobufjs": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.10.2.tgz", + "integrity": "sha512-27yj+04uF6ya9l+qfpH187aqEzfCF4+Uit0I9ZBQVqK09hk/SQzKa2MUqUpXaVa7LOFRg1TSSr3lVxGOk6c0SQ==", "dev": true, "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.0" - } - }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "requires": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - } - }, - "yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": "^13.7.0", + "long": "^4.0.0" } } } @@ -10671,6 +10635,17 @@ "requires-port": "^1.0.0" } }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, "http-proxy-middleware": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz", @@ -10809,18 +10784,18 @@ "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==" }, "husky": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.6.tgz", - "integrity": "sha512-o6UjVI8xtlWRL5395iWq9LKDyp/9TE7XMOTvIpEVzW638UcGxTmV5cfel6fsk/jbZSTlvfGVJf2svFtybcIZag==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.7.tgz", + "integrity": "sha512-0fQlcCDq/xypoyYSJvEuzbDPHFf8ZF9IXKJxlrnvxABTSzK1VPT2RKYQKrcgJ+YD39swgoB6sbzywUqFxUiqjw==", "dev": true, "requires": { "chalk": "^4.0.0", "ci-info": "^2.0.0", "compare-versions": "^3.6.0", "cosmiconfig": "^7.0.0", - "find-versions": "^3.2.0", + "find-versions": "^4.0.0", "opencollective-postinstall": "^2.0.2", - "pkg-dir": "^4.2.0", + "pkg-dir": "^5.0.0", "please-upgrade-node": "^3.2.0", "slash": "^3.0.0", "which-pm-runs": "^1.0.0" @@ -10861,12 +10836,12 @@ "dev": true }, "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "requires": { - "locate-path": "^5.0.0", + "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, @@ -10877,21 +10852,30 @@ "dev": true }, "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "requires": { - "p-locate": "^4.1.0" + "p-locate": "^5.0.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" } }, "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "requires": { - "p-limit": "^2.2.0" + "p-limit": "^3.0.2" } }, "path-exists": { @@ -10901,12 +10885,12 @@ "dev": true }, "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", + "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", "dev": true, "requires": { - "find-up": "^4.0.0" + "find-up": "^5.0.0" } }, "supports-color": { @@ -13689,9 +13673,9 @@ }, "dependencies": { "tslib": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz", - "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", + "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==", "dev": true } } @@ -14789,19 +14773,33 @@ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" }, "memoizee": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz", - "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==", + "version": "0.4.15", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.15.tgz", + "integrity": "sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==", "dev": true, "requires": { - "d": "1", - "es5-ext": "^0.10.45", - "es6-weak-map": "^2.0.2", + "d": "^1.0.1", + "es5-ext": "^0.10.53", + "es6-weak-map": "^2.0.3", "event-emitter": "^0.3.5", - "is-promise": "^2.1", - "lru-queue": "0.1", - "next-tick": "1", - "timers-ext": "^0.1.5" + "is-promise": "^2.2.2", + "lru-queue": "^0.1.0", + "next-tick": "^1.1.0", + "timers-ext": "^0.1.7" + }, + "dependencies": { + "is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==", + "dev": true + }, + "next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==", + "dev": true + } } }, "memory-fs": { @@ -15330,6 +15328,12 @@ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, + "netmask": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz", + "integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=", + "dev": true + }, "next-tick": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", @@ -15642,3100 +15646,6 @@ "sort-keys": "^1.0.0" } }, - "npm": { - "version": "6.14.9", - "resolved": "https://registry.npmjs.org/npm/-/npm-6.14.9.tgz", - "integrity": "sha512-yHi1+i9LyAZF1gAmgyYtVk+HdABlLy94PMIDoK1TRKWvmFQAt5z3bodqVwKvzY0s6dLqQPVsRLiwhJfNtiHeCg==", - "requires": { - "JSONStream": "^1.3.5", - "abbrev": "~1.1.1", - "ansicolors": "~0.3.2", - "ansistyles": "~0.1.3", - "aproba": "^2.0.0", - "archy": "~1.0.0", - "bin-links": "^1.1.8", - "bluebird": "^3.5.5", - "byte-size": "^5.0.1", - "cacache": "^12.0.3", - "call-limit": "^1.1.1", - "chownr": "^1.1.4", - "ci-info": "^2.0.0", - "cli-columns": "^3.1.2", - "cli-table3": "^0.5.1", - "cmd-shim": "^3.0.3", - "columnify": "~1.5.4", - "config-chain": "^1.1.12", - "debuglog": "*", - "detect-indent": "~5.0.0", - "detect-newline": "^2.1.0", - "dezalgo": "~1.0.3", - "editor": "~1.0.0", - "figgy-pudding": "^3.5.1", - "find-npm-prefix": "^1.0.2", - "fs-vacuum": "~1.2.10", - "fs-write-stream-atomic": "~1.0.10", - "gentle-fs": "^2.3.1", - "glob": "^7.1.6", - "graceful-fs": "^4.2.4", - "has-unicode": "~2.0.1", - "hosted-git-info": "^2.8.8", - "iferr": "^1.0.2", - "imurmurhash": "*", - "infer-owner": "^1.0.4", - "inflight": "~1.0.6", - "inherits": "^2.0.4", - "ini": "^1.3.5", - "init-package-json": "^1.10.3", - "is-cidr": "^3.0.0", - "json-parse-better-errors": "^1.0.2", - "lazy-property": "~1.0.0", - "libcipm": "^4.0.8", - "libnpm": "^3.0.1", - "libnpmaccess": "^3.0.2", - "libnpmhook": "^5.0.3", - "libnpmorg": "^1.0.1", - "libnpmsearch": "^2.0.2", - "libnpmteam": "^1.0.2", - "libnpx": "^10.2.4", - "lock-verify": "^2.1.0", - "lockfile": "^1.0.4", - "lodash._baseindexof": "*", - "lodash._baseuniq": "~4.6.0", - "lodash._bindcallback": "*", - "lodash._cacheindexof": "*", - "lodash._createcache": "*", - "lodash._getnative": "*", - "lodash.clonedeep": "~4.5.0", - "lodash.restparam": "*", - "lodash.union": "~4.6.0", - "lodash.uniq": "~4.5.0", - "lodash.without": "~4.4.0", - "lru-cache": "^5.1.1", - "meant": "^1.0.2", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.5", - "move-concurrently": "^1.0.1", - "node-gyp": "^5.1.0", - "nopt": "^4.0.3", - "normalize-package-data": "^2.5.0", - "npm-audit-report": "^1.3.3", - "npm-cache-filename": "~1.0.2", - "npm-install-checks": "^3.0.2", - "npm-lifecycle": "^3.1.5", - "npm-package-arg": "^6.1.1", - "npm-packlist": "^1.4.8", - "npm-pick-manifest": "^3.0.2", - "npm-profile": "^4.0.4", - "npm-registry-fetch": "^4.0.7", - "npm-user-validate": "^1.0.1", - "npmlog": "~4.1.2", - "once": "~1.4.0", - "opener": "^1.5.1", - "osenv": "^0.1.5", - "pacote": "^9.5.12", - "path-is-inside": "~1.0.2", - "promise-inflight": "~1.0.1", - "qrcode-terminal": "^0.12.0", - "query-string": "^6.8.2", - "qw": "~1.0.1", - "read": "~1.0.7", - "read-cmd-shim": "^1.0.5", - "read-installed": "~4.0.3", - "read-package-json": "^2.1.1", - "read-package-tree": "^5.3.1", - "readable-stream": "^3.6.0", - "readdir-scoped-modules": "^1.1.0", - "request": "^2.88.0", - "retry": "^0.12.0", - "rimraf": "^2.7.1", - "safe-buffer": "^5.1.2", - "semver": "^5.7.1", - "sha": "^3.0.0", - "slide": "~1.1.6", - "sorted-object": "~2.0.1", - "sorted-union-stream": "~2.1.3", - "ssri": "^6.0.1", - "stringify-package": "^1.0.1", - "tar": "^4.4.13", - "text-table": "~0.2.0", - "tiny-relative-date": "^1.3.0", - "uid-number": "0.0.6", - "umask": "~1.1.0", - "unique-filename": "^1.1.1", - "unpipe": "~1.0.0", - "update-notifier": "^2.5.0", - "uuid": "^3.3.3", - "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "~3.0.0", - "which": "^1.3.1", - "worker-farm": "^1.7.0", - "write-file-atomic": "^2.4.3" - }, - "dependencies": { - "JSONStream": { - "version": "1.3.5", - "bundled": true, - "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" - } - }, - "abbrev": { - "version": "1.1.1", - "bundled": true - }, - "agent-base": { - "version": "4.3.0", - "bundled": true, - "requires": { - "es6-promisify": "^5.0.0" - } - }, - "agentkeepalive": { - "version": "3.5.2", - "bundled": true, - "requires": { - "humanize-ms": "^1.2.1" - } - }, - "ansi-align": { - "version": "2.0.0", - "bundled": true, - "requires": { - "string-width": "^2.0.0" - } - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true - }, - "ansi-styles": { - "version": "3.2.1", - "bundled": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "ansicolors": { - "version": "0.3.2", - "bundled": true - }, - "ansistyles": { - "version": "0.1.3", - "bundled": true - }, - "aproba": { - "version": "2.0.0", - "bundled": true - }, - "archy": { - "version": "1.0.0", - "bundled": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "asap": { - "version": "2.0.6", - "bundled": true - }, - "asn1": { - "version": "0.2.4", - "bundled": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "bundled": true - }, - "asynckit": { - "version": "0.4.0", - "bundled": true - }, - "aws-sign2": { - "version": "0.7.0", - "bundled": true - }, - "aws4": { - "version": "1.8.0", - "bundled": true - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "bundled": true, - "optional": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "bin-links": { - "version": "1.1.8", - "bundled": true, - "requires": { - "bluebird": "^3.5.3", - "cmd-shim": "^3.0.0", - "gentle-fs": "^2.3.0", - "graceful-fs": "^4.1.15", - "npm-normalize-package-bin": "^1.0.0", - "write-file-atomic": "^2.3.0" - } - }, - "bluebird": { - "version": "3.5.5", - "bundled": true - }, - "boxen": { - "version": "1.3.0", - "bundled": true, - "requires": { - "ansi-align": "^2.0.0", - "camelcase": "^4.0.0", - "chalk": "^2.0.1", - "cli-boxes": "^1.0.0", - "string-width": "^2.0.0", - "term-size": "^1.2.0", - "widest-line": "^2.0.0" - } - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "buffer-from": { - "version": "1.0.0", - "bundled": true - }, - "builtins": { - "version": "1.0.3", - "bundled": true - }, - "byline": { - "version": "5.0.0", - "bundled": true - }, - "byte-size": { - "version": "5.0.1", - "bundled": true - }, - "cacache": { - "version": "12.0.3", - "bundled": true, - "requires": { - "bluebird": "^3.5.5", - "chownr": "^1.1.1", - "figgy-pudding": "^3.5.1", - "glob": "^7.1.4", - "graceful-fs": "^4.1.15", - "infer-owner": "^1.0.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "move-concurrently": "^1.0.1", - "promise-inflight": "^1.0.1", - "rimraf": "^2.6.3", - "ssri": "^6.0.1", - "unique-filename": "^1.1.1", - "y18n": "^4.0.0" - } - }, - "call-limit": { - "version": "1.1.1", - "bundled": true - }, - "camelcase": { - "version": "4.1.0", - "bundled": true - }, - "capture-stack-trace": { - "version": "1.0.0", - "bundled": true - }, - "caseless": { - "version": "0.12.0", - "bundled": true - }, - "chalk": { - "version": "2.4.1", - "bundled": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "chownr": { - "version": "1.1.4", - "bundled": true - }, - "ci-info": { - "version": "2.0.0", - "bundled": true - }, - "cidr-regex": { - "version": "2.0.10", - "bundled": true, - "requires": { - "ip-regex": "^2.1.0" - } - }, - "cli-boxes": { - "version": "1.0.0", - "bundled": true - }, - "cli-columns": { - "version": "3.1.2", - "bundled": true, - "requires": { - "string-width": "^2.0.0", - "strip-ansi": "^3.0.1" - } - }, - "cli-table3": { - "version": "0.5.1", - "bundled": true, - "requires": { - "colors": "^1.1.2", - "object-assign": "^4.1.0", - "string-width": "^2.1.1" - } - }, - "cliui": { - "version": "5.0.0", - "bundled": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "bundled": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true - }, - "string-width": { - "version": "3.1.0", - "bundled": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "bundled": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "clone": { - "version": "1.0.4", - "bundled": true - }, - "cmd-shim": { - "version": "3.0.3", - "bundled": true, - "requires": { - "graceful-fs": "^4.1.2", - "mkdirp": "~0.5.0" - } - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true - }, - "color-convert": { - "version": "1.9.1", - "bundled": true, - "requires": { - "color-name": "^1.1.1" - } - }, - "color-name": { - "version": "1.1.3", - "bundled": true - }, - "colors": { - "version": "1.3.3", - "bundled": true, - "optional": true - }, - "columnify": { - "version": "1.5.4", - "bundled": true, - "requires": { - "strip-ansi": "^3.0.0", - "wcwidth": "^1.0.0" - } - }, - "combined-stream": { - "version": "1.0.6", - "bundled": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - }, - "concat-stream": { - "version": "1.6.2", - "bundled": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "config-chain": { - "version": "1.1.12", - "bundled": true, - "requires": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, - "configstore": { - "version": "3.1.5", - "bundled": true, - "requires": { - "dot-prop": "^4.2.1", - "graceful-fs": "^4.1.2", - "make-dir": "^1.0.0", - "unique-string": "^1.0.0", - "write-file-atomic": "^2.0.0", - "xdg-basedir": "^3.0.0" - } - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true - }, - "copy-concurrently": { - "version": "1.0.5", - "bundled": true, - "requires": { - "aproba": "^1.1.1", - "fs-write-stream-atomic": "^1.0.8", - "iferr": "^0.1.5", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.0" - }, - "dependencies": { - "aproba": { - "version": "1.2.0", - "bundled": true - }, - "iferr": { - "version": "0.1.5", - "bundled": true - } - } - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "create-error-class": { - "version": "3.0.2", - "bundled": true, - "requires": { - "capture-stack-trace": "^1.0.0" - } - }, - "cross-spawn": { - "version": "5.1.0", - "bundled": true, - "requires": { - "lru-cache": "^4.0.1", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.5", - "bundled": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "yallist": { - "version": "2.1.2", - "bundled": true - } - } - }, - "crypto-random-string": { - "version": "1.0.0", - "bundled": true - }, - "cyclist": { - "version": "0.2.2", - "bundled": true - }, - "dashdash": { - "version": "1.14.1", - "bundled": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "debug": { - "version": "3.1.0", - "bundled": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "bundled": true - } - } - }, - "debuglog": { - "version": "1.0.1", - "bundled": true - }, - "decamelize": { - "version": "1.2.0", - "bundled": true - }, - "decode-uri-component": { - "version": "0.2.0", - "bundled": true - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true - }, - "defaults": { - "version": "1.0.3", - "bundled": true, - "requires": { - "clone": "^1.0.2" - } - }, - "define-properties": { - "version": "1.1.3", - "bundled": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "delayed-stream": { - "version": "1.0.0", - "bundled": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true - }, - "detect-indent": { - "version": "5.0.0", - "bundled": true - }, - "detect-newline": { - "version": "2.1.0", - "bundled": true - }, - "dezalgo": { - "version": "1.0.3", - "bundled": true, - "requires": { - "asap": "^2.0.0", - "wrappy": "1" - } - }, - "dot-prop": { - "version": "4.2.1", - "bundled": true, - "requires": { - "is-obj": "^1.0.0" - } - }, - "dotenv": { - "version": "5.0.1", - "bundled": true - }, - "duplexer3": { - "version": "0.1.4", - "bundled": true - }, - "duplexify": { - "version": "3.6.0", - "bundled": true, - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "bundled": true, - "optional": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "editor": { - "version": "1.0.0", - "bundled": true - }, - "emoji-regex": { - "version": "7.0.3", - "bundled": true - }, - "encoding": { - "version": "0.1.12", - "bundled": true, - "requires": { - "iconv-lite": "~0.4.13" - } - }, - "end-of-stream": { - "version": "1.4.1", - "bundled": true, - "requires": { - "once": "^1.4.0" - } - }, - "env-paths": { - "version": "2.2.0", - "bundled": true - }, - "err-code": { - "version": "1.1.2", - "bundled": true - }, - "errno": { - "version": "0.1.7", - "bundled": true, - "requires": { - "prr": "~1.0.1" - } - }, - "es-abstract": { - "version": "1.12.0", - "bundled": true, - "requires": { - "es-to-primitive": "^1.1.1", - "function-bind": "^1.1.1", - "has": "^1.0.1", - "is-callable": "^1.1.3", - "is-regex": "^1.0.4" - } - }, - "es-to-primitive": { - "version": "1.2.0", - "bundled": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "es6-promise": { - "version": "4.2.8", - "bundled": true - }, - "es6-promisify": { - "version": "5.0.0", - "bundled": true, - "requires": { - "es6-promise": "^4.0.3" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "bundled": true - }, - "execa": { - "version": "0.7.0", - "bundled": true, - "requires": { - "cross-spawn": "^5.0.1", - "get-stream": "^3.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - }, - "dependencies": { - "get-stream": { - "version": "3.0.0", - "bundled": true - } - } - }, - "extend": { - "version": "3.0.2", - "bundled": true - }, - "extsprintf": { - "version": "1.3.0", - "bundled": true - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "bundled": true - }, - "figgy-pudding": { - "version": "3.5.1", - "bundled": true - }, - "find-npm-prefix": { - "version": "1.0.2", - "bundled": true - }, - "flush-write-stream": { - "version": "1.0.3", - "bundled": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.4" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "forever-agent": { - "version": "0.6.1", - "bundled": true - }, - "form-data": { - "version": "2.3.2", - "bundled": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "1.0.6", - "mime-types": "^2.1.12" - } - }, - "from2": { - "version": "2.3.0", - "bundled": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "^2.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "fs-minipass": { - "version": "1.2.7", - "bundled": true, - "requires": { - "minipass": "^2.6.0" - }, - "dependencies": { - "minipass": { - "version": "2.9.0", - "bundled": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - } - } - }, - "fs-vacuum": { - "version": "1.2.10", - "bundled": true, - "requires": { - "graceful-fs": "^4.1.2", - "path-is-inside": "^1.0.1", - "rimraf": "^2.5.2" - } - }, - "fs-write-stream-atomic": { - "version": "1.0.10", - "bundled": true, - "requires": { - "graceful-fs": "^4.1.2", - "iferr": "^0.1.5", - "imurmurhash": "^0.1.4", - "readable-stream": "1 || 2" - }, - "dependencies": { - "iferr": { - "version": "0.1.5", - "bundled": true - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true - }, - "function-bind": { - "version": "1.1.1", - "bundled": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - }, - "dependencies": { - "aproba": { - "version": "1.2.0", - "bundled": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } - } - }, - "genfun": { - "version": "5.0.0", - "bundled": true - }, - "gentle-fs": { - "version": "2.3.1", - "bundled": true, - "requires": { - "aproba": "^1.1.2", - "chownr": "^1.1.2", - "cmd-shim": "^3.0.3", - "fs-vacuum": "^1.2.10", - "graceful-fs": "^4.1.11", - "iferr": "^0.1.5", - "infer-owner": "^1.0.4", - "mkdirp": "^0.5.1", - "path-is-inside": "^1.0.2", - "read-cmd-shim": "^1.0.1", - "slide": "^1.1.6" - }, - "dependencies": { - "aproba": { - "version": "1.2.0", - "bundled": true - }, - "iferr": { - "version": "0.1.5", - "bundled": true - } - } - }, - "get-caller-file": { - "version": "2.0.5", - "bundled": true - }, - "get-stream": { - "version": "4.1.0", - "bundled": true, - "requires": { - "pump": "^3.0.0" - } - }, - "getpass": { - "version": "0.1.7", - "bundled": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.1.6", - "bundled": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "global-dirs": { - "version": "0.1.1", - "bundled": true, - "requires": { - "ini": "^1.3.4" - } - }, - "got": { - "version": "6.7.1", - "bundled": true, - "requires": { - "create-error-class": "^3.0.0", - "duplexer3": "^0.1.4", - "get-stream": "^3.0.0", - "is-redirect": "^1.0.0", - "is-retry-allowed": "^1.0.0", - "is-stream": "^1.0.0", - "lowercase-keys": "^1.0.0", - "safe-buffer": "^5.0.1", - "timed-out": "^4.0.0", - "unzip-response": "^2.0.1", - "url-parse-lax": "^1.0.0" - }, - "dependencies": { - "get-stream": { - "version": "3.0.0", - "bundled": true - } - } - }, - "graceful-fs": { - "version": "4.2.4", - "bundled": true - }, - "har-schema": { - "version": "2.0.0", - "bundled": true - }, - "har-validator": { - "version": "5.1.5", - "bundled": true, - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "dependencies": { - "ajv": { - "version": "6.12.6", - "bundled": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "bundled": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "bundled": true - } - } - }, - "has": { - "version": "1.0.3", - "bundled": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "bundled": true - }, - "has-symbols": { - "version": "1.0.0", - "bundled": true - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true - }, - "hosted-git-info": { - "version": "2.8.8", - "bundled": true - }, - "http-cache-semantics": { - "version": "3.8.1", - "bundled": true - }, - "http-proxy-agent": { - "version": "2.1.0", - "bundled": true, - "requires": { - "agent-base": "4", - "debug": "3.1.0" - } - }, - "http-signature": { - "version": "1.2.0", - "bundled": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "https-proxy-agent": { - "version": "2.2.4", - "bundled": true, - "requires": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - } - }, - "humanize-ms": { - "version": "1.2.1", - "bundled": true, - "requires": { - "ms": "^2.0.0" - } - }, - "iconv-lite": { - "version": "0.4.23", - "bundled": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "iferr": { - "version": "1.0.2", - "bundled": true - }, - "ignore-walk": { - "version": "3.0.3", - "bundled": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "import-lazy": { - "version": "2.1.0", - "bundled": true - }, - "imurmurhash": { - "version": "0.1.4", - "bundled": true - }, - "infer-owner": { - "version": "1.0.4", - "bundled": true - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "bundled": true - }, - "ini": { - "version": "1.3.5", - "bundled": true - }, - "init-package-json": { - "version": "1.10.3", - "bundled": true, - "requires": { - "glob": "^7.1.1", - "npm-package-arg": "^4.0.0 || ^5.0.0 || ^6.0.0", - "promzard": "^0.3.0", - "read": "~1.0.1", - "read-package-json": "1 || 2", - "semver": "2.x || 3.x || 4 || 5", - "validate-npm-package-license": "^3.0.1", - "validate-npm-package-name": "^3.0.0" - } - }, - "ip": { - "version": "1.1.5", - "bundled": true - }, - "ip-regex": { - "version": "2.1.0", - "bundled": true - }, - "is-callable": { - "version": "1.1.4", - "bundled": true - }, - "is-ci": { - "version": "1.2.1", - "bundled": true, - "requires": { - "ci-info": "^1.5.0" - }, - "dependencies": { - "ci-info": { - "version": "1.6.0", - "bundled": true - } - } - }, - "is-cidr": { - "version": "3.0.0", - "bundled": true, - "requires": { - "cidr-regex": "^2.0.10" - } - }, - "is-date-object": { - "version": "1.0.1", - "bundled": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-installed-globally": { - "version": "0.1.0", - "bundled": true, - "requires": { - "global-dirs": "^0.1.0", - "is-path-inside": "^1.0.0" - } - }, - "is-npm": { - "version": "1.0.0", - "bundled": true - }, - "is-obj": { - "version": "1.0.1", - "bundled": true - }, - "is-path-inside": { - "version": "1.0.1", - "bundled": true, - "requires": { - "path-is-inside": "^1.0.1" - } - }, - "is-redirect": { - "version": "1.0.0", - "bundled": true - }, - "is-regex": { - "version": "1.0.4", - "bundled": true, - "requires": { - "has": "^1.0.1" - } - }, - "is-retry-allowed": { - "version": "1.2.0", - "bundled": true - }, - "is-stream": { - "version": "1.1.0", - "bundled": true - }, - "is-symbol": { - "version": "1.0.2", - "bundled": true, - "requires": { - "has-symbols": "^1.0.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true - }, - "isexe": { - "version": "2.0.0", - "bundled": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true - }, - "jsbn": { - "version": "0.1.1", - "bundled": true, - "optional": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "bundled": true - }, - "json-schema": { - "version": "0.2.3", - "bundled": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true - }, - "jsonparse": { - "version": "1.3.1", - "bundled": true - }, - "jsprim": { - "version": "1.4.1", - "bundled": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "latest-version": { - "version": "3.1.0", - "bundled": true, - "requires": { - "package-json": "^4.0.0" - } - }, - "lazy-property": { - "version": "1.0.0", - "bundled": true - }, - "libcipm": { - "version": "4.0.8", - "bundled": true, - "requires": { - "bin-links": "^1.1.2", - "bluebird": "^3.5.1", - "figgy-pudding": "^3.5.1", - "find-npm-prefix": "^1.0.2", - "graceful-fs": "^4.1.11", - "ini": "^1.3.5", - "lock-verify": "^2.1.0", - "mkdirp": "^0.5.1", - "npm-lifecycle": "^3.0.0", - "npm-logical-tree": "^1.2.1", - "npm-package-arg": "^6.1.0", - "pacote": "^9.1.0", - "read-package-json": "^2.0.13", - "rimraf": "^2.6.2", - "worker-farm": "^1.6.0" - } - }, - "libnpm": { - "version": "3.0.1", - "bundled": true, - "requires": { - "bin-links": "^1.1.2", - "bluebird": "^3.5.3", - "find-npm-prefix": "^1.0.2", - "libnpmaccess": "^3.0.2", - "libnpmconfig": "^1.2.1", - "libnpmhook": "^5.0.3", - "libnpmorg": "^1.0.1", - "libnpmpublish": "^1.1.2", - "libnpmsearch": "^2.0.2", - "libnpmteam": "^1.0.2", - "lock-verify": "^2.0.2", - "npm-lifecycle": "^3.0.0", - "npm-logical-tree": "^1.2.1", - "npm-package-arg": "^6.1.0", - "npm-profile": "^4.0.2", - "npm-registry-fetch": "^4.0.0", - "npmlog": "^4.1.2", - "pacote": "^9.5.3", - "read-package-json": "^2.0.13", - "stringify-package": "^1.0.0" - } - }, - "libnpmaccess": { - "version": "3.0.2", - "bundled": true, - "requires": { - "aproba": "^2.0.0", - "get-stream": "^4.0.0", - "npm-package-arg": "^6.1.0", - "npm-registry-fetch": "^4.0.0" - } - }, - "libnpmconfig": { - "version": "1.2.1", - "bundled": true, - "requires": { - "figgy-pudding": "^3.5.1", - "find-up": "^3.0.0", - "ini": "^1.3.5" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "bundled": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "locate-path": { - "version": "3.0.0", - "bundled": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.2.0", - "bundled": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "bundled": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "bundled": true - } - } - }, - "libnpmhook": { - "version": "5.0.3", - "bundled": true, - "requires": { - "aproba": "^2.0.0", - "figgy-pudding": "^3.4.1", - "get-stream": "^4.0.0", - "npm-registry-fetch": "^4.0.0" - } - }, - "libnpmorg": { - "version": "1.0.1", - "bundled": true, - "requires": { - "aproba": "^2.0.0", - "figgy-pudding": "^3.4.1", - "get-stream": "^4.0.0", - "npm-registry-fetch": "^4.0.0" - } - }, - "libnpmpublish": { - "version": "1.1.2", - "bundled": true, - "requires": { - "aproba": "^2.0.0", - "figgy-pudding": "^3.5.1", - "get-stream": "^4.0.0", - "lodash.clonedeep": "^4.5.0", - "normalize-package-data": "^2.4.0", - "npm-package-arg": "^6.1.0", - "npm-registry-fetch": "^4.0.0", - "semver": "^5.5.1", - "ssri": "^6.0.1" - } - }, - "libnpmsearch": { - "version": "2.0.2", - "bundled": true, - "requires": { - "figgy-pudding": "^3.5.1", - "get-stream": "^4.0.0", - "npm-registry-fetch": "^4.0.0" - } - }, - "libnpmteam": { - "version": "1.0.2", - "bundled": true, - "requires": { - "aproba": "^2.0.0", - "figgy-pudding": "^3.4.1", - "get-stream": "^4.0.0", - "npm-registry-fetch": "^4.0.0" - } - }, - "libnpx": { - "version": "10.2.4", - "bundled": true, - "requires": { - "dotenv": "^5.0.1", - "npm-package-arg": "^6.0.0", - "rimraf": "^2.6.2", - "safe-buffer": "^5.1.0", - "update-notifier": "^2.3.0", - "which": "^1.3.0", - "y18n": "^4.0.0", - "yargs": "^14.2.3" - } - }, - "lock-verify": { - "version": "2.1.0", - "bundled": true, - "requires": { - "npm-package-arg": "^6.1.0", - "semver": "^5.4.1" - } - }, - "lockfile": { - "version": "1.0.4", - "bundled": true, - "requires": { - "signal-exit": "^3.0.2" - } - }, - "lodash._baseindexof": { - "version": "3.1.0", - "bundled": true - }, - "lodash._baseuniq": { - "version": "4.6.0", - "bundled": true, - "requires": { - "lodash._createset": "~4.0.0", - "lodash._root": "~3.0.0" - } - }, - "lodash._bindcallback": { - "version": "3.0.1", - "bundled": true - }, - "lodash._cacheindexof": { - "version": "3.0.2", - "bundled": true - }, - "lodash._createcache": { - "version": "3.1.2", - "bundled": true, - "requires": { - "lodash._getnative": "^3.0.0" - } - }, - "lodash._createset": { - "version": "4.0.3", - "bundled": true - }, - "lodash._getnative": { - "version": "3.9.1", - "bundled": true - }, - "lodash._root": { - "version": "3.0.1", - "bundled": true - }, - "lodash.clonedeep": { - "version": "4.5.0", - "bundled": true - }, - "lodash.restparam": { - "version": "3.6.1", - "bundled": true - }, - "lodash.union": { - "version": "4.6.0", - "bundled": true - }, - "lodash.uniq": { - "version": "4.5.0", - "bundled": true - }, - "lodash.without": { - "version": "4.4.0", - "bundled": true - }, - "lowercase-keys": { - "version": "1.0.1", - "bundled": true - }, - "lru-cache": { - "version": "5.1.1", - "bundled": true, - "requires": { - "yallist": "^3.0.2" - } - }, - "make-dir": { - "version": "1.3.0", - "bundled": true, - "requires": { - "pify": "^3.0.0" - } - }, - "make-fetch-happen": { - "version": "5.0.2", - "bundled": true, - "requires": { - "agentkeepalive": "^3.4.1", - "cacache": "^12.0.0", - "http-cache-semantics": "^3.8.1", - "http-proxy-agent": "^2.1.0", - "https-proxy-agent": "^2.2.3", - "lru-cache": "^5.1.1", - "mississippi": "^3.0.0", - "node-fetch-npm": "^2.0.2", - "promise-retry": "^1.1.1", - "socks-proxy-agent": "^4.0.0", - "ssri": "^6.0.0" - } - }, - "meant": { - "version": "1.0.2", - "bundled": true - }, - "mime-db": { - "version": "1.35.0", - "bundled": true - }, - "mime-types": { - "version": "2.1.19", - "bundled": true, - "requires": { - "mime-db": "~1.35.0" - } - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.5", - "bundled": true - }, - "minizlib": { - "version": "1.3.3", - "bundled": true, - "requires": { - "minipass": "^2.9.0" - }, - "dependencies": { - "minipass": { - "version": "2.9.0", - "bundled": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - } - } - }, - "mississippi": { - "version": "3.0.0", - "bundled": true, - "requires": { - "concat-stream": "^1.5.0", - "duplexify": "^3.4.2", - "end-of-stream": "^1.1.0", - "flush-write-stream": "^1.0.0", - "from2": "^2.1.0", - "parallel-transform": "^1.1.0", - "pump": "^3.0.0", - "pumpify": "^1.3.3", - "stream-each": "^1.1.0", - "through2": "^2.0.0" - } - }, - "mkdirp": { - "version": "0.5.5", - "bundled": true, - "requires": { - "minimist": "^1.2.5" - }, - "dependencies": { - "minimist": { - "version": "1.2.5", - "bundled": true - } - } - }, - "move-concurrently": { - "version": "1.0.1", - "bundled": true, - "requires": { - "aproba": "^1.1.1", - "copy-concurrently": "^1.0.0", - "fs-write-stream-atomic": "^1.0.8", - "mkdirp": "^0.5.1", - "rimraf": "^2.5.4", - "run-queue": "^1.0.3" - }, - "dependencies": { - "aproba": { - "version": "1.2.0", - "bundled": true - } - } - }, - "ms": { - "version": "2.1.1", - "bundled": true - }, - "mute-stream": { - "version": "0.0.7", - "bundled": true - }, - "node-fetch-npm": { - "version": "2.0.2", - "bundled": true, - "requires": { - "encoding": "^0.1.11", - "json-parse-better-errors": "^1.0.0", - "safe-buffer": "^5.1.1" - } - }, - "node-gyp": { - "version": "5.1.0", - "bundled": true, - "requires": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.2", - "mkdirp": "^0.5.1", - "nopt": "^4.0.1", - "npmlog": "^4.1.2", - "request": "^2.88.0", - "rimraf": "^2.6.3", - "semver": "^5.7.1", - "tar": "^4.4.12", - "which": "^1.3.1" - } - }, - "nopt": { - "version": "4.0.3", - "bundled": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "normalize-package-data": { - "version": "2.5.0", - "bundled": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "resolve": { - "version": "1.10.0", - "bundled": true, - "requires": { - "path-parse": "^1.0.6" - } - } - } - }, - "npm-audit-report": { - "version": "1.3.3", - "bundled": true, - "requires": { - "cli-table3": "^0.5.0", - "console-control-strings": "^1.1.0" - } - }, - "npm-bundled": { - "version": "1.1.1", - "bundled": true, - "requires": { - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npm-cache-filename": { - "version": "1.0.2", - "bundled": true - }, - "npm-install-checks": { - "version": "3.0.2", - "bundled": true, - "requires": { - "semver": "^2.3.0 || 3.x || 4 || 5" - } - }, - "npm-lifecycle": { - "version": "3.1.5", - "bundled": true, - "requires": { - "byline": "^5.0.0", - "graceful-fs": "^4.1.15", - "node-gyp": "^5.0.2", - "resolve-from": "^4.0.0", - "slide": "^1.1.6", - "uid-number": "0.0.6", - "umask": "^1.1.0", - "which": "^1.3.1" - } - }, - "npm-logical-tree": { - "version": "1.2.1", - "bundled": true - }, - "npm-normalize-package-bin": { - "version": "1.0.1", - "bundled": true - }, - "npm-package-arg": { - "version": "6.1.1", - "bundled": true, - "requires": { - "hosted-git-info": "^2.7.1", - "osenv": "^0.1.5", - "semver": "^5.6.0", - "validate-npm-package-name": "^3.0.0" - } - }, - "npm-packlist": { - "version": "1.4.8", - "bundled": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1", - "npm-normalize-package-bin": "^1.0.1" - } - }, - "npm-pick-manifest": { - "version": "3.0.2", - "bundled": true, - "requires": { - "figgy-pudding": "^3.5.1", - "npm-package-arg": "^6.0.0", - "semver": "^5.4.1" - } - }, - "npm-profile": { - "version": "4.0.4", - "bundled": true, - "requires": { - "aproba": "^1.1.2 || 2", - "figgy-pudding": "^3.4.1", - "npm-registry-fetch": "^4.0.0" - } - }, - "npm-registry-fetch": { - "version": "4.0.7", - "bundled": true, - "requires": { - "JSONStream": "^1.3.4", - "bluebird": "^3.5.1", - "figgy-pudding": "^3.4.1", - "lru-cache": "^5.1.1", - "make-fetch-happen": "^5.0.0", - "npm-package-arg": "^6.1.0", - "safe-buffer": "^5.2.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.1", - "bundled": true - } - } - }, - "npm-run-path": { - "version": "2.0.2", - "bundled": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "npm-user-validate": { - "version": "1.0.1", - "bundled": true - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true - }, - "oauth-sign": { - "version": "0.9.0", - "bundled": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true - }, - "object-keys": { - "version": "1.0.12", - "bundled": true - }, - "object.getownpropertydescriptors": { - "version": "2.0.3", - "bundled": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" - } - }, - "once": { - "version": "1.4.0", - "bundled": true, - "requires": { - "wrappy": "1" - } - }, - "opener": { - "version": "1.5.1", - "bundled": true - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "p-finally": { - "version": "1.0.0", - "bundled": true - }, - "package-json": { - "version": "4.0.1", - "bundled": true, - "requires": { - "got": "^6.7.1", - "registry-auth-token": "^3.0.1", - "registry-url": "^3.0.3", - "semver": "^5.1.0" - } - }, - "pacote": { - "version": "9.5.12", - "bundled": true, - "requires": { - "bluebird": "^3.5.3", - "cacache": "^12.0.2", - "chownr": "^1.1.2", - "figgy-pudding": "^3.5.1", - "get-stream": "^4.1.0", - "glob": "^7.1.3", - "infer-owner": "^1.0.4", - "lru-cache": "^5.1.1", - "make-fetch-happen": "^5.0.0", - "minimatch": "^3.0.4", - "minipass": "^2.3.5", - "mississippi": "^3.0.0", - "mkdirp": "^0.5.1", - "normalize-package-data": "^2.4.0", - "npm-normalize-package-bin": "^1.0.0", - "npm-package-arg": "^6.1.0", - "npm-packlist": "^1.1.12", - "npm-pick-manifest": "^3.0.0", - "npm-registry-fetch": "^4.0.0", - "osenv": "^0.1.5", - "promise-inflight": "^1.0.1", - "promise-retry": "^1.1.1", - "protoduck": "^5.0.1", - "rimraf": "^2.6.2", - "safe-buffer": "^5.1.2", - "semver": "^5.6.0", - "ssri": "^6.0.1", - "tar": "^4.4.10", - "unique-filename": "^1.1.1", - "which": "^1.3.1" - }, - "dependencies": { - "minipass": { - "version": "2.9.0", - "bundled": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - } - } - }, - "parallel-transform": { - "version": "1.1.0", - "bundled": true, - "requires": { - "cyclist": "~0.2.2", - "inherits": "^2.0.3", - "readable-stream": "^2.1.5" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "path-exists": { - "version": "3.0.0", - "bundled": true - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true - }, - "path-is-inside": { - "version": "1.0.2", - "bundled": true - }, - "path-key": { - "version": "2.0.1", - "bundled": true - }, - "path-parse": { - "version": "1.0.6", - "bundled": true - }, - "performance-now": { - "version": "2.1.0", - "bundled": true - }, - "pify": { - "version": "3.0.0", - "bundled": true - }, - "prepend-http": { - "version": "1.0.4", - "bundled": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true - }, - "promise-inflight": { - "version": "1.0.1", - "bundled": true - }, - "promise-retry": { - "version": "1.1.1", - "bundled": true, - "requires": { - "err-code": "^1.0.0", - "retry": "^0.10.0" - }, - "dependencies": { - "retry": { - "version": "0.10.1", - "bundled": true - } - } - }, - "promzard": { - "version": "0.3.0", - "bundled": true, - "requires": { - "read": "1" - } - }, - "proto-list": { - "version": "1.2.4", - "bundled": true - }, - "protoduck": { - "version": "5.0.1", - "bundled": true, - "requires": { - "genfun": "^5.0.0" - } - }, - "prr": { - "version": "1.0.1", - "bundled": true - }, - "pseudomap": { - "version": "1.0.2", - "bundled": true - }, - "psl": { - "version": "1.1.29", - "bundled": true - }, - "pump": { - "version": "3.0.0", - "bundled": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "pumpify": { - "version": "1.5.1", - "bundled": true, - "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - }, - "dependencies": { - "pump": { - "version": "2.0.1", - "bundled": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - } - } - }, - "punycode": { - "version": "1.4.1", - "bundled": true - }, - "qrcode-terminal": { - "version": "0.12.0", - "bundled": true - }, - "qs": { - "version": "6.5.2", - "bundled": true - }, - "query-string": { - "version": "6.8.2", - "bundled": true, - "requires": { - "decode-uri-component": "^0.2.0", - "split-on-first": "^1.0.0", - "strict-uri-encode": "^2.0.0" - } - }, - "qw": { - "version": "1.0.1", - "bundled": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, - "read": { - "version": "1.0.7", - "bundled": true, - "requires": { - "mute-stream": "~0.0.4" - } - }, - "read-cmd-shim": { - "version": "1.0.5", - "bundled": true, - "requires": { - "graceful-fs": "^4.1.2" - } - }, - "read-installed": { - "version": "4.0.3", - "bundled": true, - "requires": { - "debuglog": "^1.0.1", - "graceful-fs": "^4.1.2", - "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0", - "semver": "2 || 3 || 4 || 5", - "slide": "~1.1.3", - "util-extend": "^1.0.1" - } - }, - "read-package-json": { - "version": "2.1.1", - "bundled": true, - "requires": { - "glob": "^7.1.1", - "graceful-fs": "^4.1.2", - "json-parse-better-errors": "^1.0.1", - "normalize-package-data": "^2.0.0", - "npm-normalize-package-bin": "^1.0.0" - } - }, - "read-package-tree": { - "version": "5.3.1", - "bundled": true, - "requires": { - "read-package-json": "^2.0.0", - "readdir-scoped-modules": "^1.0.0", - "util-promisify": "^2.1.0" - } - }, - "readable-stream": { - "version": "3.6.0", - "bundled": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, - "readdir-scoped-modules": { - "version": "1.1.0", - "bundled": true, - "requires": { - "debuglog": "^1.0.1", - "dezalgo": "^1.0.0", - "graceful-fs": "^4.1.2", - "once": "^1.3.0" - } - }, - "registry-auth-token": { - "version": "3.4.0", - "bundled": true, - "requires": { - "rc": "^1.1.6", - "safe-buffer": "^5.0.1" - } - }, - "registry-url": { - "version": "3.1.0", - "bundled": true, - "requires": { - "rc": "^1.0.1" - } - }, - "request": { - "version": "2.88.0", - "bundled": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, - "require-directory": { - "version": "2.1.1", - "bundled": true - }, - "require-main-filename": { - "version": "2.0.0", - "bundled": true - }, - "resolve-from": { - "version": "4.0.0", - "bundled": true - }, - "retry": { - "version": "0.12.0", - "bundled": true - }, - "rimraf": { - "version": "2.7.1", - "bundled": true, - "requires": { - "glob": "^7.1.3" - } - }, - "run-queue": { - "version": "1.0.3", - "bundled": true, - "requires": { - "aproba": "^1.1.1" - }, - "dependencies": { - "aproba": { - "version": "1.2.0", - "bundled": true - } - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true - }, - "semver": { - "version": "5.7.1", - "bundled": true - }, - "semver-diff": { - "version": "2.1.0", - "bundled": true, - "requires": { - "semver": "^5.0.3" - } - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true - }, - "sha": { - "version": "3.0.0", - "bundled": true, - "requires": { - "graceful-fs": "^4.1.2" - } - }, - "shebang-command": { - "version": "1.2.0", - "bundled": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "bundled": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true - }, - "slide": { - "version": "1.1.6", - "bundled": true - }, - "smart-buffer": { - "version": "4.1.0", - "bundled": true - }, - "socks": { - "version": "2.3.3", - "bundled": true, - "requires": { - "ip": "1.1.5", - "smart-buffer": "^4.1.0" - } - }, - "socks-proxy-agent": { - "version": "4.0.2", - "bundled": true, - "requires": { - "agent-base": "~4.2.1", - "socks": "~2.3.2" - }, - "dependencies": { - "agent-base": { - "version": "4.2.1", - "bundled": true, - "requires": { - "es6-promisify": "^5.0.0" - } - } - } - }, - "sorted-object": { - "version": "2.0.1", - "bundled": true - }, - "sorted-union-stream": { - "version": "2.1.3", - "bundled": true, - "requires": { - "from2": "^1.3.0", - "stream-iterate": "^1.1.0" - }, - "dependencies": { - "from2": { - "version": "1.3.0", - "bundled": true, - "requires": { - "inherits": "~2.0.1", - "readable-stream": "~1.1.10" - } - }, - "isarray": { - "version": "0.0.1", - "bundled": true - }, - "readable-stream": { - "version": "1.1.14", - "bundled": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - } - } - }, - "spdx-correct": { - "version": "3.0.0", - "bundled": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.1.0", - "bundled": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "bundled": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.5", - "bundled": true - }, - "split-on-first": { - "version": "1.1.0", - "bundled": true - }, - "sshpk": { - "version": "1.14.2", - "bundled": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "ssri": { - "version": "6.0.1", - "bundled": true, - "requires": { - "figgy-pudding": "^3.5.1" - } - }, - "stream-each": { - "version": "1.2.2", - "bundled": true, - "requires": { - "end-of-stream": "^1.1.0", - "stream-shift": "^1.0.0" - } - }, - "stream-iterate": { - "version": "1.2.0", - "bundled": true, - "requires": { - "readable-stream": "^2.1.5", - "stream-shift": "^1.0.0" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "stream-shift": { - "version": "1.0.0", - "bundled": true - }, - "strict-uri-encode": { - "version": "2.0.0", - "bundled": true - }, - "string-width": { - "version": "2.1.1", - "bundled": true, - "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "bundled": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true - }, - "strip-ansi": { - "version": "4.0.0", - "bundled": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "string_decoder": { - "version": "1.3.0", - "bundled": true, - "requires": { - "safe-buffer": "~5.2.0" - }, - "dependencies": { - "safe-buffer": { - "version": "5.2.0", - "bundled": true - } - } - }, - "stringify-package": { - "version": "1.0.1", - "bundled": true - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-eof": { - "version": "1.0.0", - "bundled": true - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true - }, - "supports-color": { - "version": "5.4.0", - "bundled": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "tar": { - "version": "4.4.13", - "bundled": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.8.6", - "minizlib": "^1.2.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.3" - }, - "dependencies": { - "minipass": { - "version": "2.9.0", - "bundled": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - } - } - }, - "term-size": { - "version": "1.2.0", - "bundled": true, - "requires": { - "execa": "^0.7.0" - } - }, - "text-table": { - "version": "0.2.0", - "bundled": true - }, - "through": { - "version": "2.3.8", - "bundled": true - }, - "through2": { - "version": "2.0.3", - "bundled": true, - "requires": { - "readable-stream": "^2.1.5", - "xtend": "~4.0.1" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "timed-out": { - "version": "4.0.1", - "bundled": true - }, - "tiny-relative-date": { - "version": "1.3.0", - "bundled": true - }, - "tough-cookie": { - "version": "2.4.3", - "bundled": true, - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "bundled": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "bundled": true, - "optional": true - }, - "typedarray": { - "version": "0.0.6", - "bundled": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true - }, - "umask": { - "version": "1.1.0", - "bundled": true - }, - "unique-filename": { - "version": "1.1.1", - "bundled": true, - "requires": { - "unique-slug": "^2.0.0" - } - }, - "unique-slug": { - "version": "2.0.0", - "bundled": true, - "requires": { - "imurmurhash": "^0.1.4" - } - }, - "unique-string": { - "version": "1.0.0", - "bundled": true, - "requires": { - "crypto-random-string": "^1.0.0" - } - }, - "unpipe": { - "version": "1.0.0", - "bundled": true - }, - "unzip-response": { - "version": "2.0.1", - "bundled": true - }, - "update-notifier": { - "version": "2.5.0", - "bundled": true, - "requires": { - "boxen": "^1.2.1", - "chalk": "^2.0.1", - "configstore": "^3.0.0", - "import-lazy": "^2.1.0", - "is-ci": "^1.0.10", - "is-installed-globally": "^0.1.0", - "is-npm": "^1.0.0", - "latest-version": "^3.0.0", - "semver-diff": "^2.0.0", - "xdg-basedir": "^3.0.0" - } - }, - "uri-js": { - "version": "4.4.0", - "bundled": true, - "requires": { - "punycode": "^2.1.0" - }, - "dependencies": { - "punycode": { - "version": "2.1.1", - "bundled": true - } - } - }, - "url-parse-lax": { - "version": "1.0.0", - "bundled": true, - "requires": { - "prepend-http": "^1.0.1" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - }, - "util-extend": { - "version": "1.0.3", - "bundled": true - }, - "util-promisify": { - "version": "2.1.0", - "bundled": true, - "requires": { - "object.getownpropertydescriptors": "^2.0.3" - } - }, - "uuid": { - "version": "3.3.3", - "bundled": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "bundled": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "validate-npm-package-name": { - "version": "3.0.0", - "bundled": true, - "requires": { - "builtins": "^1.0.3" - } - }, - "verror": { - "version": "1.10.0", - "bundled": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "wcwidth": { - "version": "1.0.1", - "bundled": true, - "requires": { - "defaults": "^1.0.3" - } - }, - "which": { - "version": "1.3.1", - "bundled": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "bundled": true - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "requires": { - "string-width": "^1.0.2" - }, - "dependencies": { - "string-width": { - "version": "1.0.2", - "bundled": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - } - } - }, - "widest-line": { - "version": "2.0.1", - "bundled": true, - "requires": { - "string-width": "^2.1.1" - } - }, - "worker-farm": { - "version": "1.7.0", - "bundled": true, - "requires": { - "errno": "~0.1.7" - } - }, - "wrap-ansi": { - "version": "5.1.0", - "bundled": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "bundled": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true - }, - "string-width": { - "version": "3.1.0", - "bundled": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "bundled": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true - }, - "write-file-atomic": { - "version": "2.4.3", - "bundled": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "xdg-basedir": { - "version": "3.0.0", - "bundled": true - }, - "xtend": { - "version": "4.0.1", - "bundled": true - }, - "y18n": { - "version": "4.0.0", - "bundled": true - }, - "yallist": { - "version": "3.0.3", - "bundled": true - }, - "yargs": { - "version": "14.2.3", - "bundled": true, - "requires": { - "cliui": "^5.0.0", - "decamelize": "^1.2.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^15.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "bundled": true - }, - "find-up": { - "version": "3.0.0", - "bundled": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true - }, - "locate-path": { - "version": "3.0.0", - "bundled": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-limit": { - "version": "2.3.0", - "bundled": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "bundled": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-try": { - "version": "2.2.0", - "bundled": true - }, - "string-width": { - "version": "3.1.0", - "bundled": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "bundled": true, - "requires": { - "ansi-regex": "^4.1.0" - } - } - } - }, - "yargs-parser": { - "version": "15.0.1", - "bundled": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "dependencies": { - "camelcase": { - "version": "5.3.1", - "bundled": true - } - } - } - } - }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -18987,13 +15897,9 @@ } }, "open-color": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/open-color/-/open-color-1.7.0.tgz", - "integrity": "sha512-Kyl74V5gohYxajOVgIaXhvhjKtXfhwl7ddJ28HVXDkPuM8PVdaWbFPucf6qPGW6aXOMxnukw0/R1lLLyXKEffA==", - "requires": { - "lodash": "^4.17.11", - "npm": "^6.9.0" - } + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/open-color/-/open-color-1.8.0.tgz", + "integrity": "sha512-gSHRpWLx83rKlHZIm9ZoUBsSMijhPRMxOOacUETjY8guu9dAwIAbtZgmVqkfglmhs3/pYppGohzp8fUdJ4YBqQ==" }, "openapi3-ts": { "version": "1.4.0", @@ -19187,6 +16093,34 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" }, + "pac-proxy-agent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-4.1.0.tgz", + "integrity": "sha512-ejNgYm2HTXSIYX9eFlkvqFp8hyJ374uDf0Zq5YUAifiSh1D6fo+iBivQZirGvVv8dCYUsLhmLBRhlAYvBKI5+Q==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4", + "get-uri": "3", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "5", + "pac-resolver": "^4.1.0", + "raw-body": "^2.2.0", + "socks-proxy-agent": "5" + } + }, + "pac-resolver": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-4.1.0.tgz", + "integrity": "sha512-d6lf2IrZJJ7ooVHr7BfwSjRO1yKSJMaiiWYSHcrxSIUtZrCa4KKGwcztdkZ/E9LFleJfjoi1yl+XLR7AX24nbQ==", + "dev": true, + "requires": { + "degenerator": "^2.2.0", + "ip": "^1.1.5", + "netmask": "^1.0.6" + } + }, "package-json": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", @@ -20718,6 +17652,28 @@ "ipaddr.js": "1.9.1" } }, + "proxy-agent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-4.0.0.tgz", + "integrity": "sha512-8P0Y2SkwvKjiGU1IkEfYuTteioMIDFxPL4/j49zzt5Mz3pG1KO+mIrDG1qH0PQUHTTczjwGcYl+EzfXiFj5vUQ==", + "dev": true, + "requires": { + "agent-base": "^6.0.0", + "debug": "4", + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "lru-cache": "^5.1.1", + "pac-proxy-agent": "^4.1.0", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^5.0.0" + } + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, "prr": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", @@ -21026,9 +17982,9 @@ } }, "tar": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.0.5.tgz", - "integrity": "sha512-0b4HOimQHj9nXNEAA7zWwMM91Zhhba3pspja6sQbgTpynOJf+bkjBnfybNYzbpLbnwXnbyB4LOREvlyXLkCHSg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.0.tgz", + "integrity": "sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==", "dev": true, "optional": true, "requires": { @@ -22509,9 +19465,9 @@ } }, "semver-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz", - "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-3.1.2.tgz", + "integrity": "sha512-bXWyL6EAKOJa81XG1OZ/Yyuq+oT0b2YLlxx7c+mrdYPaPbnj6WgVULXhinMIeZGufuUBu/eVRqXEhiv4imfwxA==", "dev": true }, "send": { @@ -22789,6 +19745,12 @@ "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" }, + "smart-buffer": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz", + "integrity": "sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw==", + "dev": true + }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -23003,6 +19965,27 @@ } } }, + "socks": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.5.1.tgz", + "integrity": "sha512-oZCsJJxapULAYJaEYBSzMcz8m3jqgGrHaGhkmU/o/PQfFWYWxkAaA0UMGImb6s6tEXfKi959X6VJjMMQ3P6TTQ==", + "dev": true, + "requires": { + "ip": "^1.1.5", + "smart-buffer": "^4.1.0" + } + }, + "socks-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-5.0.0.tgz", + "integrity": "sha512-lEpa1zsWCChxiynk+lCycKuC502RxDWLKJZoIhnxrWNjLSDGYRFflHA1/228VkRcnv9TIb8w98derGbpKxJRgA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4", + "socks": "^2.3.3" + } + }, "sort-keys": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", @@ -23770,9 +20753,9 @@ } }, "tar-stream": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.4.tgz", - "integrity": "sha512-o3pS2zlG4gxr67GmFYBLlq+dM8gyRGUOvsrHclSkvtVtQbjV0s/+ZE8OpICbaj8clrX3tjeHngYGP7rweaBnuw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", "dev": true, "requires": { "bl": "^4.0.3", @@ -26316,6 +23299,12 @@ "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=" }, + "xregexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", + "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=", + "dev": true + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -26389,6 +23378,12 @@ "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=" }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + }, "zip-stream": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-2.1.3.tgz", diff --git a/package.json b/package.json index b75d7bedb..4c5771e7d 100644 --- a/package.json +++ b/package.json @@ -19,23 +19,23 @@ ] }, "dependencies": { - "@sentry/browser": "5.29.0", - "@sentry/integrations": "5.29.0", - "@testing-library/jest-dom": "5.11.6", - "@testing-library/react": "11.2.2", - "@types/jest": "26.0.19", + "@sentry/browser": "5.29.2", + "@sentry/integrations": "5.29.2", + "@testing-library/jest-dom": "5.11.8", + "@testing-library/react": "11.2.3", + "@types/jest": "26.0.20", "@types/nanoid": "2.1.0", "@types/react": "17.0.0", "@types/react-dom": "17.0.0", "@types/socket.io-client": "1.4.34", "browser-nativefs": "0.12.0", "clsx": "1.1.1", - "firebase": "8.2.1", + "firebase": "8.2.2", "i18next-browser-languagedetector": "6.0.1", "lodash.throttle": "4.1.1", "nanoid": "2.1.11", "node-sass": "4.14.1", - "open-color": "1.7.0", + "open-color": "1.8.0", "pako": "1.0.11", "png-chunk-text": "1.0.0", "png-chunks-encode": "1.0.0", @@ -53,9 +53,9 @@ "@types/lodash.throttle": "4.1.6", "@types/pako": "1.0.1", "eslint-config-prettier": "7.1.0", - "eslint-plugin-prettier": "3.3.0", - "firebase-tools": "9.0.1", - "husky": "4.3.6", + "eslint-plugin-prettier": "3.3.1", + "firebase-tools": "9.1.2", + "husky": "4.3.7", "jest-canvas-mock": "2.3.0", "lint-staged": "10.5.3", "pepjs": "0.5.3", @@ -81,8 +81,8 @@ "private": true, "scripts": { "build-node": "node ./scripts/build-node.js", - "build:app:docker": "REACT_APP_INCLUDE_GTAG=false REACT_APP_DISABLE_SENTRY=true react-scripts build", - "build:app": "REACT_APP_INCLUDE_GTAG=true REACT_APP_GIT_SHA=$NOW_GITHUB_COMMIT_SHA react-scripts build", + "build:app:docker": "REACT_APP_DISABLE_SENTRY=true react-scripts build", + "build:app": "REACT_APP_GIT_SHA=$NOW_GITHUB_COMMIT_SHA react-scripts build", "build:version": "node ./scripts/build-version.js", "build": "npm run build:app && npm run build:version", "eject": "react-scripts eject", diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png index e228a7323..40af4de2f 100644 Binary files a/public/apple-touch-icon.png and b/public/apple-touch-icon.png differ diff --git a/public/index.html b/public/index.html index 138dc4e0e..24b76e866 100644 --- a/public/index.html +++ b/public/index.html @@ -86,10 +86,10 @@ - <% if (process.env.REACT_APP_INCLUDE_GTAG === 'true') { %> + <% if (process.env.REACT_APP_GOOGLE_ANALYTICS_ID) { %> <% } %> diff --git a/public/logo-180x180.png b/public/logo-180x180.png index ade636cda..9aa9b103b 100644 Binary files a/public/logo-180x180.png and b/public/logo-180x180.png differ diff --git a/public/og-image.png b/public/og-image.png index 1601d16ed..8f05f7bab 100644 Binary files a/public/og-image.png and b/public/og-image.png differ diff --git a/scripts/build-version.js b/scripts/build-version.js index 06b31b433..0d77f7dac 100755 --- a/scripts/build-version.js +++ b/scripts/build-version.js @@ -5,23 +5,40 @@ const path = require("path"); const versionFile = path.join("build", "version.json"); const indexFile = path.join("build", "index.html"); -const zero = (digit) => `0${digit}`.slice(-2); +const versionDate = (date) => date.toISOString().replace(".000", ""); -const versionDate = (date) => { - const date_ = `${date.getFullYear()}-${zero(date.getMonth() + 1)}-${zero( - date.getDate(), - )}`; - const time = `${zero(date.getHours())}-${zero(date.getMinutes())}-${zero( - date.getSeconds(), - )}`; - return `${date_}-${time}`; +const commitHash = () => { + try { + return require("child_process") + .execSync("git rev-parse --short HEAD") + .toString() + .trim(); + } catch { + return "none"; + } }; -const now = new Date(); +const commitDate = (hash) => { + try { + const unix = require("child_process") + .execSync(`git show -s --format=%ct ${hash}`) + .toString() + .trim(); + const date = new Date(parseInt(unix) * 1000); + return versionDate(date); + } catch { + return versionDate(new Date()); + } +}; + +const getFullVersion = () => { + const hash = commitHash(); + return `${commitDate(hash)}-${hash}`; +}; const data = JSON.stringify( { - version: versionDate(now), + version: getFullVersion(), }, undefined, 2, @@ -34,7 +51,7 @@ fs.readFile(indexFile, "utf8", (error, data) => { if (error) { return console.error(error); } - const result = data.replace(/{version}/g, versionDate(now)); + const result = data.replace(/{version}/g, getFullVersion()); fs.writeFile(indexFile, result, "utf8", (error) => { if (error) { diff --git a/scripts/locales-coverage-description.js b/scripts/locales-coverage-description.js index 3a8ea7951..df5794409 100644 --- a/scripts/locales-coverage-description.js +++ b/scripts/locales-coverage-description.js @@ -4,26 +4,28 @@ const THRESSHOLD = 85; const crowdinMap = { "ar-SA": "en-ar", - "el-GR": "en-el", - "fi-FI": "en-fi", - "ja-JP": "en-ja", "bg-BG": "en-bg", "ca-ES": "en-ca", "de-DE": "en-de", + "el-GR": "en-el", "es-ES": "en-es", "fa-IR": "en-fa", + "fi-FI": "en-fi", "fr-FR": "en-fr", "he-IL": "en-he", "hi-IN": "en-hi", "hu-HU": "en-hu", "id-ID": "en-id", "it-IT": "en-it", + "ja-JP": "en-ja", "ko-KR": "en-ko", "my-MM": "en-my", "nb-NO": "en-nb", "nl-NL": "en-nl", "nn-NO": "en-nnno", + "pa-IN": "en-pain", "pl-PL": "en-pl", + "pt-BR": "en-ptbr", "pt-PT": "en-pt", "ro-RO": "en-ro", "ru-RU": "en-ru", @@ -56,7 +58,9 @@ const flags = { "nb-NO": "🇳🇴", "nl-NL": "🇳🇱", "nn-NO": "🇳🇴", + "pa-IN": "🇮🇳", "pl-PL": "🇵🇱", + "pt-BR": "🇧🇷", "pt-PT": "🇵🇹", "ro-RO": "🇷🇴", "ru-RU": "🇷🇺", @@ -71,7 +75,7 @@ const flags = { const languages = { "ar-SA": "العربية", "bg-BG": "Български", - "ca-ES": "Catalan", + "ca-ES": "Català", "de-DE": "Deutsch", "el-GR": "Ελληνικά", "es-ES": "Español", @@ -89,7 +93,9 @@ const languages = { "nb-NO": "Norsk bokmål", "nl-NL": "Nederlands", "nn-NO": "Norsk nynorsk", + "pa-IN": "ਪੰਜਾਬੀ", "pl-PL": "Polski", + "pt-BR": "Português Brasileiro", "pt-PT": "Português", "ro-RO": "Română", "ru-RU": "Русский", @@ -114,16 +120,14 @@ const boldIf = (text, condition) => (condition ? `**${text}**` : text); const printHeader = () => { let result = "| | Flag | Locale | % |\n"; - result += "| --: | :--: | -- | --: |"; + result += "| :--: | :--: | -- | :--: |"; return result; }; const printRow = (id, locale, coverage) => { - const isOver = coverage > THRESSHOLD; - let result = `| ${boldIf(id, isOver)} | `; - + const isOver = coverage >= THRESSHOLD; + let result = `| ${isOver ? id : "..."} | `; result += `${locale in flags ? flags[locale] : ""} | `; - const language = locale in languages ? languages[locale] : locale; if (locale in crowdinMap && crowdinMap[locale]) { result += `[${boldIf( @@ -133,14 +137,12 @@ const printRow = (id, locale, coverage) => { } else { result += `${boldIf(language, isOver)} | `; } - result += `${boldIf(coverage, isOver)} |`; + result += `${coverage === 100 ? "💯" : boldIf(coverage, isOver)} |`; return result; }; -console.info("## Languages check"); -console.info("\n\r"); console.info( - `Our translations for every languages should be at least **${THRESSHOLD}%** to appear on Excalidraw. Join our project in [Crowdin](https://crowdin.com/project/excalidraw) and help us translate it in your language. **Can't find your own?** Open an [issue](https://github.com/excalidraw/excalidraw/issues/new) and we'll add it to the list.`, + `Each language must be at least **${THRESSHOLD}%** translated in order to appear on Excalidraw. Join us on [Crowdin](https://crowdin.com/project/excalidraw) and help us translate your own language. **Can't find yours yet?** Open an [issue](https://github.com/excalidraw/excalidraw/issues/new) and we'll add it to the list.`, ); console.info("\n\r"); console.info(printHeader()); diff --git a/src/actions/actionAddToLibrary.ts b/src/actions/actionAddToLibrary.ts index 53727a819..a0abbf5ca 100644 --- a/src/actions/actionAddToLibrary.ts +++ b/src/actions/actionAddToLibrary.ts @@ -3,7 +3,6 @@ import { getSelectedElements } from "../scene"; import { getNonDeletedElements } from "../element"; import { deepCopyElement } from "../element/newElement"; import { Library } from "../data/library"; -import { EVENT_LIBRARY, trackEvent } from "../analytics"; export const actionAddToLibrary = register({ name: "addToLibrary", @@ -16,7 +15,6 @@ export const actionAddToLibrary = register({ Library.loadLibrary().then((items) => { Library.saveLibrary([...items, selectedElements.map(deepCopyElement)]); }); - trackEvent(EVENT_LIBRARY, "add"); return false; }, contextMenuOrder: 6, diff --git a/src/actions/actionAlign.tsx b/src/actions/actionAlign.tsx index 77c1e8800..5397df9b4 100644 --- a/src/actions/actionAlign.tsx +++ b/src/actions/actionAlign.tsx @@ -1,7 +1,5 @@ import React from "react"; -import { KEYS } from "../keys"; -import { t } from "../i18n"; -import { register } from "./register"; +import { alignElements, Alignment } from "../align"; import { AlignBottomIcon, AlignLeftIcon, @@ -10,14 +8,15 @@ import { CenterHorizontallyIcon, CenterVerticallyIcon, } from "../components/icons"; -import { getSelectedElements, isSomeElementSelected } from "../scene"; -import { getElementMap, getNonDeletedElements } from "../element"; import { ToolButton } from "../components/ToolButton"; +import { getElementMap, getNonDeletedElements } from "../element"; import { ExcalidrawElement } from "../element/types"; +import { t } from "../i18n"; +import { KEYS } from "../keys"; +import { getSelectedElements, isSomeElementSelected } from "../scene"; import { AppState } from "../types"; -import { alignElements, Alignment } from "../align"; import { getShortcutKey } from "../utils"; -import { trackEvent, EVENT_ALIGN } from "../analytics"; +import { register } from "./register"; const enableActionGroup = ( elements: readonly ExcalidrawElement[], @@ -44,7 +43,6 @@ const alignSelectedElements = ( export const actionAlignTop = register({ name: "alignTop", perform: (elements, appState) => { - trackEvent(EVENT_ALIGN, "align", "top"); return { appState, elements: alignSelectedElements(elements, appState, { @@ -74,7 +72,6 @@ export const actionAlignTop = register({ export const actionAlignBottom = register({ name: "alignBottom", perform: (elements, appState) => { - trackEvent(EVENT_ALIGN, "align", "bottom"); return { appState, elements: alignSelectedElements(elements, appState, { @@ -104,7 +101,6 @@ export const actionAlignBottom = register({ export const actionAlignLeft = register({ name: "alignLeft", perform: (elements, appState) => { - trackEvent(EVENT_ALIGN, "align", "left"); return { appState, elements: alignSelectedElements(elements, appState, { @@ -134,7 +130,6 @@ export const actionAlignLeft = register({ export const actionAlignRight = register({ name: "alignRight", perform: (elements, appState) => { - trackEvent(EVENT_ALIGN, "align", "right"); return { appState, elements: alignSelectedElements(elements, appState, { @@ -164,7 +159,6 @@ export const actionAlignRight = register({ export const actionAlignVerticallyCentered = register({ name: "alignVerticallyCentered", perform: (elements, appState) => { - trackEvent(EVENT_ALIGN, "vertically", "center"); return { appState, elements: alignSelectedElements(elements, appState, { @@ -190,7 +184,6 @@ export const actionAlignVerticallyCentered = register({ export const actionAlignHorizontallyCentered = register({ name: "alignHorizontallyCentered", perform: (elements, appState) => { - trackEvent(EVENT_ALIGN, "horizontally", "center"); return { appState, elements: alignSelectedElements(elements, appState, { diff --git a/src/actions/actionCanvas.tsx b/src/actions/actionCanvas.tsx index 567aeeafc..872874a5b 100644 --- a/src/actions/actionCanvas.tsx +++ b/src/actions/actionCanvas.tsx @@ -1,37 +1,25 @@ import React from "react"; -import { ColorPicker } from "../components/ColorPicker"; import { getDefaultAppState } from "../appState"; -import { trash, zoomIn, zoomOut, resetZoom } from "../components/icons"; +import { ColorPicker } from "../components/ColorPicker"; +import { resetZoom, trash, zoomIn, zoomOut } from "../components/icons"; import { ToolButton } from "../components/ToolButton"; -import { t } from "../i18n"; -import { getNormalizedZoom, getSelectedElements } from "../scene"; -import { getNonDeletedElements } from "../element"; -import { CODES, KEYS } from "../keys"; -import { getShortcutKey } from "../utils"; -import useIsMobile from "../is-mobile"; -import { register } from "./register"; +import { GRID_SIZE } from "../constants"; +import { getCommonBounds, getNonDeletedElements } from "../element"; import { newElementWith } from "../element/mutateElement"; import { ExcalidrawElement } from "../element/types"; -import { AppState, NormalizedZoomValue } from "../types"; -import { getCommonBounds } from "../element"; -import { getNewZoom } from "../scene/zoom"; +import { t } from "../i18n"; +import useIsMobile from "../is-mobile"; +import { CODES, KEYS } from "../keys"; +import { getNormalizedZoom, getSelectedElements } from "../scene"; import { centerScrollOn } from "../scene/scroll"; -import { EVENT_ACTION, EVENT_CHANGE, trackEvent } from "../analytics"; -import colors from "../colors"; -import { GRID_SIZE } from "../constants"; +import { getNewZoom } from "../scene/zoom"; +import { AppState, NormalizedZoomValue } from "../types"; +import { getShortcutKey } from "../utils"; +import { register } from "./register"; export const actionChangeViewBackgroundColor = register({ name: "changeViewBackgroundColor", perform: (_, appState, value) => { - if (value !== appState.viewBackgroundColor) { - trackEvent( - EVENT_CHANGE, - "canvas color", - colors.canvasBackground.includes(value) - ? `${value} (picker ${colors.canvasBackground.indexOf(value)})` - : value, - ); - } return { appState: { ...appState, viewBackgroundColor: value }, commitToHistory: true, @@ -54,7 +42,6 @@ export const actionChangeViewBackgroundColor = register({ export const actionClearCanvas = register({ name: "clearCanvas", perform: (elements, appState: AppState) => { - trackEvent(EVENT_ACTION, "clear canvas"); return { elements: elements.map((element) => newElementWith(element, { isDeleted: true }), @@ -68,6 +55,7 @@ export const actionClearCanvas = register({ gridSize: appState.gridSize || GRID_SIZE, shouldAddWatermark: appState.shouldAddWatermark, showStats: appState.showStats, + pasteDialog: appState.pasteDialog, }, commitToHistory: true, }; @@ -99,7 +87,6 @@ export const actionZoomIn = register({ { left: appState.offsetLeft, top: appState.offsetTop }, { x: appState.width / 2, y: appState.height / 2 }, ); - trackEvent(EVENT_ACTION, "zoom", "in", zoom.value * 100); return { appState: { ...appState, @@ -134,7 +121,6 @@ export const actionZoomOut = register({ { x: appState.width / 2, y: appState.height / 2 }, ); - trackEvent(EVENT_ACTION, "zoom", "out", zoom.value * 100); return { appState: { ...appState, @@ -162,7 +148,6 @@ export const actionZoomOut = register({ export const actionResetZoom = register({ name: "resetZoom", perform: (_elements, appState) => { - trackEvent(EVENT_ACTION, "zoom", "reset", 100); return { appState: { ...appState, @@ -235,12 +220,10 @@ const zoomToFitElements = ( left: appState.offsetLeft, top: appState.offsetTop, }); - const action = zoomToSelection ? "selection" : "fit"; const [x1, y1, x2, y2] = commonBounds; const centerX = (x1 + x2) / 2; const centerY = (y1 + y2) / 2; - trackEvent(EVENT_ACTION, "zoom", action, newZoom.value * 100); return { appState: { ...appState, diff --git a/src/actions/actionDistribute.tsx b/src/actions/actionDistribute.tsx index 15669dde0..fdd8267c1 100644 --- a/src/actions/actionDistribute.tsx +++ b/src/actions/actionDistribute.tsx @@ -1,19 +1,18 @@ import React from "react"; -import { CODES } from "../keys"; -import { t } from "../i18n"; -import { register } from "./register"; import { DistributeHorizontallyIcon, DistributeVerticallyIcon, } from "../components/icons"; -import { getSelectedElements, isSomeElementSelected } from "../scene"; -import { getElementMap, getNonDeletedElements } from "../element"; import { ToolButton } from "../components/ToolButton"; -import { ExcalidrawElement } from "../element/types"; -import { AppState } from "../types"; import { distributeElements, Distribution } from "../disitrubte"; +import { getElementMap, getNonDeletedElements } from "../element"; +import { ExcalidrawElement } from "../element/types"; +import { t } from "../i18n"; +import { CODES } from "../keys"; +import { getSelectedElements, isSomeElementSelected } from "../scene"; +import { AppState } from "../types"; import { getShortcutKey } from "../utils"; -import { EVENT_ALIGN, trackEvent } from "../analytics"; +import { register } from "./register"; const enableActionGroup = ( elements: readonly ExcalidrawElement[], @@ -40,7 +39,6 @@ const distributeSelectedElements = ( export const distributeHorizontally = register({ name: "distributeHorizontally", perform: (elements, appState) => { - trackEvent(EVENT_ALIGN, "distribute", "horizontally"); return { appState, elements: distributeSelectedElements(elements, appState, { @@ -69,7 +67,6 @@ export const distributeHorizontally = register({ export const distributeVertically = register({ name: "distributeVertically", perform: (elements, appState) => { - trackEvent(EVENT_ALIGN, "distribute", "vertically"); return { appState, elements: distributeSelectedElements(elements, appState, { diff --git a/src/actions/actionExport.tsx b/src/actions/actionExport.tsx index 2748ad3a4..e341d98fc 100644 --- a/src/actions/actionExport.tsx +++ b/src/actions/actionExport.tsx @@ -1,22 +1,20 @@ import React from "react"; -import { EVENT_CHANGE, EVENT_IO, trackEvent } from "../analytics"; -import { load, save, saveAs } from "../components/icons"; +import { trackEvent } from "../analytics"; +import { load, questionCircle, save, saveAs } from "../components/icons"; import { ProjectName } from "../components/ProjectName"; import { ToolButton } from "../components/ToolButton"; +import "../components/ToolIcon.scss"; import { Tooltip } from "../components/Tooltip"; -import { questionCircle } from "../components/icons"; import { loadFromJSON, saveAsJSON } from "../data"; import { t } from "../i18n"; import useIsMobile from "../is-mobile"; import { KEYS } from "../keys"; -import { muteFSAbortError } from "../utils"; import { register } from "./register"; -import "../components/ToolIcon.scss"; export const actionChangeProjectName = register({ name: "changeProjectName", perform: (_elements, appState, value) => { - trackEvent(EVENT_CHANGE, "title"); + trackEvent("change", "title"); return { appState: { ...appState, name: value }, commitToHistory: false }; }, PanelComponent: ({ appState, updateData }) => ( @@ -100,7 +98,6 @@ export const actionSaveScene = register({ perform: async (elements, appState, value) => { try { const { fileHandle } = await saveAsJSON(elements, appState); - trackEvent(EVENT_IO, "save"); return { commitToHistory: false, appState: { ...appState, fileHandle } }; } catch (error) { if (error?.name !== "AbortError") { @@ -131,7 +128,6 @@ export const actionSaveAsScene = register({ ...appState, fileHandle: null, }); - trackEvent(EVENT_IO, "save as"); return { commitToHistory: false, appState: { ...appState, fileHandle } }; } catch (error) { if (error?.name !== "AbortError") { @@ -159,18 +155,29 @@ export const actionSaveAsScene = register({ export const actionLoadScene = register({ name: "loadScene", - perform: ( - elements, - appState, - { elements: loadedElements, appState: loadedAppState, error }, - ) => ({ - elements: loadedElements, - appState: { - ...loadedAppState, - errorMessage: error, - }, - commitToHistory: true, - }), + perform: async (elements, appState) => { + try { + const { + elements: loadedElements, + appState: loadedAppState, + } = await loadFromJSON(appState); + return { + elements: loadedElements, + appState: loadedAppState, + commitToHistory: true, + }; + } catch (error) { + if (error?.name === "AbortError") { + return false; + } + return { + elements, + appState: { ...appState, errorMessage: error.message }, + commitToHistory: false, + }; + } + }, + keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.key === KEYS.O, PanelComponent: ({ updateData, appState }) => ( { - loadFromJSON(appState) - .then(({ elements, appState }) => { - updateData({ elements, appState }); - }) - .catch(muteFSAbortError) - .catch((error) => { - updateData({ error: error.message }); - }); - }} + onClick={updateData} /> ), }); diff --git a/src/actions/actionFinalize.tsx b/src/actions/actionFinalize.tsx index 67f4da882..2842615f9 100644 --- a/src/actions/actionFinalize.tsx +++ b/src/actions/actionFinalize.tsx @@ -118,11 +118,14 @@ export const actionFinalize = register({ ); } - if (!appState.elementLocked) { + if (!appState.elementLocked && appState.elementType !== "draw") { appState.selectedElementIds[multiPointElement.id] = true; } } - if (!appState.elementLocked || !multiPointElement) { + if ( + (!appState.elementLocked && appState.elementType !== "draw") || + !multiPointElement + ) { resetCursor(); } return { @@ -130,7 +133,8 @@ export const actionFinalize = register({ appState: { ...appState, elementType: - appState.elementLocked && multiPointElement + (appState.elementLocked || appState.elementType === "draw") && + multiPointElement ? appState.elementType : "selection", draggingElement: null, @@ -139,7 +143,9 @@ export const actionFinalize = register({ startBoundElement: null, suggestedBindings: [], selectedElementIds: - multiPointElement && !appState.elementLocked + multiPointElement && + !appState.elementLocked && + appState.elementType !== "draw" ? { ...appState.selectedElementIds, [multiPointElement.id]: true, diff --git a/src/actions/actionMenu.tsx b/src/actions/actionMenu.tsx index 7abe74c40..6ae29e519 100644 --- a/src/actions/actionMenu.tsx +++ b/src/actions/actionMenu.tsx @@ -7,7 +7,6 @@ import { register } from "./register"; import { allowFullScreen, exitFullScreen, isFullScreen } from "../utils"; import { CODES, KEYS } from "../keys"; import { HelpIcon } from "../components/HelpIcon"; -import { EVENT_DIALOG, trackEvent } from "../analytics"; export const actionToggleCanvasMenu = register({ name: "toggleCanvasMenu", @@ -72,7 +71,6 @@ export const actionFullScreen = register({ export const actionShortcuts = register({ name: "toggleShortcuts", perform: (_elements, appState) => { - trackEvent(EVENT_DIALOG, "shortcuts"); return { appState: { ...appState, diff --git a/src/actions/actionNavigate.tsx b/src/actions/actionNavigate.tsx index 02d981f75..ea9012f9d 100644 --- a/src/actions/actionNavigate.tsx +++ b/src/actions/actionNavigate.tsx @@ -1,16 +1,14 @@ import React from "react"; -import { Avatar } from "../components/Avatar"; -import { register } from "./register"; import { getClientColors, getClientInitials } from "../clients"; -import { Collaborator } from "../types"; +import { Avatar } from "../components/Avatar"; import { centerScrollOn } from "../scene/scroll"; -import { EVENT_SHARE, trackEvent } from "../analytics"; +import { Collaborator } from "../types"; +import { register } from "./register"; export const actionGoToCollaborator = register({ name: "goToCollaborator", perform: (_elements, appState, value) => { const point = value as Collaborator["pointer"]; - trackEvent(EVENT_SHARE, "go to collaborator"); if (!point) { return { appState, commitToHistory: false }; } diff --git a/src/actions/actionProperties.tsx b/src/actions/actionProperties.tsx index a818cf245..b6e39fa32 100644 --- a/src/actions/actionProperties.tsx +++ b/src/actions/actionProperties.tsx @@ -1,56 +1,53 @@ import React from "react"; -import { getLanguage } from "../i18n"; -import { - ExcalidrawElement, - ExcalidrawTextElement, - TextAlign, - FontFamily, - ExcalidrawLinearElement, - Arrowhead, -} from "../element/types"; -import { - getCommonAttributeOfSelectedElements, - isSomeElementSelected, - getTargetElements, - canChangeSharpness, - canHaveArrowheads, -} from "../scene"; -import { ButtonSelect } from "../components/ButtonSelect"; +import { AppState } from "../../src/types"; import { ButtonIconSelect } from "../components/ButtonIconSelect"; +import { ButtonSelect } from "../components/ButtonSelect"; +import { ColorPicker } from "../components/ColorPicker"; import { IconPicker } from "../components/IconPicker"; import { - isTextElement, - redrawTextBoundingBox, - getNonDeletedElements, -} from "../element"; -import { isLinearElement, isLinearElementType } from "../element/typeChecks"; -import { ColorPicker } from "../components/ColorPicker"; -import { AppState } from "../../src/types"; -import { t } from "../i18n"; -import { register } from "./register"; -import { newElementWith } from "../element/mutateElement"; -import { DEFAULT_FONT_SIZE, DEFAULT_FONT_FAMILY } from "../constants"; -import { randomInteger } from "../random"; -import { - FillHachureIcon, - FillCrossHatchIcon, - FillSolidIcon, - StrokeWidthIcon, - StrokeStyleSolidIcon, - StrokeStyleDashedIcon, - StrokeStyleDottedIcon, - EdgeSharpIcon, - EdgeRoundIcon, - SloppinessArchitectIcon, - SloppinessArtistIcon, - SloppinessCartoonistIcon, ArrowheadArrowIcon, ArrowheadBarIcon, ArrowheadDotIcon, ArrowheadNoneIcon, + EdgeRoundIcon, + EdgeSharpIcon, + FillCrossHatchIcon, + FillHachureIcon, + FillSolidIcon, + SloppinessArchitectIcon, + SloppinessArtistIcon, + SloppinessCartoonistIcon, + StrokeStyleDashedIcon, + StrokeStyleDottedIcon, + StrokeStyleSolidIcon, + StrokeWidthIcon, } from "../components/icons"; -import { EVENT_CHANGE, trackEvent } from "../analytics"; -import colors from "../colors"; +import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE } from "../constants"; +import { + getNonDeletedElements, + isTextElement, + redrawTextBoundingBox, +} from "../element"; +import { newElementWith } from "../element/mutateElement"; +import { isLinearElement, isLinearElementType } from "../element/typeChecks"; +import { + Arrowhead, + ExcalidrawElement, + ExcalidrawLinearElement, + ExcalidrawTextElement, + FontFamily, + TextAlign, +} from "../element/types"; +import { getLanguage, t } from "../i18n"; +import { randomInteger } from "../random"; +import { + canChangeSharpness, + canHaveArrowheads, + getCommonAttributeOfSelectedElements, + getTargetElements, + isSomeElementSelected, +} from "../scene"; +import { register } from "./register"; const changeProperty = ( elements: readonly ExcalidrawElement[], @@ -92,15 +89,6 @@ const getFormValue = function ( export const actionChangeStrokeColor = register({ name: "changeStrokeColor", perform: (elements, appState, value) => { - if (value !== appState.currentItemStrokeColor) { - trackEvent( - EVENT_CHANGE, - "stroke color", - colors.elementStroke.includes(value) - ? `${value} (picker ${colors.elementStroke.indexOf(value)})` - : value, - ); - } return { elements: changeProperty(elements, appState, (el) => newElementWith(el, { @@ -132,16 +120,6 @@ export const actionChangeStrokeColor = register({ export const actionChangeBackgroundColor = register({ name: "changeBackgroundColor", perform: (elements, appState, value) => { - if (value !== appState.currentItemBackgroundColor) { - trackEvent( - EVENT_CHANGE, - "background color", - colors.elementBackground.includes(value) - ? `${value} (picker ${colors.elementBackground.indexOf(value)})` - : value, - ); - } - return { elements: changeProperty(elements, appState, (el) => newElementWith(el, { @@ -173,7 +151,6 @@ export const actionChangeBackgroundColor = register({ export const actionChangeFillStyle = register({ name: "changeFillStyle", perform: (elements, appState, value) => { - trackEvent(EVENT_CHANGE, "fill", value); return { elements: changeProperty(elements, appState, (el) => newElementWith(el, { @@ -223,7 +200,6 @@ export const actionChangeFillStyle = register({ export const actionChangeStrokeWidth = register({ name: "changeStrokeWidth", perform: (elements, appState, value) => { - trackEvent(EVENT_CHANGE, "stroke", "width", value); return { elements: changeProperty(elements, appState, (el) => newElementWith(el, { @@ -286,7 +262,6 @@ export const actionChangeStrokeWidth = register({ export const actionChangeSloppiness = register({ name: "changeSloppiness", perform: (elements, appState, value) => { - trackEvent(EVENT_CHANGE, "stroke", "sloppiness", value); return { elements: changeProperty(elements, appState, (el) => newElementWith(el, { @@ -335,7 +310,6 @@ export const actionChangeSloppiness = register({ export const actionChangeStrokeStyle = register({ name: "changeStrokeStyle", perform: (elements, appState, value) => { - trackEvent(EVENT_CHANGE, "style", value); return { elements: changeProperty(elements, appState, (el) => newElementWith(el, { @@ -383,7 +357,6 @@ export const actionChangeStrokeStyle = register({ export const actionChangeOpacity = register({ name: "changeOpacity", perform: (elements, appState, value) => { - trackEvent(EVENT_CHANGE, "opacity", "value", value); return { elements: changeProperty(elements, appState, (el) => newElementWith(el, { @@ -580,7 +553,6 @@ export const actionChangeSharpness = register({ const shouldUpdateForLinearElements = targetElements.length ? targetElements.every(isLinearElement) : isLinearElementType(appState.elementType); - trackEvent(EVENT_CHANGE, "edge", value); return { elements: changeProperty(elements, appState, (el) => newElementWith(el, { @@ -642,12 +614,6 @@ export const actionChangeArrowhead = register({ return { elements: changeProperty(elements, appState, (el) => { if (isLinearElement(el)) { - trackEvent( - EVENT_CHANGE, - `arrowhead ${value.position}`, - value.type || "none", - ); - const { position, type } = value; if (position === "start") { diff --git a/src/actions/shortcuts.ts b/src/actions/shortcuts.ts index cab6526b0..e2fcf595a 100644 --- a/src/actions/shortcuts.ts +++ b/src/actions/shortcuts.ts @@ -20,6 +20,7 @@ export type ShortcutName = | "group" | "ungroup" | "gridMode" + | "zenMode" | "stats" | "addToLibrary"; @@ -52,6 +53,7 @@ const shortcutMap: Record = { group: [getShortcutKey("CtrlOrCmd+G")], ungroup: [getShortcutKey("CtrlOrCmd+Shift+G")], gridMode: [getShortcutKey("CtrlOrCmd+'")], + zenMode: [getShortcutKey("Alt+Z")], stats: [], addToLibrary: [], }; diff --git a/src/analytics.ts b/src/analytics.ts index 255862736..30a3887e3 100644 --- a/src/analytics.ts +++ b/src/analytics.ts @@ -1,18 +1,7 @@ -export const EVENT_ACTION = "action"; -export const EVENT_ALIGN = "align"; -export const EVENT_CHANGE = "change"; -export const EVENT_DIALOG = "dialog"; -export const EVENT_EXIT = "exit"; -export const EVENT_IO = "io"; -export const EVENT_LAYER = "layer"; -export const EVENT_LIBRARY = "library"; -export const EVENT_LOAD = "load"; -export const EVENT_SHAPE = "shape"; -export const EVENT_SHARE = "share"; -export const EVENT_MAGIC = "magic"; - export const trackEvent = - typeof window !== "undefined" && window.gtag + process.env.REACT_APP_GOOGLE_ANALYTICS_ID && + typeof window !== "undefined" && + window.gtag ? (category: string, name: string, label?: string, value?: number) => { window.gtag("event", name, { event_category: category, @@ -23,5 +12,6 @@ export const trackEvent = : typeof process !== "undefined" && process?.env?.JEST_WORKER_ID ? (category: string, name: string, label?: string, value?: number) => {} : (category: string, name: string, label?: string, value?: number) => { - console.info("Track Event", category, name, label, value); + // Uncomment the next line to track locally + // console.info("Track Event", category, name, label, value); }; diff --git a/src/appState.ts b/src/appState.ts index c5d4c3c43..676bb21e1 100644 --- a/src/appState.ts +++ b/src/appState.ts @@ -1,13 +1,13 @@ import oc from "open-color"; -import { AppState, FlooredNumber, NormalizedZoomValue } from "./types"; -import { getDateTime } from "./utils"; -import { t } from "./i18n"; import { - DEFAULT_FONT_SIZE, DEFAULT_FONT_FAMILY, + DEFAULT_FONT_SIZE, DEFAULT_TEXT_ALIGN, GRID_SIZE, } from "./constants"; +import { t } from "./i18n"; +import { AppState, FlooredNumber, NormalizedZoomValue } from "./types"; +import { getDateTime } from "./utils"; export const getDefaultAppState = (): Omit< AppState, @@ -15,67 +15,64 @@ export const getDefaultAppState = (): Omit< > => { return { appearance: "light", - isLoading: false, - errorMessage: null, + collaborators: new Map(), + currentChartType: "bar", + currentItemBackgroundColor: "transparent", + currentItemEndArrowhead: "arrow", + currentItemFillStyle: "hachure", + currentItemFontFamily: DEFAULT_FONT_FAMILY, + currentItemFontSize: DEFAULT_FONT_SIZE, + currentItemLinearStrokeSharpness: "round", + currentItemOpacity: 100, + currentItemRoughness: 1, + currentItemStartArrowhead: null, + currentItemStrokeColor: oc.black, + currentItemStrokeSharpness: "sharp", + currentItemStrokeStyle: "solid", + currentItemStrokeWidth: 1, + currentItemTextAlign: DEFAULT_TEXT_ALIGN, + cursorButton: "up", draggingElement: null, - resizingElement: null, - multiElement: null, editingElement: null, - startBoundElement: null, + editingGroupId: null, editingLinearElement: null, - elementType: "selection", elementLocked: false, + elementType: "selection", + errorMessage: null, exportBackground: true, exportEmbedScene: false, - shouldAddWatermark: false, - currentItemStrokeColor: oc.black, - currentItemBackgroundColor: "transparent", - currentItemFillStyle: "hachure", - currentItemStrokeWidth: 1, - currentItemStrokeStyle: "solid", - currentItemRoughness: 1, - currentItemOpacity: 100, - currentItemFontSize: DEFAULT_FONT_SIZE, - currentItemFontFamily: DEFAULT_FONT_FAMILY, - currentItemTextAlign: DEFAULT_TEXT_ALIGN, - currentItemStrokeSharpness: "sharp", - currentItemLinearStrokeSharpness: "round", - currentItemStartArrowhead: null, - currentItemEndArrowhead: "arrow", - viewBackgroundColor: oc.white, - scrollX: 0 as FlooredNumber, - scrollY: 0 as FlooredNumber, - cursorX: 0, - cursorY: 0, - cursorButton: "up", - scrolledOutside: false, - name: `${t("labels.untitled")}-${getDateTime()}`, + fileHandle: null, + gridSize: GRID_SIZE, + height: window.innerHeight, isBindingEnabled: true, + isLibraryOpen: false, + isLoading: false, isResizing: false, isRotating: false, - selectionElement: null, - zoom: { - value: 1 as NormalizedZoomValue, - translation: { x: 0, y: 0 }, - }, - openMenu: null, lastPointerDownWith: "mouse", - selectedElementIds: {}, + multiElement: null, + name: `${t("labels.untitled")}-${getDateTime()}`, + openMenu: null, + pasteDialog: { shown: false, data: null }, previousSelectedElementIds: {}, - shouldCacheIgnoreZoom: false, - showShortcutsDialog: false, - suggestedBindings: [], - zenModeEnabled: false, - gridSize: GRID_SIZE, - showGrid: false, - editingGroupId: null, + resizingElement: null, + scrolledOutside: false, + scrollX: 0 as FlooredNumber, + scrollY: 0 as FlooredNumber, + selectedElementIds: {}, selectedGroupIds: {}, - width: window.innerWidth, - height: window.innerHeight, - isLibraryOpen: false, - fileHandle: null, - collaborators: new Map(), + selectionElement: null, + shouldAddWatermark: false, + shouldCacheIgnoreZoom: false, + showGrid: false, + showShortcutsDialog: false, showStats: false, + startBoundElement: null, + suggestedBindings: [], + viewBackgroundColor: oc.white, + width: window.innerWidth, + zenModeEnabled: false, + zoom: { value: 1 as NormalizedZoomValue, translation: { x: 0, y: 0 } }, }; }; @@ -95,26 +92,25 @@ const APP_STATE_STORAGE_CONF = (< config: { [K in keyof T]: K extends keyof AppState ? T[K] : never }, ) => config)({ appearance: { browser: true, export: false }, + collaborators: { browser: false, export: false }, + currentChartType: { browser: true, export: false }, currentItemBackgroundColor: { browser: true, export: false }, + currentItemEndArrowhead: { browser: true, export: false }, currentItemFillStyle: { browser: true, export: false }, currentItemFontFamily: { browser: true, export: false }, currentItemFontSize: { browser: true, export: false }, + currentItemLinearStrokeSharpness: { browser: true, export: false }, currentItemOpacity: { browser: true, export: false }, currentItemRoughness: { browser: true, export: false }, + currentItemStartArrowhead: { browser: true, export: false }, currentItemStrokeColor: { browser: true, export: false }, + currentItemStrokeSharpness: { browser: true, export: false }, currentItemStrokeStyle: { browser: true, export: false }, currentItemStrokeWidth: { browser: true, export: false }, currentItemTextAlign: { browser: true, export: false }, - currentItemStrokeSharpness: { browser: true, export: false }, - currentItemLinearStrokeSharpness: { browser: true, export: false }, - currentItemStartArrowhead: { browser: true, export: false }, - currentItemEndArrowhead: { browser: true, export: false }, cursorButton: { browser: true, export: false }, - cursorX: { browser: true, export: false }, - cursorY: { browser: true, export: false }, draggingElement: { browser: false, export: false }, editingElement: { browser: false, export: false }, - startBoundElement: { browser: false, export: false }, editingGroupId: { browser: true, export: false }, editingLinearElement: { browser: false, export: false }, elementLocked: { browser: true, export: false }, @@ -122,6 +118,7 @@ const APP_STATE_STORAGE_CONF = (< errorMessage: { browser: false, export: false }, exportBackground: { browser: true, export: false }, exportEmbedScene: { browser: true, export: false }, + fileHandle: { browser: false, export: false }, gridSize: { browser: true, export: true }, showGrid: { browser: true, export: false }, height: { browser: false, export: false }, @@ -133,7 +130,10 @@ const APP_STATE_STORAGE_CONF = (< lastPointerDownWith: { browser: true, export: false }, multiElement: { browser: false, export: false }, name: { browser: true, export: false }, + offsetLeft: { browser: false, export: false }, + offsetTop: { browser: false, export: false }, openMenu: { browser: true, export: false }, + pasteDialog: { browser: false, export: false }, previousSelectedElementIds: { browser: true, export: false }, resizingElement: { browser: false, export: false }, scrolledOutside: { browser: true, export: false }, @@ -145,16 +145,13 @@ const APP_STATE_STORAGE_CONF = (< shouldAddWatermark: { browser: true, export: false }, shouldCacheIgnoreZoom: { browser: true, export: false }, showShortcutsDialog: { browser: false, export: false }, + showStats: { browser: true, export: false }, + startBoundElement: { browser: false, export: false }, suggestedBindings: { browser: false, export: false }, viewBackgroundColor: { browser: true, export: true }, width: { browser: false, export: false }, zenModeEnabled: { browser: true, export: false }, zoom: { browser: true, export: false }, - offsetTop: { browser: false, export: false }, - offsetLeft: { browser: false, export: false }, - fileHandle: { browser: false, export: false }, - collaborators: { browser: false, export: false }, - showStats: { browser: true, export: false }, }); const _clearAppStateForStorage = ( diff --git a/src/charts.ts b/src/charts.ts index 5e49e936e..3b2bbb38b 100644 --- a/src/charts.ts +++ b/src/charts.ts @@ -1,13 +1,16 @@ -import { EVENT_MAGIC, trackEvent } from "./analytics"; +import { trackEvent } from "./analytics"; import colors from "./colors"; -import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE } from "./constants"; -import { newElement, newTextElement, newLinearElement } from "./element"; -import { ExcalidrawElement } from "./element/types"; +import { DEFAULT_FONT_FAMILY, DEFAULT_FONT_SIZE, ENV } from "./constants"; +import { newElement, newLinearElement, newTextElement } from "./element"; +import { NonDeletedExcalidrawElement } from "./element/types"; import { randomId } from "./random"; +export type ChartElements = readonly NonDeletedExcalidrawElement[]; + const BAR_WIDTH = 32; const BAR_GAP = 12; const BAR_HEIGHT = 256; +const GRID_OPACITY = 50; export interface Spreadsheet { title: string | null; @@ -139,114 +142,48 @@ export const tryParseSpreadsheet = (text: string): ParseSpreadsheetResult => { return transposedResults; } } - return result; }; -// For the maths behind it https://excalidraw.com/#json=6320864370884608,O_5xfD-Agh32tytHpRJx1g -export const renderSpreadsheet = ( +const bgColors = colors.elementBackground.slice( + 2, + colors.elementBackground.length, +); + +// Put all the common properties here so when the whole chart is selected +// the properties dialog shows the correct selected values +const commonProps = { + fillStyle: "hachure", + fontFamily: DEFAULT_FONT_FAMILY, + fontSize: DEFAULT_FONT_SIZE, + opacity: 100, + roughness: 1, + strokeColor: colors.elementStroke[0], + strokeSharpness: "sharp", + strokeStyle: "solid", + strokeWidth: 1, + verticalAlign: "middle", +} as const; + +const getChartDimentions = (spreadsheet: Spreadsheet) => { + const chartWidth = + (BAR_WIDTH + BAR_GAP) * spreadsheet.values.length + BAR_GAP; + const chartHeight = BAR_HEIGHT + BAR_GAP * 2; + return { chartWidth, chartHeight }; +}; + +const chartXLabels = ( spreadsheet: Spreadsheet, x: number, y: number, -): ExcalidrawElement[] => { - const values = spreadsheet.values; - const max = Math.max(...values); - const chartHeight = BAR_HEIGHT + BAR_GAP * 2; - const chartWidth = (BAR_WIDTH + BAR_GAP) * values.length + BAR_GAP; - const maxColors = colors.elementBackground.length; - const bgColors = colors.elementBackground.slice(2, maxColors); - - // Put all the common properties here so when the whole chart is selected - // the properties dialog shows the correct selected values - const commonProps = { - backgroundColor: bgColors[Math.floor(Math.random() * bgColors.length)], - fillStyle: "hachure", - fontFamily: DEFAULT_FONT_FAMILY, - fontSize: DEFAULT_FONT_SIZE, - groupIds: [randomId()], - opacity: 100, - roughness: 1, - strokeColor: colors.elementStroke[0], - strokeSharpness: "sharp", - strokeStyle: "solid", - strokeWidth: 1, - verticalAlign: "middle", - } as const; - - const minYLabel = newTextElement({ - ...commonProps, - x: x - BAR_GAP, - y: y - BAR_GAP, - text: "0", - textAlign: "right", - }); - - const maxYLabel = newTextElement({ - ...commonProps, - x: x - BAR_GAP, - y: y - BAR_HEIGHT - minYLabel.height / 2, - text: max.toLocaleString(), - textAlign: "right", - }); - - const xAxisLine = newLinearElement({ - type: "line", - x, - y, - startArrowhead: null, - endArrowhead: null, - width: chartWidth, - points: [ - [0, 0], - [chartWidth, 0], - ], - ...commonProps, - }); - - const yAxisLine = newLinearElement({ - type: "line", - x, - y, - startArrowhead: null, - endArrowhead: null, - height: chartHeight, - points: [ - [0, 0], - [0, -chartHeight], - ], - ...commonProps, - }); - - const maxValueLine = newLinearElement({ - type: "line", - x, - y: y - BAR_HEIGHT - BAR_GAP, - startArrowhead: null, - endArrowhead: null, - ...commonProps, - strokeStyle: "dotted", - width: chartWidth, - points: [ - [0, 0], - [chartWidth, 0], - ], - }); - - const bars = values.map((value, index) => { - const barHeight = (value / max) * BAR_HEIGHT; - return newElement({ - ...commonProps, - type: "rectangle", - x: x + index * (BAR_WIDTH + BAR_GAP) + BAR_GAP, - y: y - barHeight - BAR_GAP, - width: BAR_WIDTH, - height: barHeight, - }); - }); - - const xLabels = + groupId: string, + backgroundColor: string, +): ChartElements => { + return ( spreadsheet.labels?.map((label, index) => { return newTextElement({ + groupIds: [groupId], + backgroundColor, ...commonProps, text: label.length > 8 ? `${label.slice(0, 5)}...` : label, x: x + index * (BAR_WIDTH + BAR_GAP) + BAR_GAP * 2, @@ -257,29 +194,288 @@ export const renderSpreadsheet = ( textAlign: "center", verticalAlign: "top", }); - }) || []; + }) || [] + ); +}; + +const chartYLabels = ( + spreadsheet: Spreadsheet, + x: number, + y: number, + groupId: string, + backgroundColor: string, +): ChartElements => { + const minYLabel = newTextElement({ + groupIds: [groupId], + backgroundColor, + ...commonProps, + x: x - BAR_GAP, + y: y - BAR_GAP, + text: "0", + textAlign: "right", + }); + + const maxYLabel = newTextElement({ + groupIds: [groupId], + backgroundColor, + ...commonProps, + x: x - BAR_GAP, + y: y - BAR_HEIGHT - minYLabel.height / 2, + text: Math.max(...spreadsheet.values).toLocaleString(), + textAlign: "right", + }); + + return [minYLabel, maxYLabel]; +}; + +const chartLines = ( + spreadsheet: Spreadsheet, + x: number, + y: number, + groupId: string, + backgroundColor: string, +): ChartElements => { + const { chartWidth, chartHeight } = getChartDimentions(spreadsheet); + const xLine = newLinearElement({ + backgroundColor, + groupIds: [groupId], + ...commonProps, + type: "line", + x, + y, + startArrowhead: null, + endArrowhead: null, + width: chartWidth, + points: [ + [0, 0], + [chartWidth, 0], + ], + }); + + const yLine = newLinearElement({ + backgroundColor, + groupIds: [groupId], + ...commonProps, + type: "line", + x, + y, + startArrowhead: null, + endArrowhead: null, + height: chartHeight, + points: [ + [0, 0], + [0, -chartHeight], + ], + }); + + const maxLine = newLinearElement({ + backgroundColor, + groupIds: [groupId], + ...commonProps, + type: "line", + x, + y: y - BAR_HEIGHT - BAR_GAP, + startArrowhead: null, + endArrowhead: null, + strokeStyle: "dotted", + width: chartWidth, + opacity: GRID_OPACITY, + points: [ + [0, 0], + [chartWidth, 0], + ], + }); + + return [xLine, yLine, maxLine]; +}; + +// For the maths behind it https://excalidraw.com/#json=6320864370884608,O_5xfD-Agh32tytHpRJx1g +const chartBaseElements = ( + spreadsheet: Spreadsheet, + x: number, + y: number, + groupId: string, + backgroundColor: string, + debug?: boolean, +): ChartElements => { + const { chartWidth, chartHeight } = getChartDimentions(spreadsheet); const title = spreadsheet.title ? newTextElement({ + backgroundColor, + groupIds: [groupId], ...commonProps, text: spreadsheet.title, x: x + chartWidth / 2, - y: y - BAR_HEIGHT - BAR_GAP * 2 - maxYLabel.height, + y: y - BAR_HEIGHT - BAR_GAP * 2 - DEFAULT_FONT_SIZE, strokeSharpness: "sharp", strokeStyle: "solid", textAlign: "center", }) : null; - trackEvent(EVENT_MAGIC, "chart", "bars", bars.length); + const debugRect = debug + ? newElement({ + backgroundColor, + groupIds: [groupId], + ...commonProps, + type: "rectangle", + x, + y: y - chartHeight, + width: chartWidth, + height: chartHeight, + strokeColor: colors.elementStroke[0], + fillStyle: "solid", + opacity: 6, + }) + : null; + return [ - title, - ...bars, - ...xLabels, - xAxisLine, - yAxisLine, - maxValueLine, - minYLabel, - maxYLabel, - ].filter((element) => element !== null) as ExcalidrawElement[]; + ...(debugRect ? [debugRect] : []), + ...(title ? [title] : []), + ...chartXLabels(spreadsheet, x, y, groupId, backgroundColor), + ...chartYLabels(spreadsheet, x, y, groupId, backgroundColor), + ...chartLines(spreadsheet, x, y, groupId, backgroundColor), + ]; +}; + +const chartTypeBar = ( + spreadsheet: Spreadsheet, + x: number, + y: number, +): ChartElements => { + const max = Math.max(...spreadsheet.values); + const groupId = randomId(); + const backgroundColor = bgColors[Math.floor(Math.random() * bgColors.length)]; + + const bars = spreadsheet.values.map((value, index) => { + const barHeight = (value / max) * BAR_HEIGHT; + return newElement({ + backgroundColor, + groupIds: [groupId], + ...commonProps, + type: "rectangle", + x: x + index * (BAR_WIDTH + BAR_GAP) + BAR_GAP, + y: y - barHeight - BAR_GAP, + width: BAR_WIDTH, + height: barHeight, + }); + }); + + return [ + ...bars, + ...chartBaseElements( + spreadsheet, + x, + y, + groupId, + backgroundColor, + process.env.NODE_ENV === ENV.DEVELOPMENT, + ), + ]; +}; + +const chartTypeLine = ( + spreadsheet: Spreadsheet, + x: number, + y: number, +): ChartElements => { + const max = Math.max(...spreadsheet.values); + const groupId = randomId(); + const backgroundColor = bgColors[Math.floor(Math.random() * bgColors.length)]; + + let index = 0; + const points = []; + for (const value of spreadsheet.values) { + const cx = index * (BAR_WIDTH + BAR_GAP); + const cy = -(value / max) * BAR_HEIGHT; + points.push([cx, cy]); + index++; + } + + const maxX = Math.max(...points.map((element) => element[0])); + const maxY = Math.max(...points.map((element) => element[1])); + const minX = Math.min(...points.map((element) => element[0])); + const minY = Math.min(...points.map((element) => element[1])); + + const line = newLinearElement({ + backgroundColor, + groupIds: [groupId], + ...commonProps, + type: "line", + x: x + BAR_GAP + BAR_WIDTH / 2, + y: y - BAR_GAP, + startArrowhead: null, + endArrowhead: null, + height: maxY - minY, + width: maxX - minX, + strokeWidth: 2, + points: points as any, + }); + + const dots = spreadsheet.values.map((value, index) => { + const cx = index * (BAR_WIDTH + BAR_GAP) + BAR_GAP / 2; + const cy = -(value / max) * BAR_HEIGHT + BAR_GAP / 2; + return newElement({ + backgroundColor, + groupIds: [groupId], + ...commonProps, + fillStyle: "solid", + strokeWidth: 2, + type: "ellipse", + x: x + cx + BAR_WIDTH / 2, + y: y + cy - BAR_GAP * 2, + width: BAR_GAP, + height: BAR_GAP, + }); + }); + + const lines = spreadsheet.values.map((value, index) => { + const cx = index * (BAR_WIDTH + BAR_GAP) + BAR_GAP / 2; + const cy = (value / max) * BAR_HEIGHT + BAR_GAP / 2 + BAR_GAP; + return newLinearElement({ + backgroundColor, + groupIds: [groupId], + ...commonProps, + type: "line", + x: x + cx + BAR_WIDTH / 2 + BAR_GAP / 2, + y: y - cy, + startArrowhead: null, + endArrowhead: null, + height: cy, + strokeStyle: "dotted", + opacity: GRID_OPACITY, + points: [ + [0, 0], + [0, cy], + ], + }); + }); + + return [ + ...chartBaseElements( + spreadsheet, + x, + y, + groupId, + backgroundColor, + process.env.NODE_ENV === ENV.DEVELOPMENT, + ), + line, + ...lines, + ...dots, + ]; +}; + +export const renderSpreadsheet = ( + chartType: string, + spreadsheet: Spreadsheet, + x: number, + y: number, +): ChartElements => { + trackEvent("magic", "chart", chartType, spreadsheet.values.length); + if (chartType === "line") { + return chartTypeLine(spreadsheet, x, y); + } + return chartTypeBar(spreadsheet, x, y); }; diff --git a/src/components/Actions.tsx b/src/components/Actions.tsx index ad1a0a45e..177fd61c2 100644 --- a/src/components/Actions.tsx +++ b/src/components/Actions.tsx @@ -1,23 +1,22 @@ import React from "react"; -import { AppState, Zoom } from "../types"; -import { ExcalidrawElement } from "../element/types"; import { ActionManager } from "../actions/manager"; +import { getNonDeletedElements } from "../element"; +import { ExcalidrawElement } from "../element/types"; +import { t } from "../i18n"; +import useIsMobile from "../is-mobile"; import { - hasBackground, - hasStroke, canChangeSharpness, - hasText, canHaveArrowheads, getTargetElements, + hasBackground, + hasStroke, + hasText, } from "../scene"; -import { t } from "../i18n"; import { SHAPES } from "../shapes"; -import { ToolButton } from "./ToolButton"; +import { AppState, Zoom } from "../types"; import { capitalizeString, isTransparent, setCursorForShape } from "../utils"; import Stack from "./Stack"; -import useIsMobile from "../is-mobile"; -import { getNonDeletedElements } from "../element"; -import { trackEvent, EVENT_SHAPE, EVENT_DIALOG } from "../analytics"; +import { ToolButton } from "./ToolButton"; export const SelectedShapeActions = ({ appState, @@ -181,7 +180,6 @@ export const ShapesSwitcher = ({ aria-keyshortcuts={shortcut} data-testid={value} onChange={() => { - trackEvent(EVENT_SHAPE, value, "toolbar"); setAppState({ elementType: value, multiElement: null, @@ -203,9 +201,6 @@ export const ShapesSwitcher = ({ title={`${capitalizeString(t("toolBar.library"))} — 9`} aria-label={capitalizeString(t("toolBar.library"))} onClick={() => { - if (!isLibraryOpen) { - trackEvent(EVENT_DIALOG, "library"); - } setAppState({ isLibraryOpen: !isLibraryOpen }); }} /> diff --git a/src/components/App.tsx b/src/components/App.tsx index cab3b4360..acc08fb05 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -1,180 +1,161 @@ +import { Point, simplify } from "points-on-curve"; import React from "react"; - -import rough from "roughjs/bin/rough"; import { RoughCanvas } from "roughjs/bin/canvas"; -import { simplify, Point } from "points-on-curve"; - -import { - newElement, - newTextElement, - duplicateElement, - isInvisiblySmallElement, - isTextElement, - textWysiwyg, - getCommonBounds, - getCursorForResizingElement, - getPerfectElementSize, - getNormalizedDimensions, - newLinearElement, - transformElements, - getElementWithTransformHandleType, - getResizeOffsetXY, - getResizeArrowDirection, - getTransformHandleTypeFromCoords, - isNonDeletedElement, - updateTextElement, - dragSelectedElements, - getDragOffsetXY, - dragNewElement, - hitTest, - isHittingElementBoundingBoxWithoutHittingElement, - getNonDeletedElements, -} from "../element"; -import { - getElementsWithinSelection, - isOverScrollBars, - getElementsAtPosition, - getElementContainingPosition, - getNormalizedZoom, - getSelectedElements, - isSomeElementSelected, - calculateScrollCenter, -} from "../scene"; -import { loadFromBlob, exportCanvas } from "../data"; - -import { renderScene } from "../renderer"; -import { - AppState, - GestureEvent, - Gesture, - ExcalidrawProps, - SceneData, -} from "../types"; -import { - ExcalidrawElement, - ExcalidrawTextElement, - NonDeleted, - ExcalidrawGenericElement, - ExcalidrawLinearElement, - ExcalidrawBindableElement, -} from "../element/types"; - -import { distance2d, isPathALoop, getGridPoint } from "../math"; - -import { - isWritableElement, - isInputLike, - isToolIcon, - debounce, - distance, - resetCursor, - viewportCoordsToSceneCoords, - sceneCoordsToViewportCoords, - setCursorForShape, - tupleToCoors, - ResolvablePromise, - resolvablePromise, - withBatchedUpdates, -} from "../utils"; -import { - KEYS, - isArrowKey, - getResizeCenterPointKey, - getResizeWithSidesSameLengthKey, - getRotateWithDiscreteAngleKey, - CODES, -} from "../keys"; - -import { findShapeByKey } from "../shapes"; -import { createHistory, SceneHistory } from "../history"; - -import ContextMenu from "./ContextMenu"; - -import { ActionManager } from "../actions/manager"; +import rough from "roughjs/bin/rough"; import "../actions"; +import { actionDeleteSelected, actionFinalize } from "../actions"; +import { createRedoAction, createUndoAction } from "../actions/actionHistory"; +import { ActionManager } from "../actions/manager"; import { actions } from "../actions/register"; - import { ActionResult } from "../actions/types"; +import { trackEvent } from "../analytics"; import { getDefaultAppState } from "../appState"; -import { t, getLanguage } from "../i18n"; - import { copyToClipboard, parseClipboard, probablySupportsClipboardBlob, probablySupportsClipboardWriteText, } from "../clipboard"; -import { normalizeScroll } from "../scene"; -import { getCenter, getDistance } from "../gesture"; -import { createUndoAction, createRedoAction } from "../actions/actionHistory"; - import { + APP_NAME, + CANVAS_ONLY_ACTIONS, CURSOR_TYPE, + DEFAULT_VERTICAL_ALIGN, + DRAGGING_THRESHOLD, ELEMENT_SHIFT_TRANSLATE_AMOUNT, ELEMENT_TRANSLATE_AMOUNT, - POINTER_BUTTON, - DRAGGING_THRESHOLD, - TEXT_TO_CENTER_SNAP_THRESHOLD, - LINE_CONFIRM_THRESHOLD, - EVENT, ENV, - CANVAS_ONLY_ACTIONS, - DEFAULT_VERTICAL_ALIGN, + EVENT, + LINE_CONFIRM_THRESHOLD, MIME_TYPES, + POINTER_BUTTON, TAP_TWICE_TIMEOUT, + TEXT_TO_CENTER_SNAP_THRESHOLD, TOUCH_CTX_MENU_TIMEOUT, - APP_NAME, } from "../constants"; - -import LayerUI from "./LayerUI"; -import { ScrollBars, SceneState } from "../scene/types"; -import { mutateElement } from "../element/mutateElement"; -import { invalidateShapeForElement } from "../renderer/renderElement"; -import { - isLinearElement, - isLinearElementType, - isBindingElement, - isBindingElementType, -} from "../element/typeChecks"; -import { actionFinalize, actionDeleteSelected } from "../actions"; - -import { LinearElementEditor } from "../element/linearElementEditor"; -import { - getSelectedGroupIds, - isSelectedViaGroup, - selectGroupsForSelectedElements, - isElementInGroup, - getSelectedGroupIdForElement, - getElementsInGroup, - editGroupForSelectedElement, -} from "../groups"; -import { Library } from "../data/library"; -import Scene from "../scene/Scene"; -import { - getHoveredElementForBinding, - maybeBindLinearElement, - getEligibleElementsForBinding, - bindOrUnbindSelectedElements, - unbindLinearElements, - fixBindingsAfterDuplication, - fixBindingsAfterDeletion, - isLinearElementSimpleAndAlreadyBound, - isBindingEnabled, - updateBoundElements, - shouldEnableBindingForPointerEvent, -} from "../element/binding"; -import { MaybeTransformHandleType } from "../element/transformHandles"; -import { deepCopyElement } from "../element/newElement"; -import { renderSpreadsheet } from "../charts"; +import { exportCanvas, loadFromBlob } from "../data"; import { isValidLibrary } from "../data/json"; -import { getNewZoom } from "../scene/zoom"; +import { Library } from "../data/library"; import { restore } from "../data/restore"; import { - EVENT_DIALOG, - EVENT_LIBRARY, - EVENT_SHAPE, - trackEvent, -} from "../analytics"; + dragNewElement, + dragSelectedElements, + duplicateElement, + getCommonBounds, + getCursorForResizingElement, + getDragOffsetXY, + getElementWithTransformHandleType, + getNonDeletedElements, + getNormalizedDimensions, + getPerfectElementSize, + getResizeArrowDirection, + getResizeOffsetXY, + getTransformHandleTypeFromCoords, + hitTest, + isHittingElementBoundingBoxWithoutHittingElement, + isInvisiblySmallElement, + isNonDeletedElement, + isTextElement, + newElement, + newLinearElement, + newTextElement, + textWysiwyg, + transformElements, + updateTextElement, +} from "../element"; +import { + bindOrUnbindSelectedElements, + fixBindingsAfterDeletion, + fixBindingsAfterDuplication, + getEligibleElementsForBinding, + getHoveredElementForBinding, + isBindingEnabled, + isLinearElementSimpleAndAlreadyBound, + maybeBindLinearElement, + shouldEnableBindingForPointerEvent, + unbindLinearElements, + updateBoundElements, +} from "../element/binding"; +import { LinearElementEditor } from "../element/linearElementEditor"; +import { mutateElement } from "../element/mutateElement"; +import { deepCopyElement } from "../element/newElement"; +import { MaybeTransformHandleType } from "../element/transformHandles"; +import { + isBindingElement, + isBindingElementType, + isLinearElement, + isLinearElementType, +} from "../element/typeChecks"; +import { + ExcalidrawBindableElement, + ExcalidrawElement, + ExcalidrawGenericElement, + ExcalidrawLinearElement, + ExcalidrawTextElement, + NonDeleted, +} from "../element/types"; +import { getCenter, getDistance } from "../gesture"; +import { + editGroupForSelectedElement, + getElementsInGroup, + getSelectedGroupIdForElement, + getSelectedGroupIds, + isElementInGroup, + isSelectedViaGroup, + selectGroupsForSelectedElements, +} from "../groups"; +import { createHistory, SceneHistory } from "../history"; +import { defaultLang, getLanguage, languages, setLanguage, t } from "../i18n"; +import { + CODES, + getResizeCenterPointKey, + getResizeWithSidesSameLengthKey, + getRotateWithDiscreteAngleKey, + isArrowKey, + KEYS, +} from "../keys"; +import { distance2d, getGridPoint, isPathALoop } from "../math"; +import { renderScene } from "../renderer"; +import { invalidateShapeForElement } from "../renderer/renderElement"; +import { + calculateScrollCenter, + getElementContainingPosition, + getElementsAtPosition, + getElementsWithinSelection, + getNormalizedZoom, + getSelectedElements, + isOverScrollBars, + isSomeElementSelected, + normalizeScroll, +} from "../scene"; +import Scene from "../scene/Scene"; +import { SceneState, ScrollBars } from "../scene/types"; +import { getNewZoom } from "../scene/zoom"; +import { findShapeByKey } from "../shapes"; +import { + AppState, + ExcalidrawProps, + Gesture, + GestureEvent, + SceneData, +} from "../types"; +import { + debounce, + distance, + isInputLike, + isToolIcon, + isWritableElement, + resetCursor, + ResolvablePromise, + resolvablePromise, + sceneCoordsToViewportCoords, + setCursorForShape, + tupleToCoors, + viewportCoordsToSceneCoords, + withBatchedUpdates, +} from "../utils"; +import ContextMenu from "./ContextMenu"; +import LayerUI from "./LayerUI"; import { Stats } from "./Stats"; const { history } = createHistory(); @@ -345,7 +326,7 @@ class App extends React.Component { offsetLeft, } = this.state; - const { onCollabButtonClick, onExportToBackend } = this.props; + const { onCollabButtonClick, onExportToBackend, renderFooter } = this.props; const canvasScale = window.devicePixelRatio; const canvasWidth = canvasDOMWidth * canvasScale; @@ -373,7 +354,7 @@ class App extends React.Component { elements={this.scene.getElements()} onCollabButtonClick={onCollabButtonClick} onLockToggle={this.toggleLock} - onInsertShape={(elements) => + onInsertElements={(elements) => this.addElementsFromPasteOrLibrary( elements, DEFAULT_PASTE_X, @@ -382,9 +363,10 @@ class App extends React.Component { } zenModeEnabled={zenModeEnabled} toggleZenMode={this.toggleZenMode} - lng={getLanguage().lng} + langCode={getLanguage().code} isCollaborating={this.props.isCollaborating || false} onExportToBackend={onExportToBackend} + renderCustomFooter={renderFooter} /> {this.state.showStats && ( { ) ) { await Library.importLibrary(blob); - trackEvent(EVENT_LIBRARY, "import"); this.setState({ isLibraryOpen: true, }); @@ -752,6 +733,10 @@ class App extends React.Component { } componentDidUpdate(prevProps: ExcalidrawProps, prevState: AppState) { + if (prevProps.langCode !== this.props.langCode) { + this.updateLanguage(); + } + if ( prevProps.width !== this.props.width || prevProps.height !== this.props.height || @@ -875,7 +860,16 @@ class App extends React.Component { history.record(this.state, this.scene.getElementsIncludingDeleted()); - this.props.onChange?.(this.scene.getElementsIncludingDeleted(), this.state); + // Do not notify consumers if we're still loading the scene. Among other + // potential issues, this fixes a case where the tab isn't focused during + // init, which would trigger onChange with empty elements, which would then + // override whatever is in localStorage currently. + if (!this.state.isLoading) { + this.props.onChange?.( + this.scene.getElementsIncludingDeleted(), + this.state, + ); + } } // Copy/paste @@ -1004,9 +998,12 @@ class App extends React.Component { if (data.errorMessage) { this.setState({ errorMessage: data.errorMessage }); } else if (data.spreadsheet) { - this.addElementsFromPasteOrLibrary( - renderSpreadsheet(data.spreadsheet, cursorX, cursorY), - ); + this.setState({ + pasteDialog: { + data: data.spreadsheet, + shown: true, + }, + }); } else if (data.elements) { this.addElementsFromPasteOrLibrary(data.elements); } else if (data.text) { @@ -1136,7 +1133,6 @@ class App extends React.Component { toggleLock = () => { this.setState((prevState) => { - trackEvent(EVENT_SHAPE, "lock", !prevState.elementLocked ? "on" : "off"); return { elementLocked: !prevState.elementLocked, elementType: prevState.elementLocked @@ -1160,7 +1156,7 @@ class App extends React.Component { toggleStats = () => { if (!this.state.showStats) { - trackEvent(EVENT_DIALOG, "stats"); + trackEvent("dialog", "stats"); } this.setState({ showStats: !this.state.showStats, @@ -1272,9 +1268,6 @@ class App extends React.Component { } if (event.code === CODES.NINE) { - if (!this.state.isLibraryOpen) { - trackEvent(EVENT_DIALOG, "library"); - } this.setState({ isLibraryOpen: !this.state.isLibraryOpen }); } @@ -1359,7 +1352,6 @@ class App extends React.Component { ) { const shape = findShapeByKey(event.key); if (shape) { - trackEvent(EVENT_SHAPE, shape, "shortcut"); this.selectShapeTool(shape); } else if (event.key === KEYS.Q) { this.toggleLock(); @@ -1743,7 +1735,6 @@ class App extends React.Component { resetCursor(); if (!event[KEYS.CTRL_OR_CMD]) { - trackEvent(EVENT_SHAPE, "text", "double-click"); this.startTextEditing({ sceneX, sceneY, @@ -2473,8 +2464,7 @@ class App extends React.Component { // otherwise, it will trigger selection based on current // state of the box if (!this.state.selectedElementIds[hitElement.id]) { - // if we are currently editing a group, treat all selections outside of the group - // as exiting editing mode. + // if we are currently editing a group, exiting editing mode and deselect the group. if ( this.state.editingGroupId && !isElementInGroup(hitElement, this.state.editingGroupId) @@ -2484,7 +2474,6 @@ class App extends React.Component { selectedGroupIds: {}, editingGroupId: null, }); - return true; } // Add hit element to selection. At this point if we're not holding @@ -3156,7 +3145,7 @@ class App extends React.Component { ); } this.setState({ suggestedBindings: [], startBoundElement: null }); - if (!elementLocked) { + if (!elementLocked && elementType !== "draw") { resetCursor(); this.setState((prevState) => ({ draggingElement: null, @@ -3303,7 +3292,7 @@ class App extends React.Component { return; } - if (!elementLocked && draggingElement) { + if (!elementLocked && elementType !== "draw" && draggingElement) { this.setState((prevState) => ({ selectedElementIds: { ...prevState.selectedElementIds, @@ -3327,7 +3316,7 @@ class App extends React.Component { ); } - if (!elementLocked) { + if (!elementLocked && elementType !== "draw") { resetCursor(); this.setState({ draggingElement: null, @@ -3667,6 +3656,12 @@ class App extends React.Component { label: t("labels.gridMode"), action: this.toggleGridMode, }, + { + checked: this.state.zenModeEnabled, + shortcutName: "zenMode", + label: t("buttons.zenMode"), + action: this.toggleZenMode, + }, { checked: this.state.showStats, shortcutName: "stats", @@ -3871,6 +3866,14 @@ class App extends React.Component { offsetTop: typeof offsets?.offsetTop === "number" ? offsets.offsetTop : 0, }; } + + private async updateLanguage() { + const currentLang = + languages.find((lang) => lang.code === this.props.langCode) || + defaultLang; + await setLanguage(currentLang); + this.setAppState({}); + } } // ----------------------------------------------------------------------------- diff --git a/src/components/BackgroundPickerAndDarkModeToggle.tsx b/src/components/BackgroundPickerAndDarkModeToggle.tsx index e87ff08a9..f2eba1315 100644 --- a/src/components/BackgroundPickerAndDarkModeToggle.tsx +++ b/src/components/BackgroundPickerAndDarkModeToggle.tsx @@ -1,6 +1,5 @@ import React from "react"; import { ActionManager } from "../actions/manager"; -import { EVENT_CHANGE, trackEvent } from "../analytics"; import { AppState } from "../types"; import { DarkModeToggle } from "./DarkModeToggle"; @@ -19,8 +18,6 @@ export const BackgroundPickerAndDarkModeToggle = ({ { - // TODO: track the theme on the first load too - trackEvent(EVENT_CHANGE, "theme", appearance); setAppState({ appearance }); }} /> diff --git a/src/components/CollabButton.tsx b/src/components/CollabButton.tsx index 297b56391..a046041da 100644 --- a/src/components/CollabButton.tsx +++ b/src/components/CollabButton.tsx @@ -6,7 +6,6 @@ import useIsMobile from "../is-mobile"; import { users } from "./icons"; import "./CollabButton.scss"; -import { EVENT_DIALOG, trackEvent } from "../analytics"; const CollabButton = ({ isCollaborating, @@ -23,10 +22,7 @@ const CollabButton = ({ className={clsx("CollabButton", { "is-collaborating": isCollaborating, })} - onClick={() => { - trackEvent(EVENT_DIALOG, "collaboration"); - onClick(); - }} + onClick={onClick} icon={users} type="button" title={t("buttons.roomDialog")} diff --git a/src/components/ColorPicker.scss b/src/components/ColorPicker.scss index 86b0d9328..23a6aac82 100644 --- a/src/components/ColorPicker.scss +++ b/src/components/ColorPicker.scss @@ -218,7 +218,7 @@ left: 2px; } - @media #{$media-query} { + @media #{$is-mobile-query} { display: none; } } diff --git a/src/components/ContextMenu.scss b/src/components/ContextMenu.scss index f2acaaad3..fe8059e09 100644 --- a/src/components/ContextMenu.scss +++ b/src/components/ContextMenu.scss @@ -1,4 +1,4 @@ -@import "open-color/open-color.scss"; +@import "../css/_variables"; .excalidraw { .context-menu { @@ -42,16 +42,16 @@ } &.dangerous { - div:nth-child(1) { + .context-menu-option__label { color: $oc-red-7; } } - div:nth-child(1) { + .context-menu-option__label { justify-self: start; margin-inline-end: 20px; } - div:nth-child(2) { + .context-menu-option__shortcut { justify-self: end; opacity: 0.6; font-size: 0.7rem; @@ -63,7 +63,7 @@ background-color: var(--select-highlight-color); &.dangerous { - div:nth-child(1) { + .context-menu-option__label { color: var(--popup-background-color); } background-color: $oc-red-6; @@ -73,4 +73,18 @@ .context-menu-option:focus { z-index: 1; } + + @media #{$is-mobile-query} { + .context-menu-option { + display: block; + + .context-menu-option__label { + margin-inline-end: 0; + } + + .context-menu-option__shortcut { + display: none; + } + } + } } diff --git a/src/components/ContextMenu.tsx b/src/components/ContextMenu.tsx index 390673821..27d14d880 100644 --- a/src/components/ContextMenu.tsx +++ b/src/components/ContextMenu.tsx @@ -51,8 +51,8 @@ const ContextMenu = ({ options, onCloseRequest, top, left }: Props) => { ${checked ? "checkmark" : ""}`} onClick={action} > -
{label}
-
+
{label}
+
{shortcutName ? getShortcutFromShortcutName(shortcutName) : ""} diff --git a/src/components/Dialog.scss b/src/components/Dialog.scss index 5c94a9069..3586c1cd2 100644 --- a/src/components/Dialog.scss +++ b/src/components/Dialog.scss @@ -7,6 +7,9 @@ margin-top: 0; grid-template-columns: 1fr calc(var(--space-factor) * 7); grid-gap: var(--metric); + padding: calc(var(--space-factor) * 2); + text-align: center; + font-variant: small-caps; } .Dialog__titleContent { @@ -18,7 +21,11 @@ margin: 0; } - @media #{$media-query} { + .Dialog__content { + padding: 0 16px 16px; + } + + @media #{$is-mobile-query} { .Dialog { --metric: calc(var(--space-factor) * 4); --inset-left: #{"max(var(--metric), var(--sal))"}; @@ -30,13 +37,8 @@ var(--space-factor) * 7 ); position: sticky; - top: calc(-1 * var(--metric)); - margin: calc(-1 * var(--inset-right)); - margin-top: calc(-1 * var(--metric)); - margin-bottom: var(--metric); + top: 0; padding: calc(var(--space-factor) * 2); - padding-left: var(--inset-left); - padding-right: var(--inset-right); background: var(--bg-color-island); font-size: 1.25em; diff --git a/src/components/Dialog.tsx b/src/components/Dialog.tsx index f1b83b4ea..aa2ef7c01 100644 --- a/src/components/Dialog.tsx +++ b/src/components/Dialog.tsx @@ -1,13 +1,12 @@ -import React, { useCallback, useEffect, useState } from "react"; import clsx from "clsx"; -import { Modal } from "./Modal"; -import { Island } from "./Island"; +import React, { useCallback, useEffect, useState } from "react"; import { t } from "../i18n"; import useIsMobile from "../is-mobile"; -import { back, close } from "./icons"; import { KEYS } from "../keys"; - import "./Dialog.scss"; +import { back, close } from "./icons"; +import { Island } from "./Island"; +import { Modal } from "./Modal"; const useRefState = () => { const [refValue, setRefValue] = useState(null); @@ -20,9 +19,10 @@ const useRefState = () => { export const Dialog = (props: { children: React.ReactNode; className?: string; - maxWidth?: number; + small?: boolean; onCloseRequest(): void; title: React.ReactNode; + autofocus?: boolean; }) => { const [islandNode, setIslandNode] = useRefState(); @@ -33,7 +33,7 @@ export const Dialog = (props: { const focusableElements = queryFocusableElements(islandNode); - if (focusableElements.length > 0) { + if (focusableElements.length > 0 && props.autofocus !== false) { // If there's an element other than close, focus it. (focusableElements[1] || focusableElements[0]).focus(); } @@ -62,7 +62,7 @@ export const Dialog = (props: { islandNode.addEventListener("keydown", handleKeyDown); return () => islandNode.removeEventListener("keydown", handleKeyDown); - }, [islandNode]); + }, [islandNode, props.autofocus]); const queryFocusableElements = (node: HTMLElement) => { const focusableElements = node.querySelectorAll( @@ -76,11 +76,11 @@ export const Dialog = (props: { - -

+ +

{props.title} -

- {props.children} +

+
{props.children}
); diff --git a/src/components/ErrorDialog.tsx b/src/components/ErrorDialog.tsx index f10c71897..fbd8e48cf 100644 --- a/src/components/ErrorDialog.tsx +++ b/src/components/ErrorDialog.tsx @@ -24,7 +24,7 @@ export const ErrorDialog = ({ <> {modalIsShown && ( diff --git a/src/components/ExportDialog.scss b/src/components/ExportDialog.scss index 9a479d58f..3086d72b1 100644 --- a/src/components/ExportDialog.scss +++ b/src/components/ExportDialog.scss @@ -37,7 +37,7 @@ } } - @media (max-width: 550px) { + @media #{$is-mobile-query} { .ExportDialog { display: flex; flex-direction: column; @@ -51,9 +51,7 @@ .ExportDialog__actions > * { margin-bottom: calc(var(--space-factor) * 3); } - } - @media #{$media-query} { .ExportDialog__preview canvas { max-height: 30vh; } diff --git a/src/components/ExportDialog.tsx b/src/components/ExportDialog.tsx index 013bbed33..2df04aa7d 100644 --- a/src/components/ExportDialog.tsx +++ b/src/components/ExportDialog.tsx @@ -1,7 +1,6 @@ import React, { useEffect, useRef, useState } from "react"; import { render, unmountComponentAtNode } from "react-dom"; import { ActionsManagerInterface } from "../actions/types"; -import { EVENT_DIALOG, trackEvent } from "../analytics"; import { probablySupportsClipboardBlob } from "../clipboard"; import { canvasToBlob } from "../data/blob"; import { NonDeletedExcalidrawElement } from "../element/types"; @@ -251,7 +250,6 @@ export const ExportDialog = ({ <> { - trackEvent(EVENT_DIALOG, "export"); setModalIsShown(true); }} icon={exportFile} @@ -262,11 +260,7 @@ export const ExportDialog = ({ ref={triggerButton} /> {modalIsShown && ( - + { - trackEvent(EVENT_EXIT, "github"); - }} > span { diff --git a/src/components/IconPicker.scss b/src/components/IconPicker.scss index 9521e7eda..ced5c5c23 100644 --- a/src/components/IconPicker.scss +++ b/src/components/IconPicker.scss @@ -102,6 +102,7 @@ position: absolute; bottom: 2px; font-size: 0.7em; + color: var(--keybinding-color); :root[dir="ltr"] & { right: 2px; @@ -110,7 +111,7 @@ :root[dir="rtl"] & { left: 2px; } - @media #{$media-query} { + @media #{$is-mobile-query} { display: none; } } diff --git a/src/components/InitializeApp.tsx b/src/components/InitializeApp.tsx index 091f726d7..ae0bea036 100644 --- a/src/components/InitializeApp.tsx +++ b/src/components/InitializeApp.tsx @@ -1,18 +1,29 @@ import React from "react"; import { LoadingMessage } from "./LoadingMessage"; -import { setLanguageFirstTime } from "../i18n"; +import { + defaultLang, + Language, + languages, + setLanguageFirstTime, +} from "../i18n"; -export class InitializeApp extends React.Component< - any, - { isLoading: boolean } -> { +interface Props { + langCode: Language["code"]; +} +interface State { + isLoading: boolean; +} +export class InitializeApp extends React.Component { public state: { isLoading: boolean } = { isLoading: true, }; async componentDidMount() { - await setLanguageFirstTime(); + const currentLang = + languages.find((lang) => lang.code === this.props.langCode) || + defaultLang; + await setLanguageFirstTime(currentLang); this.setState({ isLoading: false, }); diff --git a/src/components/Island.scss b/src/components/Island.scss index 713910aca..faac18d68 100644 --- a/src/components/Island.scss +++ b/src/components/Island.scss @@ -4,7 +4,7 @@ background-color: var(--bg-color-island); backdrop-filter: saturate(100%) blur(10px); box-shadow: var(--shadow-island); - border-radius: var(--border-radius-m); + border-radius: 4px; padding: calc(var(--padding) * var(--space-factor)); position: relative; transition: box-shadow 0.5s ease-in-out; diff --git a/src/components/LanguageList.tsx b/src/components/LanguageList.tsx deleted file mode 100644 index 79852154b..000000000 --- a/src/components/LanguageList.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React from "react"; -import clsx from "clsx"; -import * as i18n from "../i18n"; - -export const LanguageList = ({ - onChange, - languages = i18n.languages, - currentLanguage = i18n.getLanguage().lng, - floating, -}: { - languages?: { lng: string; label: string }[]; - onChange: (value: string) => void; - currentLanguage?: string; - floating?: boolean; -}) => ( - - - -); diff --git a/src/components/LayerUI.scss b/src/components/LayerUI.scss index e4aa90298..494d3ba22 100644 --- a/src/components/LayerUI.scss +++ b/src/components/LayerUI.scss @@ -7,11 +7,23 @@ align-items: center; justify-content: center; - .browse-libraries { - position: absolute; - right: 12px; - top: 16px; - white-space: nowrap; + .layer-ui__library-header { + display: flex; + align-items: center; + width: 100%; + margin: 2px 0; + + button { + // 2px from the left to account for focus border of left-most button + margin: 0 2px; + } + + a { + margin-left: auto; + // 17px for scrollbar (needed for overlay scrollbars on Big Sur?) + 1px extra + padding-right: 18px; + white-space: nowrap; + } } } diff --git a/src/components/LayerUI.tsx b/src/components/LayerUI.tsx index 6e4ebbebc..fbd5fdee0 100644 --- a/src/components/LayerUI.tsx +++ b/src/components/LayerUI.tsx @@ -1,56 +1,46 @@ +import clsx from "clsx"; import React, { + RefObject, + useCallback, + useEffect, useRef, useState, - RefObject, - useEffect, - useCallback, } from "react"; -import { showSelectedShapeActions } from "../element"; -import { calculateScrollCenter, getSelectedElements } from "../scene"; -import { exportCanvas } from "../data"; - -import { AppState, LibraryItems, LibraryItem } from "../types"; -import { NonDeletedExcalidrawElement } from "../element/types"; - import { ActionManager } from "../actions/manager"; -import { Island } from "./Island"; -import Stack from "./Stack"; -import { FixedSideContainer } from "./FixedSideContainer"; -import { UserList } from "./UserList"; -import { LockIcon } from "./LockIcon"; -import { ExportDialog, ExportCB } from "./ExportDialog"; -import { LanguageList } from "./LanguageList"; -import { t, languages, setLanguage } from "../i18n"; -import { HintViewer } from "./HintViewer"; +import { CLASSES } from "../constants"; +import { exportCanvas } from "../data"; +import { importLibraryFromJSON, saveLibraryAsJSON } from "../data/json"; +import { Library } from "../data/library"; +import { showSelectedShapeActions } from "../element"; +import { NonDeletedExcalidrawElement } from "../element/types"; +import { Language, t } from "../i18n"; import useIsMobile from "../is-mobile"; - +import { calculateScrollCenter, getSelectedElements } from "../scene"; import { ExportType } from "../scene/types"; -import { MobileMenu } from "./MobileMenu"; -import { ZoomActions, SelectedShapeActions, ShapesSwitcher } from "./Actions"; -import { Section } from "./Section"; +import { AppState, LibraryItem, LibraryItems } from "../types"; +import { muteFSAbortError } from "../utils"; +import { SelectedShapeActions, ShapesSwitcher, ZoomActions } from "./Actions"; +import { BackgroundPickerAndDarkModeToggle } from "./BackgroundPickerAndDarkModeToggle"; import CollabButton from "./CollabButton"; import { ErrorDialog } from "./ErrorDialog"; -import { ShortcutsDialog } from "./ShortcutsDialog"; -import { LoadingMessage } from "./LoadingMessage"; -import { CLASSES } from "../constants"; -import { shield, exportFile, load } from "./icons"; +import { ExportCB, ExportDialog } from "./ExportDialog"; +import { FixedSideContainer } from "./FixedSideContainer"; import { GitHubCorner } from "./GitHubCorner"; -import { Tooltip } from "./Tooltip"; - +import { HintViewer } from "./HintViewer"; +import { exportFile, load, shield } from "./icons"; +import { Island } from "./Island"; import "./LayerUI.scss"; import { LibraryUnit } from "./LibraryUnit"; +import { LoadingMessage } from "./LoadingMessage"; +import { LockIcon } from "./LockIcon"; +import { MobileMenu } from "./MobileMenu"; +import { PasteChartDialog } from "./PasteChartDialog"; +import { Section } from "./Section"; +import { ShortcutsDialog } from "./ShortcutsDialog"; +import Stack from "./Stack"; import { ToolButton } from "./ToolButton"; -import { saveLibraryAsJSON, importLibraryFromJSON } from "../data/json"; -import { muteFSAbortError } from "../utils"; -import { BackgroundPickerAndDarkModeToggle } from "./BackgroundPickerAndDarkModeToggle"; -import clsx from "clsx"; -import { Library } from "../data/library"; -import { - EVENT_ACTION, - EVENT_EXIT, - EVENT_LIBRARY, - trackEvent, -} from "../analytics"; +import { Tooltip } from "./Tooltip"; +import { UserList } from "./UserList"; interface LayerUIProps { actionManager: ActionManager; @@ -60,16 +50,17 @@ interface LayerUIProps { elements: readonly NonDeletedExcalidrawElement[]; onCollabButtonClick?: () => void; onLockToggle: () => void; - onInsertShape: (elements: LibraryItem) => void; + onInsertElements: (elements: readonly NonDeletedExcalidrawElement[]) => void; zenModeEnabled: boolean; toggleZenMode: () => void; - lng: string; + langCode: Language["code"]; isCollaborating: boolean; onExportToBackend?: ( exportedElements: readonly NonDeletedExcalidrawElement[], appState: AppState, canvas: HTMLCanvasElement | null, ) => void; + renderCustomFooter?: (isMobile: boolean) => JSX.Element; } const useOnClickOutside = ( @@ -123,59 +114,45 @@ const LibraryMenuItems = ({ let addedPendingElements = false; rows.push( - <> - + { - trackEvent(EVENT_EXIT, "libraries"); + importLibraryFromJSON() + .then(() => { + // Maybe we should close and open the menu so that the items get updated. + // But for now we just close the menu. + setAppState({ isLibraryOpen: false }); + }) + .catch(muteFSAbortError) + .catch((error) => { + setAppState({ errorMessage: error.message }); + }); }} - > + /> + { + saveLibraryAsJSON() + .catch(muteFSAbortError) + .catch((error) => { + setAppState({ errorMessage: error.message }); + }); + }} + /> + + {t("labels.libraries")} - - - { - importLibraryFromJSON() - .then(() => { - // Maybe we should close and open the menu so that the items get updated. - // But for now we just close the menu. - setAppState({ isLibraryOpen: false }); - }) - .catch(muteFSAbortError) - .catch((error) => { - setAppState({ errorMessage: error.message }); - }); - }} - /> - { - saveLibraryAsJSON() - .catch(muteFSAbortError) - .catch((error) => { - setAppState({ errorMessage: error.message }); - }); - }} - /> - - , +
, ); for (let row = 0; row < numRows; row++) { @@ -274,7 +251,6 @@ const LibraryMenu = ({ const items = await Library.loadLibrary(); const nextItems = items.filter((_, index) => index !== indexToRemove); Library.saveLibrary(nextItems); - trackEvent(EVENT_LIBRARY, "remove"); setLibraryItems(nextItems); }, []); @@ -283,7 +259,6 @@ const LibraryMenu = ({ const items = await Library.loadLibrary(); const nextItems = [...items, elements]; onAddToLibrary(); - trackEvent(EVENT_LIBRARY, "add"); Library.saveLibrary(nextItems); setLibraryItems(nextItems); }, @@ -318,11 +293,12 @@ const LayerUI = ({ elements, onCollabButtonClick, onLockToggle, - onInsertShape, + onInsertElements, zenModeEnabled, toggleZenMode, isCollaborating, onExportToBackend, + renderCustomFooter, }: LayerUIProps) => { const isMobile = useIsMobile(); @@ -334,9 +310,6 @@ const LayerUI = ({ href="https://blog.excalidraw.com/end-to-end-encryption/" target="_blank" rel="noopener noreferrer" - onClick={() => { - trackEvent(EVENT_EXIT, "e2ee shield"); - }} > {shield} @@ -456,7 +429,7 @@ const LayerUI = ({ @@ -558,14 +531,7 @@ const LayerUI = ({ "transition-right disable-pointerEvents": zenModeEnabled, })} > - { - await setLanguage(lng); - setAppState({}); - }} - languages={languages} - floating - /> + {renderCustomFooter?.(false)} {actionManager.renderAction("toggleShortcuts")}
+ ); +}; + +export const PasteChartDialog = ({ + setAppState, + appState, + onClose, + onInsertChart, +}: { + appState: AppState; + onClose: () => void; + setAppState: React.Component["setState"]; + onInsertChart: (elements: LibraryItem) => void; +}) => { + const handleClose = React.useCallback(() => { + if (onClose) { + onClose(); + } + }, [onClose]); + + const handleChartClick = (chartType: ChartType, elements: ChartElements) => { + onInsertChart(elements); + setAppState({ + currentChartType: chartType, + pasteDialog: { + shown: false, + data: null, + }, + }); + }; + + return ( + +
+ + +
+
+ ); +}; diff --git a/src/components/ShortcutsDialog.tsx b/src/components/ShortcutsDialog.tsx index 2e58a1ea2..ff9327d90 100644 --- a/src/components/ShortcutsDialog.tsx +++ b/src/components/ShortcutsDialog.tsx @@ -4,7 +4,6 @@ import { isDarwin } from "../keys"; import { Dialog } from "./Dialog"; import { getShortcutKey } from "../utils"; import "./ShortcutsDialog.scss"; -import { EVENT_EXIT, trackEvent } from "../analytics"; const Columns = (props: { children: React.ReactNode }) => (
( href="https://blog.excalidraw.com" target="_blank" rel="noopener noreferrer" - onClick={() => { - trackEvent(EVENT_EXIT, "blog"); - }} > {t("shortcutsDialog.blog")} @@ -102,9 +98,6 @@ const Footer = () => ( href="https://howto.excalidraw.com" target="_blank" rel="noopener noreferrer" - onClick={() => { - trackEvent(EVENT_EXIT, "guides"); - }} > {t("shortcutsDialog.howto")} @@ -112,9 +105,6 @@ const Footer = () => ( href="https://github.com/excalidraw/excalidraw/issues" target="_blank" rel="noopener noreferrer" - onClick={() => { - trackEvent(EVENT_EXIT, "issues"); - }} > {t("shortcutsDialog.github")} @@ -130,11 +120,7 @@ export const ShortcutsDialog = ({ onClose }: { onClose?: () => void }) => { return ( <> - + diff --git a/src/components/Stats.tsx b/src/components/Stats.tsx index c4b781b63..001a3c1fa 100644 --- a/src/components/Stats.tsx +++ b/src/components/Stats.tsx @@ -92,7 +92,6 @@ export const Stats = (props: { {t("stats.total")} {nFormatter(storageSizes.total, 1)} - {selectedElements.length === 1 && ( {t("stats.element")} diff --git a/src/components/ToolIcon.scss b/src/components/ToolIcon.scss index 3c542aea0..91e8e1bc5 100644 --- a/src/components/ToolIcon.scss +++ b/src/components/ToolIcon.scss @@ -142,6 +142,7 @@ user-select: none; } + // shrink shape icons on small viewports to make them fit @media (max-width: 425px) { .Shape .ToolIcon__icon { width: 2rem; @@ -153,6 +154,8 @@ } } + // move the lock button out of the way on small viewports + // it begins to collide with the GitHub icon before we switch to mobile mode @media (max-width: 760px) { .ToolIcon.ToolIcon__lock { display: inline-block; @@ -162,6 +165,7 @@ margin-left: 0; border-radius: 20px 0 0 20px; + z-index: 1; background-color: var(--button-gray-1); @@ -189,7 +193,7 @@ margin-left: 5px; margin-top: 1px; - @media #{$media-query} { + @media #{$is-mobile-query} { display: none; } } diff --git a/src/constants.ts b/src/constants.ts index 0a6a793cd..4f22b35ec 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -70,6 +70,7 @@ export const DEFAULT_FONT_SIZE = 20; export const DEFAULT_FONT_FAMILY: FontFamily = 1; export const DEFAULT_TEXT_ALIGN = "left"; export const DEFAULT_VERTICAL_ALIGN = "top"; +export const DEFAULT_VERSION = "{version}"; export const CANVAS_ONLY_ACTIONS = ["selectAll"]; diff --git a/src/css/_variables.scss b/src/css/_variables.scss index 142d1756b..4e4ac861d 100644 --- a/src/css/_variables.scss +++ b/src/css/_variables.scss @@ -1,3 +1,4 @@ @import "open-color/open-color.scss"; -$media-query: "(max-width: 600px), (max-height: 500px) and (max-width: 1000px)"; +// keep up to date with is-mobile.tsx +$is-mobile-query: "(max-width: 600px), (max-height: 500px) and (max-width: 1000px)"; diff --git a/src/css/styles.scss b/src/css/styles.scss index 28edcc7ee..c2fcd527b 100644 --- a/src/css/styles.scss +++ b/src/css/styles.scss @@ -441,7 +441,7 @@ } } - @media #{$media-query} { + @media #{$is-mobile-query} { aside { display: none; } diff --git a/src/css/theme.scss b/src/css/theme.scss index b28fca637..4de90d83d 100644 --- a/src/css/theme.scss +++ b/src/css/theme.scss @@ -3,7 +3,6 @@ :root { --bg-color-island: rgba(255, 255, 255, 0.9); --popup-background-color: #{$oc-white}; - --border-radius-m: 4px; --space-factor: 0.25rem; --button-gray-1: #{$oc-gray-2}; --button-gray-2: #{$oc-gray-4}; @@ -15,7 +14,6 @@ --icon-fill-color: #{$oc-black}; --icon-green-fill-color: #{$oc-green-9}; --keybinding-color: #{$oc-gray-5}; - --color-overlay-text-color: #ccc; --sat: env(safe-area-inset-top); --sab: env(safe-area-inset-bottom); --sal: env(safe-area-inset-left); @@ -23,8 +21,6 @@ --text-color-primary: #{$oc-gray-8}; --shadow-island: 0 1px 5px #{transparentize($oc-black, 0.85)}; --overlay-background-color: #{transparentize($oc-white, 0.12)}; - --border-radius-m: 4px; - --space-factor: 0.25rem; --dropdown-icon: url('data:image/svg+xml,'); --focus-highlight-color: #{$oc-blue-2}; --select-highlight-color: #{$oc-blue-5}; @@ -35,6 +31,7 @@ --popup-secondary-background-color: #{$oc-gray-1}; --popup-text-color: #{$oc-black}; --popup-text-inverted-color: #{$oc-white}; + --dialog-border: #{$oc-gray-6}; } .excalidraw { @@ -60,10 +57,8 @@ --icon-fill-color: #{$oc-gray-4}; --icon-green-fill-color: #{$oc-green-4}; --keybinding-color: #{$oc-gray-6}; - --color-overlay-text-color: #bbb; --shadow-island: 0 1px 5px #{transparentize($oc-black, 0.7)}; --overlay-background-color: rgba(30, 30, 30, 0.88); - // #{$oc-gray-4}; inlined --dropdown-icon: url('data:image/svg+xml,'); --focus-highlight-color: #{$oc-blue-6}; --select-highlight-color: #{$oc-blue-4}; @@ -74,5 +69,6 @@ --popup-secondary-background-color: #222; --popup-text-color: #{$oc-gray-4}; --popup-text-inverted-color: #2c2c2c; + --dialog-border: #{$oc-gray-9}; } } diff --git a/src/data/blob.ts b/src/data/blob.ts index e73b367b6..1ecc9df7f 100644 --- a/src/data/blob.ts +++ b/src/data/blob.ts @@ -1,4 +1,3 @@ -import { EVENT_IO, trackEvent } from "../analytics"; import { cleanAppStateForExport } from "../appState"; import { MIME_TYPES } from "../constants"; import { clearElementsForExport } from "../element"; @@ -111,7 +110,6 @@ export const loadFromBlob = async ( localAppState, ); - trackEvent(EVENT_IO, "load", getMimeType(blob)); return result; } catch (error) { console.error(error.message); diff --git a/src/data/index.ts b/src/data/index.ts index 6797a7a30..41de22a44 100644 --- a/src/data/index.ts +++ b/src/data/index.ts @@ -1,5 +1,4 @@ import { fileSave } from "browser-nativefs"; -import { EVENT_IO, trackEvent } from "../analytics"; import { copyCanvasToClipboardAsPng, copyTextToSystemClipboard, @@ -8,8 +7,8 @@ import { NonDeletedExcalidrawElement } from "../element/types"; import { t } from "../i18n"; import { exportToCanvas, exportToSvg } from "../scene/export"; import { ExportType } from "../scene/types"; -import { canvasToBlob } from "./blob"; import { AppState } from "../types"; +import { canvasToBlob } from "./blob"; import { serializeAsJSON } from "./json"; export { loadFromBlob } from "./blob"; @@ -60,10 +59,8 @@ export const exportCanvas = async ( fileName: `${name}.svg`, extensions: [".svg"], }); - trackEvent(EVENT_IO, "export", "svg"); return; } else if (type === "clipboard-svg") { - trackEvent(EVENT_IO, "export", "clipboard-svg"); copyTextToSystemClipboard(tempSvg.outerHTML); return; } @@ -95,11 +92,9 @@ export const exportCanvas = async ( fileName, extensions: [".png"], }); - trackEvent(EVENT_IO, "export", "png"); } else if (type === "clipboard") { try { await copyCanvasToClipboardAsPng(tempCanvas); - trackEvent(EVENT_IO, "export", "clipboard-png"); } catch (error) { if (error.name === "CANVAS_POSSIBLY_TOO_BIG") { throw error; diff --git a/src/data/json.ts b/src/data/json.ts index 67e969bef..d4d3205a1 100644 --- a/src/data/json.ts +++ b/src/data/json.ts @@ -1,13 +1,11 @@ -import { ExcalidrawElement } from "../element/types"; -import { AppState } from "../types"; -import { cleanAppStateForExport } from "../appState"; - import { fileOpen, fileSave } from "browser-nativefs"; -import { loadFromBlob } from "./blob"; -import { Library } from "./library"; +import { cleanAppStateForExport } from "../appState"; import { MIME_TYPES } from "../constants"; import { clearElementsForExport } from "../element"; -import { EVENT_LIBRARY, trackEvent } from "../analytics"; +import { ExcalidrawElement } from "../element/types"; +import { AppState } from "../types"; +import { loadFromBlob } from "./blob"; +import { Library } from "./library"; export const serializeAsJSON = ( elements: readonly ExcalidrawElement[], @@ -84,7 +82,6 @@ export const saveLibraryAsJSON = async () => { description: "Excalidraw library file", extensions: [".excalidrawlib"], }); - trackEvent(EVENT_LIBRARY, "save"); }; export const importLibraryFromJSON = async () => { @@ -93,6 +90,5 @@ export const importLibraryFromJSON = async () => { extensions: [".json", ".excalidrawlib"], mimeTypes: ["application/json"], }); - trackEvent(EVENT_LIBRARY, "load"); Library.importLibrary(blob); }; diff --git a/src/element/types.ts b/src/element/types.ts index 2980263bf..baeb001a6 100644 --- a/src/element/types.ts +++ b/src/element/types.ts @@ -1,6 +1,7 @@ import { Point } from "../types"; import { FONT_FAMILY } from "../constants"; +export type ChartType = "bar" | "line"; export type FillStyle = "hachure" | "cross-hatch" | "solid"; export type FontFamily = keyof typeof FONT_FAMILY; export type FontString = string & { _brand: "fontString" }; @@ -26,11 +27,21 @@ type _ExcalidrawElementBase = Readonly<{ width: number; height: number; angle: number; + /** Random integer used to seed shape generation so that the roughjs shape + doesn't differ across renders. */ seed: number; + /** Integer that is sequentially incremented on each change. Used to reconcile + elements during collaboration or when saving to server. */ version: number; + /** Random integer that is regenerated on each change. + Used for deterministic reconciliation of updates during collaboration, + in case the versions (see above) are identical. */ versionNonce: number; isDeleted: boolean; + /** List of groups the element belongs to. + Ordered from deepest to shallowest. */ groupIds: readonly GroupId[]; + /** Ids of (linear) elements that are bound to this element. */ boundElementIds: readonly ExcalidrawLinearElement["id"][] | null; }>; diff --git a/src/excalidraw-app/collab/CollabWrapper.tsx b/src/excalidraw-app/collab/CollabWrapper.tsx index 9e46a630c..d27adb35d 100644 --- a/src/excalidraw-app/collab/CollabWrapper.tsx +++ b/src/excalidraw-app/collab/CollabWrapper.tsx @@ -1,40 +1,36 @@ -import React, { PureComponent } from "react"; import throttle from "lodash.throttle"; - +import React, { PureComponent } from "react"; +import { ExcalidrawImperativeAPI } from "../../components/App"; +import { ErrorDialog } from "../../components/ErrorDialog"; import { APP_NAME, ENV, EVENT } from "../../constants"; - -import { - decryptAESGEM, - SocketUpdateDataSource, - getCollaborationLinkData, - generateCollaborationLink, - SOCKET_SERVER, -} from "../data"; -import { isSavedToFirebase, saveToFirebase } from "../data/firebase"; - -import Portal from "./Portal"; -import { AppState, Collaborator, Gesture } from "../../types"; +import { ImportedDataState } from "../../data/types"; import { ExcalidrawElement } from "../../element/types"; -import { - importUsernameFromLocalStorage, - saveUsernameToLocalStorage, - STORAGE_KEYS, -} from "../data/localStorage"; -import { resolvablePromise, withBatchedUpdates } from "../../utils"; import { getSceneVersion, getSyncableElements, } from "../../packages/excalidraw/index"; -import RoomDialog from "./RoomDialog"; -import { ErrorDialog } from "../../components/ErrorDialog"; -import { ImportedDataState } from "../../data/types"; -import { ExcalidrawImperativeAPI } from "../../components/App"; +import { AppState, Collaborator, Gesture } from "../../types"; +import { resolvablePromise, withBatchedUpdates } from "../../utils"; import { INITIAL_SCENE_UPDATE_TIMEOUT, SCENE, SYNC_FULL_SCENE_INTERVAL_MS, } from "../app_constants"; -import { EVENT_SHARE, trackEvent } from "../../analytics"; +import { + decryptAESGEM, + generateCollaborationLink, + getCollaborationLinkData, + SocketUpdateDataSource, + SOCKET_SERVER, +} from "../data"; +import { isSavedToFirebase, saveToFirebase } from "../data/firebase"; +import { + importUsernameFromLocalStorage, + saveUsernameToLocalStorage, + STORAGE_KEYS, +} from "../data/localStorage"; +import Portal from "./Portal"; +import RoomDialog from "./RoomDialog"; interface CollabState { isCollaborating: boolean; @@ -168,7 +164,6 @@ class CollabWrapper extends PureComponent { elements, commitToHistory: true, }); - trackEvent(EVENT_SHARE, "session start"); return this.initializeSocketClient(); }; @@ -176,7 +171,6 @@ class CollabWrapper extends PureComponent { this.saveCollabRoomToFirebase(); window.history.pushState({}, APP_NAME, window.location.origin); this.destroySocketClient(); - trackEvent(EVENT_SHARE, "session end"); }; private destroySocketClient = () => { diff --git a/src/excalidraw-app/collab/RoomDialog.tsx b/src/excalidraw-app/collab/RoomDialog.tsx index afe8ef243..c880eece7 100644 --- a/src/excalidraw-app/collab/RoomDialog.tsx +++ b/src/excalidraw-app/collab/RoomDialog.tsx @@ -1,12 +1,10 @@ import React, { useRef } from "react"; -import { t } from "../../i18n"; -import { Dialog } from "../../components/Dialog"; import { copyTextToSystemClipboard } from "../../clipboard"; -import { ToolButton } from "../../components/ToolButton"; +import { Dialog } from "../../components/Dialog"; import { clipboard, start, stop } from "../../components/icons"; - +import { ToolButton } from "../../components/ToolButton"; +import { t } from "../../i18n"; import "./RoomDialog.scss"; -import { EVENT_SHARE, trackEvent } from "../../analytics"; const RoomDialog = ({ handleClose, @@ -30,7 +28,6 @@ const RoomDialog = ({ const copyRoomLink = async () => { try { await copyTextToSystemClipboard(activeRoomLink); - trackEvent(EVENT_SHARE, "copy link"); } catch (error) { setErrorMessage(error.message); } @@ -95,7 +92,6 @@ const RoomDialog = ({ value={username || ""} className="RoomDialog-username TextInput" onChange={(event) => onUsernameChange(event.target.value)} - onBlur={() => trackEvent(EVENT_SHARE, "name")} onKeyPress={(event) => event.key === "Enter" && handleClose()} />
@@ -123,11 +119,7 @@ const RoomDialog = ({ ); }; return ( - + {renderRoomDialog()} ); diff --git a/src/excalidraw-app/components/LanguageList.tsx b/src/excalidraw-app/components/LanguageList.tsx new file mode 100644 index 000000000..4b707907e --- /dev/null +++ b/src/excalidraw-app/components/LanguageList.tsx @@ -0,0 +1,36 @@ +import React from "react"; +import clsx from "clsx"; +import * as i18n from "../../i18n"; + +export const LanguageList = ({ + onChange, + languages = i18n.languages, + currentLangCode = i18n.getLanguage().code, + floating, +}: { + languages?: { code: string; label: string }[]; + onChange: (langCode: i18n.Language["code"]) => void; + currentLangCode?: i18n.Language["code"]; + floating?: boolean; +}) => ( + + + +); diff --git a/src/excalidraw-app/data/index.ts b/src/excalidraw-app/data/index.ts index 0eb52fd86..9ec7b257c 100644 --- a/src/excalidraw-app/data/index.ts +++ b/src/excalidraw-app/data/index.ts @@ -1,10 +1,9 @@ -import { t } from "../../i18n"; -import { ExcalidrawElement } from "../../element/types"; -import { AppState } from "../../types"; -import { ImportedDataState } from "../../data/types"; -import { restore } from "../../data/restore"; -import { EVENT_ACTION, EVENT_IO, trackEvent } from "../../analytics"; import { serializeAsJSON } from "../../data/json"; +import { restore } from "../../data/restore"; +import { ImportedDataState } from "../../data/types"; +import { ExcalidrawElement } from "../../element/types"; +import { t } from "../../i18n"; +import { AppState } from "../../types"; const byteToHex = (byte: number): string => `0${byte.toString(16)}`.slice(-2); @@ -192,7 +191,6 @@ const importFromBackend = async ( data = await response.json(); } - trackEvent(EVENT_ACTION, "import"); return { elements: data.elements || null, appState: data.appState || null, @@ -276,7 +274,6 @@ export const exportToBackend = async ( url.hash = `json=${json.id},${exportedKey.k!}`; const urlString = url.toString(); window.prompt(`🔒${t("alerts.uploadedSecurly")}`, urlString); - trackEvent(EVENT_IO, "export", "backend"); } else if (json.error_class === "RequestTooLargeError") { window.alert(t("alerts.couldNotCreateShareableLinkTooBig")); } else { diff --git a/src/excalidraw-app/index.tsx b/src/excalidraw-app/index.tsx index c8b151f47..d63eb71b6 100644 --- a/src/excalidraw-app/index.tsx +++ b/src/excalidraw-app/index.tsx @@ -1,34 +1,53 @@ -import React, { useState, useLayoutEffect, useEffect, useRef } from "react"; - -import Excalidraw from "../packages/excalidraw/index"; - +import LanguageDetector from "i18next-browser-languagedetector"; +import React, { + useCallback, + useEffect, + useLayoutEffect, + useRef, + useState, +} from "react"; +import { trackEvent } from "../analytics"; +import { getDefaultAppState } from "../appState"; +import { ExcalidrawImperativeAPI } from "../components/App"; +import { ErrorDialog } from "../components/ErrorDialog"; +import { TopErrorBoundary } from "../components/TopErrorBoundary"; +import { APP_NAME, EVENT, TITLE_TIMEOUT } from "../constants"; +import { ImportedDataState } from "../data/types"; +import { + ExcalidrawElement, + NonDeletedExcalidrawElement, +} from "../element/types"; +import { Language, t } from "../i18n"; +import Excalidraw, { + defaultLang, + languages, +} from "../packages/excalidraw/index"; +import { AppState, ExcalidrawAPIRefValue } from "../types"; +import { + debounce, + getVersion, + ResolvablePromise, + resolvablePromise, +} from "../utils"; +import { SAVE_TO_LOCAL_STORAGE_TIMEOUT } from "./app_constants"; +import CollabWrapper, { CollabAPI } from "./collab/CollabWrapper"; +import { LanguageList } from "./components/LanguageList"; +import { exportToBackend, getCollaborationLinkData, loadScene } from "./data"; +import { loadFromFirebase } from "./data/firebase"; import { - getTotalStorageSize, importFromLocalStorage, saveToLocalStorage, STORAGE_KEYS, } from "./data/localStorage"; -import { ImportedDataState } from "../data/types"; -import CollabWrapper, { CollabAPI } from "./collab/CollabWrapper"; -import { TopErrorBoundary } from "../components/TopErrorBoundary"; -import { t } from "../i18n"; -import { exportToBackend, loadScene } from "./data"; -import { getCollaborationLinkData } from "./data"; -import { EVENT } from "../constants"; -import { loadFromFirebase } from "./data/firebase"; -import { ExcalidrawImperativeAPI } from "../components/App"; -import { debounce, ResolvablePromise, resolvablePromise } from "../utils"; -import { AppState, ExcalidrawAPIRefValue } from "../types"; -import { - ExcalidrawElement, - NonDeletedExcalidrawElement, -} from "../element/types"; -import { SAVE_TO_LOCAL_STORAGE_TIMEOUT } from "./app_constants"; -import { EVENT_LOAD, EVENT_SHARE, trackEvent } from "../analytics"; -import { ErrorDialog } from "../components/ErrorDialog"; -import { getDefaultAppState } from "../appState"; -import { APP_NAME, TITLE_TIMEOUT } from "../constants"; +const languageDetector = new LanguageDetector(); +languageDetector.init({ + languageUtils: { + formatLanguageCode: (langCode: Language["code"]) => langCode, + isWhitelisted: () => true, + }, + checkWhitelist: false, +}); const excalidrawRef: React.MutableRefObject< MarkRequired @@ -93,7 +112,6 @@ type Scene = ImportedDataState & { commitToHistory: boolean }; const initializeScene = async (opts: { resetScene: ExcalidrawImperativeAPI["resetScene"]; initializeSocketClient: CollabAPI["initializeSocketClient"]; - onLateInitialization?: (scene: Scene) => void; }): Promise => { const searchParams = new URLSearchParams(window.location.search); const id = searchParams.get("id"); @@ -124,17 +142,15 @@ const initializeScene = async (opts: { } else { // https://github.com/excalidraw/excalidraw/issues/1919 if (document.hidden) { - window.addEventListener( - "focus", - () => - initializeScene(opts).then((_scene) => { - opts?.onLateInitialization?.(_scene || scene); - }), - { - once: true, - }, - ); - return null; + return new Promise((resolve, reject) => { + window.addEventListener( + "focus", + () => initializeScene(opts).then(resolve).catch(reject), + { + once: true, + }, + ); + }); } isCollabScene = false; @@ -146,7 +162,6 @@ const initializeScene = async (opts: { // into the remote scene opts.resetScene(); const scenePromise = opts.initializeSocketClient(); - trackEvent(EVENT_SHARE, "session join"); try { const [, roomId, roomKey] = getCollaborationLinkData( @@ -185,6 +200,8 @@ function ExcalidrawWrapper(props: { collab: CollabAPI }) { height: window.innerHeight, }); const [errorMessage, setErrorMessage] = useState(""); + const currentLangCode = languageDetector.detect() || defaultLang.code; + const [langCode, setLangCode] = useState(currentLangCode); useLayoutEffect(() => { const onResize = () => { @@ -212,19 +229,11 @@ function ExcalidrawWrapper(props: { collab: CollabAPI }) { const { collab } = props; useEffect(() => { - const storageSize = getTotalStorageSize(); - if (storageSize) { - trackEvent(EVENT_LOAD, "storage", "size", storageSize); - } else { - trackEvent(EVENT_LOAD, "first time"); - } + trackEvent("load", "version", getVersion()); excalidrawRef.current!.readyPromise.then((excalidrawApi) => { initializeScene({ resetScene: excalidrawApi.resetScene, initializeSocketClient: collab.initializeSocketClient, - onLateInitialization: (scene) => { - initialStatePromiseRef.current.promise.resolve(scene); - }, }).then((scene) => { initialStatePromiseRef.current.promise.resolve(scene); }); @@ -262,6 +271,10 @@ function ExcalidrawWrapper(props: { collab: CollabAPI }) { }; }, [collab.initializeSocketClient]); + useEffect(() => { + languageDetector.cacheUserLanguage(langCode); + }, [langCode]); + const onChange = ( elements: readonly ExcalidrawElement[], appState: AppState, @@ -297,6 +310,32 @@ function ExcalidrawWrapper(props: { collab: CollabAPI }) { } } }; + + const renderFooter = useCallback( + (isMobile: boolean) => { + const renderLanguageList = () => ( + { + setLangCode(langCode); + }} + languages={languages} + floating={!isMobile} + currentLangCode={langCode} + /> + ); + if (isMobile) { + return ( +
+ {t("labels.language")} + {renderLanguageList()} +
+ ); + } + return renderLanguageList(); + }, + [langCode], + ); + return ( <> {errorMessage && ( (left.label > right.label ? 1 : -1)), - ) +const allLanguages: Language[] = [ + { code: "ar-SA", label: "العربية", rtl: true }, + { code: "bg-BG", label: "Български" }, + { code: "ca-ES", label: "Català" }, + { code: "de-DE", label: "Deutsch" }, + { code: "el-GR", label: "Ελληνικά" }, + { code: "es-ES", label: "Español" }, + { code: "fa-IR", label: "فارسی", rtl: true }, + { code: "fi-FI", label: "Suomi" }, + { code: "fr-FR", label: "Français" }, + { code: "he-IL", label: "עברית", rtl: true }, + { code: "hi-IN", label: "हिन्दी" }, + { code: "hu-HU", label: "Magyar" }, + { code: "id-ID", label: "Bahasa Indonesia" }, + { code: "it-IT", label: "Italiano" }, + { code: "ja-JP", label: "日本語" }, + { code: "ko-KR", label: "한국어" }, + { code: "my-MM", label: "Burmese" }, + { code: "nb-NO", label: "Norsk bokmål" }, + { code: "nl-NL", label: "Nederlands" }, + { code: "nn-NO", label: "Norsk nynorsk" }, + { code: "pa-IN", label: "ਪੰਜਾਬੀ" }, + { code: "pl-PL", label: "Polski" }, + { code: "pt-BR", label: "Português Brasileiro" }, + { code: "pt-PT", label: "Português" }, + { code: "ro-RO", label: "Română" }, + { code: "ru-RU", label: "Русский" }, + { code: "sk-SK", label: "Slovenčina" }, + { code: "sv-SE", label: "Svenska" }, + { code: "tr-TR", label: "Türkçe" }, + { code: "uk-UA", label: "Українська" }, + { code: "zh-CN", label: "简体中文" }, + { code: "zh-TW", label: "繁體中文" }, +].concat([defaultLang]); + +export const languages: Language[] = allLanguages + .sort((left, right) => (left.label > right.label ? 1 : -1)) .filter( (lang) => - (percentages as Record)[lang.lng] > - COMPLETION_THRESHOLD_TO_EXCEED, + (percentages as Record)[lang.code] >= + COMPLETION_THRESHOLD, ); -let currentLanguage = languages[0]; -let currentLanguageData = {}; -const fallbackLanguage = languages[0]; +let currentLang: Language = defaultLang; +let currentLangData = {}; -export const setLanguage = async (newLng: string | undefined) => { - currentLanguage = - languages.find((language) => language.lng === newLng) || fallbackLanguage; +export const setLanguage = async (lang: Language) => { + currentLang = lang; + document.documentElement.dir = currentLang.rtl ? "rtl" : "ltr"; - document.documentElement.dir = currentLanguage.rtl ? "rtl" : "ltr"; - - currentLanguageData = await import( - /* webpackChunkName: "i18n-[request]" */ `./locales/${currentLanguage.lng}.json` + currentLangData = await import( + /* webpackChunkName: "i18n-[request]" */ `./locales/${currentLang.code}.json` ); - languageDetector.cacheUserLanguage(currentLanguage.lng); - trackEvent(EVENT_CHANGE, "language", currentLanguage.lng); }; -export const setLanguageFirstTime = async () => { - const newLng: string | undefined = languageDetector.detect(); +export const setLanguageFirstTime = async (lang: Language) => { + currentLang = lang; + document.documentElement.dir = currentLang.rtl ? "rtl" : "ltr"; - currentLanguage = - languages.find((language) => language.lng === newLng) || fallbackLanguage; - - document.documentElement.dir = currentLanguage.rtl ? "rtl" : "ltr"; - - currentLanguageData = await import( - /* webpackChunkName: "i18n-[request]" */ `./locales/${currentLanguage.lng}.json` + currentLangData = await import( + /* webpackChunkName: "i18n-[request]" */ `./locales/${currentLang.code}.json` ); - - languageDetector.cacheUserLanguage(currentLanguage.lng); }; -export const getLanguage = () => currentLanguage; +export const getLanguage = () => currentLang; const findPartsForData = (data: any, parts: string[]) => { for (let index = 0; index < parts.length; ++index) { @@ -106,8 +94,8 @@ const findPartsForData = (data: any, parts: string[]) => { export const t = (path: string, replacement?: { [key: string]: string }) => { const parts = path.split("."); let translation = - findPartsForData(currentLanguageData, parts) || - findPartsForData(fallbackLanguageData, parts); + findPartsForData(currentLangData, parts) || + findPartsForData(fallbackLangData, parts); if (translation === undefined) { throw new Error(`Can't find translation for ${path}`); } @@ -119,12 +107,3 @@ export const t = (path: string, replacement?: { [key: string]: string }) => { } return translation; }; - -const languageDetector = new LanguageDetector(); -languageDetector.init({ - languageUtils: { - formatLanguageCode: (lng: string) => lng, - isWhitelisted: () => true, - }, - checkWhitelist: false, -}); diff --git a/src/is-mobile.tsx b/src/is-mobile.tsx index 9a8d5fe2b..c20bf89de 100644 --- a/src/is-mobile.tsx +++ b/src/is-mobile.tsx @@ -11,6 +11,7 @@ export const IsMobileProvider = ({ if (!query.current) { query.current = window.matchMedia ? window.matchMedia( + // keep up to date with _variables.scss "(max-width: 640px), (max-height: 500px) and (max-width: 1000px)", ) : (({ diff --git a/src/keys.ts b/src/keys.ts index d072ca937..9e0cd2ac9 100644 --- a/src/keys.ts +++ b/src/keys.ts @@ -40,6 +40,7 @@ export const KEYS = { D: "d", E: "e", L: "l", + O: "o", P: "p", Q: "q", R: "r", diff --git a/src/locales/README.md b/src/locales/README.md index 6ed6bf324..a6113c1a0 100644 --- a/src/locales/README.md +++ b/src/locales/README.md @@ -3,12 +3,10 @@ Please do not contribute changes directly to these files, as we manage them with Crowdin. Instead: - to request a new translation, [open an issue](https://github.com/excalidraw/excalidraw/issues/new/choose). -- to update existing translations, [edit them on Crowdin](https://crowdin.com/translate/excalidraw/10) - and we should have them included in the app soon! +- to update existing translations, [edit them on Crowdin](https://crowdin.com/translate/excalidraw/10) and we should have them included in the app soon! ## Completion of translation -[percentages.json](./percentages.json) holds a percentage of completion for each language. We generate these -automatically [on build time](./../../.github/workflows/locales-coverage.yml) when a new translation PR appears. +[percentages.json](./percentages.json) holds a percentage of completion for each language. We generate these automatically [on build time](./../../.github/workflows/locales-coverage.yml) when a new translation PR appears. We only make a language available on the app if it exceeds a certain threshold of completion. diff --git a/src/locales/ar-SA.json b/src/locales/ar-SA.json index 59238624c..6e69ed5fc 100644 --- a/src/locales/ar-SA.json +++ b/src/locales/ar-SA.json @@ -1,17 +1,18 @@ { "labels": { "paste": "لصق", + "pasteCharts": "لصق الرسوم البيانية", "selectAll": "تحديد الكل", "multiSelect": "إضافة عنصر للتحديد", "moveCanvas": "نقل لوح رسم", - "cut": "", + "cut": "قص", "copy": "نسخ", "copyAsPng": "نسخ إلى الحافظة بصيغة PNG", - "copyAsSvg": "نسخ بصيغة SVG", - "bringForward": "ارقع للأمام", + "copyAsSvg": "نسخ إلى الحافظة بصيغة SVG", + "bringForward": "جلب للأمام", "sendToBack": "أرسل للخلف", "bringToFront": "أحضر للأمام", - "sendBackward": "أنزل للوراء", + "sendBackward": "أرسل للخلف", "delete": "حذف", "copyStyles": "نسخ النمط", "pasteStyles": "لصق النمط", @@ -29,11 +30,11 @@ "edges": "الحواف", "sharp": "حادة", "round": "دائرية", - "arrowheads": "", - "arrowhead_none": "", - "arrowhead_arrow": "", - "arrowhead_bar": "", - "arrowhead_dot": "", + "arrowheads": "رؤوس الأسهم", + "arrowhead_none": "لا شيء", + "arrowhead_arrow": "سهم", + "arrowhead_bar": "شريط", + "arrowhead_dot": "نقطة", "fontSize": "حجم الخط", "fontFamily": "نوع الخط", "onlySelected": "المحدد فقط", @@ -60,7 +61,7 @@ "architect": "معماري", "artist": "رسام", "cartoonist": "كرتوني", - "fileTitle": "", + "fileTitle": "عنوان الملف", "colorPicker": "اختيار الألوان", "canvasBackground": "خلفية اللوحة", "drawingCanvas": "لوحة الرسم", @@ -69,19 +70,18 @@ "language": "اللغة", "createRoom": "مشاركة الجلسة مباشرة", "duplicateSelection": "تكرار", - "untitled": "", + "untitled": "غير معنون", "name": "الاسم", "yourName": "اسمك", "madeWithExcalidraw": "مصنوعة بواسطة Excalidraw", "group": "تحديد مجموعة", "ungroup": "إلغاء تحديد مجموعة", "collaborators": "المتعاونون", - "toggleGridMode": "التبديل إلى وضع الشبكة", - "toggleStats": "", + "gridMode": "وضع الشبكة", "addToLibrary": "أضف إلى المكتبة", "removeFromLibrary": "حذف من المكتبة", "libraryLoadingMessage": "جارٍ تحميل المكتبة...", - "libraries": "", + "libraries": "تصفح المكتبات", "loadingScene": "جاري تحميل المشهد...", "align": "محاذاة", "alignTop": "محاذاة إلى اﻷعلى", @@ -118,9 +118,10 @@ "redo": "إعادة تنفيذ", "roomDialog": "بدء المشاركة الحية", "createNewRoom": "إنشاء غرفة جديدة", - "toggleFullScreen": "التبديل لوضع ملء الشاشة", - "toggleDarkMode": "تبديل الوضع الليلي", - "toggleZenMode": "تبديل الوضع الليلي", + "fullScreen": "شاشة كاملة", + "darkMode": "الوضع المظلم", + "lightMode": "الوضع المضيء", + "zenMode": "وضع التأمل", "exitZenMode": "إلغاء الوضع الليلى" }, "alerts": { @@ -136,7 +137,7 @@ "loadSceneOverridePrompt": "تحميل الرسم الخارجي سيحل محل المحتوى الموجود لديك. هل ترغب في المتابعة؟", "errorLoadingLibrary": "حصل خطأ أثناء تحميل مكتبة الطرف الثالث.", "confirmAddLibrary": "هذا سيضيف {{numShapes}} شكل إلى مكتبتك. هل أنت متأكد؟", - "imageDoesNotContainScene": "لا يحتوي ملف الصورة على بيانات المشهد. هل قمت بتمكين هذا أثناء التصدير؟", + "imageDoesNotContainScene": "استيراد الصور غير مدعوم في الوقت الراهن.\n\nهل تريد استيراد مشهد؟ لا يبدو أن هذه الصورة تحتوي على أي بيانات مشهد. هل قمت بسماح هذا أثناء التصدير؟", "cannotRestoreFromImage": "تعذر استعادة المشهد من ملف الصورة" }, "toolBar": { @@ -161,6 +162,7 @@ "freeDraw": "انقر واسحب، افرج عند الانتهاء", "text": "نصيحة: يمكنك أيضًا إضافة نص بالنقر المزدوج في أي مكان بأداة الاختيار", "linearElementMulti": "انقر فوق النقطة الأخيرة أو اضغط على Esc أو Enter للإنهاء", + "lockAngle": "يمكنك تقييد الزاوية بالضغط على SHIFT", "resize": "يمكنك تقييد النسب بالضغط على SHIFT أثناء تغيير الحجم،\nاضغط على ALT لتغيير الحجم من المركز", "rotate": "يمكنك تقييد الزوايا من خلال الضغط على SHIFT أثناء الدوران", "lineEditor_info": "انقر نقراً مزدوجاً أو اضغط Enter لتعديل النقاط", @@ -201,7 +203,7 @@ "title": "اختصارات لوحة المفاتيح", "shapes": "الأشكال", "or": "أو", - "click": "انقر فوق", + "click": "انقر", "drag": "اسحب", "curvedArrow": "سهم منحنى", "curvedLine": "خط منحنى", @@ -213,22 +215,22 @@ "textNewLine": "إضافة سطر جديد (نص)", "textFinish": "الانتهاء من تحرير (النص)", "zoomToFit": "تكبير لتلائم جميع العناصر", - "zoomToSelection": "", + "zoomToSelection": "تقريب للمحدد", "preventBinding": "منع ربط السهم" }, "encrypted": { "tooltip": "رسوماتك مشفرة من النهاية إلى النهاية حتى أن خوادم Excalidraw لن تراها أبدا." }, "stats": { - "angle": "", - "element": "", - "elements": "", - "height": "", - "scene": "", - "selected": "", - "storage": "", - "title": "", - "total": "", - "width": "" + "angle": "الزاوية", + "element": "عنصر", + "elements": "العناصر", + "height": "الارتفاع", + "scene": "المشهد", + "selected": "المحدد", + "storage": "التخزين", + "title": "إحصائيات للمهووسين", + "total": "المجموع", + "width": "العرض" } } diff --git a/src/locales/bg-BG.json b/src/locales/bg-BG.json index d70b71998..2101a395d 100644 --- a/src/locales/bg-BG.json +++ b/src/locales/bg-BG.json @@ -1,10 +1,11 @@ { "labels": { "paste": "Постави", + "pasteCharts": "Постави графики", "selectAll": "Маркирай всичко", - "multiSelect": "", - "moveCanvas": "", - "cut": "", + "multiSelect": "Добави елемент към селекция", + "moveCanvas": "Премести платно", + "cut": "Изрежи", "copy": "Копирай", "copyAsPng": "Копиране в клипборда", "copyAsSvg": "Копиране в клипборда", @@ -19,28 +20,28 @@ "background": "Фон", "fill": "Наситеност", "strokeWidth": "Ширина на щриха", - "strokeStyle": "", - "strokeStyle_solid": "", - "strokeStyle_dashed": "", - "strokeStyle_dotted": "", + "strokeStyle": "Стил на линия", + "strokeStyle_solid": "Плътен", + "strokeStyle_dashed": "Пунктир", + "strokeStyle_dotted": "Пунктирано", "sloppiness": "Небрежност", - "opacity": "Непрозрачност", + "opacity": "Прозрачност", "textAlign": "Подравняване на текста", - "edges": "", - "sharp": "", - "round": "", - "arrowheads": "", - "arrowhead_none": "", - "arrowhead_arrow": "", - "arrowhead_bar": "", - "arrowhead_dot": "", + "edges": "Крайща", + "sharp": "Остър", + "round": "Закръглено", + "arrowheads": "Стрелки", + "arrowhead_none": "Без", + "arrowhead_arrow": "Стрелка", + "arrowhead_bar": "Връх на стрелката", + "arrowhead_dot": "Точка", "fontSize": "Размер на шрифта", "fontFamily": "Семейство шрифтове", "onlySelected": "Само избраното", "withBackground": "С фон", - "exportEmbedScene": "", - "exportEmbedScene_details": "", - "addWatermark": "", + "exportEmbedScene": "Вгради сцената във файл", + "exportEmbedScene_details": "Данните от сцената ще бъдат екпортирани в PNG/SVG файл, за да може сцената да бъде възстановена от него.\nТова ще увеличи размера на файла.", + "addWatermark": "Добави \"Направено с Excalidraw\"", "handDrawn": "Нарисувано на ръка", "normal": "Нормален", "code": "Код", @@ -50,7 +51,7 @@ "veryLarge": "Много голям", "solid": "Солиден", "hachure": "Хералдика", - "crossHatch": "", + "crossHatch": "Двойно-пресечено", "thin": "Тънък", "bold": "Ясно очертан", "left": "Ляво", @@ -60,7 +61,7 @@ "architect": "Архитект", "artist": "Художник", "cartoonist": "Карикатурист", - "fileTitle": "", + "fileTitle": "Заглавие на файл", "colorPicker": "Избор на цвят", "canvasBackground": "Фон на платно", "drawingCanvas": "Платно за рисуване", @@ -69,29 +70,28 @@ "language": "Език", "createRoom": "Споделете сесия за сътрудничество на живо", "duplicateSelection": "Дублирай", - "untitled": "", + "untitled": "Неозаглавено", "name": "Име", - "yourName": "", - "madeWithExcalidraw": "", - "group": "", - "ungroup": "", - "collaborators": "", - "toggleGridMode": "", - "toggleStats": "", - "addToLibrary": "", - "removeFromLibrary": "", - "libraryLoadingMessage": "", - "libraries": "", - "loadingScene": "", - "align": "", - "alignTop": "", - "alignBottom": "", - "alignLeft": "", - "alignRight": "", - "centerVertically": "", - "centerHorizontally": "", - "distributeHorizontally": "", - "distributeVertically": "" + "yourName": "Вашето име", + "madeWithExcalidraw": "Направено с Excalidraw", + "group": "Групирай селекцията", + "ungroup": "Спри групирането на селекцията", + "collaborators": "Сътрудници", + "gridMode": "Решетъчен режим", + "addToLibrary": "Добавяне към библиотеката", + "removeFromLibrary": "Премахване от библиотеката", + "libraryLoadingMessage": "Зареждане на библиотеката...", + "libraries": "Разглеждане на библиотеките", + "loadingScene": "Зареждане на сцена...", + "align": "Подравняване", + "alignTop": "Подравняване отгоре", + "alignBottom": "Подравняване отдолу", + "alignLeft": "Подравняване отляво", + "alignRight": "Подравняване отдясно", + "centerVertically": "Центрирай вертикално", + "centerHorizontally": "Центрирай хоризонтално", + "distributeHorizontally": "Разпредели хоризонтално", + "distributeVertically": "Разпредели вертикално" }, "buttons": { "clearReset": "Нулиране на платно", @@ -100,7 +100,7 @@ "exportToSvg": "Изнасяне в SVG", "copyToClipboard": "Копиране в клипборда", "copyPngToClipboard": "Копирай PNG в клипборда", - "scale": "", + "scale": "Мащаб", "save": "Запази", "saveAs": "Запиши като", "load": "Зареждане", @@ -118,37 +118,38 @@ "redo": "Повтори", "roomDialog": "Започнете сътрудничество на живо", "createNewRoom": "Създай нова стая", - "toggleFullScreen": "Превключване на цял екран", - "toggleDarkMode": "", - "toggleZenMode": "", - "exitZenMode": "" + "fullScreen": "На цял екран", + "darkMode": "Тъмен режим", + "lightMode": "Светъл режим", + "zenMode": "Режим Zen", + "exitZenMode": "Спиране на Zen режим" }, "alerts": { "clearReset": "Това ще изчисти цялото платно. Сигурни ли сте?", "couldNotCreateShareableLink": "Връзката не може да бъде създадена.", - "couldNotCreateShareableLinkTooBig": "", + "couldNotCreateShareableLinkTooBig": "Не може да се създаде връзка за споделяне: сцената е твърде голяма", "couldNotLoadInvalidFile": "Невалиден файл не може да се зареди", "importBackendFailed": "Импортирането от бекенд не беше успешно.", "cannotExportEmptyCanvas": "Не може да се експортира празно платно.", "couldNotCopyToClipboard": "Неуспешно копиране в клипборда. Опитайте да използвате браузъра Chrome.", "decryptFailed": "Данните не можаха да се дешифрират.", "uploadedSecurly": "Качването е защитено с криптиране от край до край, което означава, че сървърът Excalidraw и трети страни не могат да четат съдържанието.", - "loadSceneOverridePrompt": "", - "errorLoadingLibrary": "", - "confirmAddLibrary": "", - "imageDoesNotContainScene": "", - "cannotRestoreFromImage": "" + "loadSceneOverridePrompt": "Зареждането на външна рисунка ще презапише настоящото ви съдържание. Желаете ли да продължите?", + "errorLoadingLibrary": "Възникна грешка при зареждането на външна библиотека.", + "confirmAddLibrary": "Ще се добавят {{numShapes}} фигура(и) във вашата библиотека. Сигурни ли сте?", + "imageDoesNotContainScene": "Импортирането на картинки не се поддържва в момента.\n\nИскате да импортнете сцена? Тази картинка не съдържа данни от сцена. Разрешили ли сте последното при експортирането?", + "cannotRestoreFromImage": "Не може да бъде възстановена сцена от този файл" }, "toolBar": { "selection": "Селекция", - "draw": "", + "draw": "Рисуване", "rectangle": "Правоъгълник", "diamond": "Диамант", "ellipse": "Елипс", "arrow": "Стрелка", "line": "Линия", "text": "Текст", - "library": "", + "library": "Библиотека", "lock": "Поддържайте избрания инструмент активен след рисуване" }, "headings": { @@ -158,19 +159,20 @@ }, "hints": { "linearElement": "Кликнете, за да стартирате няколко точки, плъзнете за една линия", - "freeDraw": "", - "text": "", + "freeDraw": "Натиснете и влачете, пуснете като сте готови", + "text": "Подсказка: Можете също да добавите текст като натиснете някъде два път с инструмента за селекция", "linearElementMulti": "Кликнете върху последната точка или натиснете Escape или Enter, за да завършите", - "resize": "", + "lockAngle": "Можете да ограничите ъгъла, като задържите SHIFT", + "resize": "Може да ограничите при преоразмеряване като задържите SHIFT,\nзадръжте ALT за преоразмерите през центъра", "rotate": "Можете да ограничите ъглите, като държите SHIFT, докато се въртите", - "lineEditor_info": "", - "lineEditor_pointSelected": "", - "lineEditor_nothingSelected": "" + "lineEditor_info": "Кликнете два пъти или натиснете Enter за да промените точките", + "lineEditor_pointSelected": "Натиснете Delete за да изтриете точка, CtrlOrCmd+D за дуплициране, или извлачете за да преместите", + "lineEditor_nothingSelected": "Изберете точка за местене или изтриване, или пък задръжте Alt и натиснете за да добавите нови точки" }, "canvasError": { - "cannotShowPreview": "", - "canvasTooBig": "", - "canvasTooBigTip": "" + "cannotShowPreview": "Невъзможност за показване на preview", + "canvasTooBig": "Платното е твърде голямо.", + "canvasTooBigTip": "Подсказка: пробвайте да приближите далечните елементи по-близко." }, "errorSplash": { "headingMain_pre": "Среща грешка. Опитайте ", @@ -192,7 +194,7 @@ "button_stopSession": "Стоп на сесията", "desc_inProgressIntro": "Сесията за сътрудничество на живо е в ход.", "desc_shareLink": "Споделете тази връзка с всеки, с когото искате да си сътрудничите:", - "desc_exitSession": "" + "desc_exitSession": "Спирането на сесията ще ви изключи от стаята, но ще можете да продължите да работите със сцената, локално. Имайте предвид, че това няма да засегне други хора и те все още ще могат да си сътрудничат с тяхната версия." }, "errorDialog": { "title": "Грешка" @@ -212,23 +214,23 @@ "github": "Намерихте проблем? Изпратете", "textNewLine": "Добавяне на нов ред (текст)", "textFinish": "Завършете редактиране (текст)", - "zoomToFit": "", - "zoomToSelection": "", - "preventBinding": "" + "zoomToFit": "Приближи докато се виждат всички елементи", + "zoomToSelection": "Приближи селекцията", + "preventBinding": "Спри прилепяне на стрелките" }, "encrypted": { - "tooltip": "" + "tooltip": "Вашите рисунки са криптирани от край до край, така че сървърите на Excalidraw няма да могат да ги виждат." }, "stats": { - "angle": "", - "element": "", - "elements": "", - "height": "", - "scene": "", - "selected": "", - "storage": "", - "title": "", - "total": "", - "width": "" + "angle": "Ъгъл", + "element": "Елемент", + "elements": "Елементи", + "height": "Височина", + "scene": "Сцена", + "selected": "Селектирано", + "storage": "Съхранение на данни", + "title": "Статистика за хакери", + "total": "Общо", + "width": "Широчина" } } diff --git a/src/locales/ca-ES.json b/src/locales/ca-ES.json index c352d9f8f..9fedba288 100644 --- a/src/locales/ca-ES.json +++ b/src/locales/ca-ES.json @@ -1,10 +1,11 @@ { "labels": { "paste": "Enganxar", + "pasteCharts": "Enganxar diagrames", "selectAll": "Seleccionar tot", "multiSelect": "Afegir element a la selecció", "moveCanvas": "Moure el llenç", - "cut": "", + "cut": "Tallar", "copy": "Copiar", "copyAsPng": "Copiar al porta-retalls com a PNG", "copyAsSvg": "Copiar al porta-retalls com a SVG", @@ -29,17 +30,17 @@ "edges": "Vores", "sharp": "Agut", "round": "Arrodonit", - "arrowheads": "", - "arrowhead_none": "", - "arrowhead_arrow": "", - "arrowhead_bar": "", - "arrowhead_dot": "", + "arrowheads": "Punta de fletxa", + "arrowhead_none": "Cap", + "arrowhead_arrow": "Fletxa", + "arrowhead_bar": "Línia", + "arrowhead_dot": "Punt", "fontSize": "Mida de lletra", "fontFamily": "Tipus de lletra", "onlySelected": "Només seleccionats", "withBackground": "Amb fons", - "exportEmbedScene": "", - "exportEmbedScene_details": "", + "exportEmbedScene": "Incrustar escena al fitxer exportat", + "exportEmbedScene_details": "Les dades de l’escena es desaran al fitxer PNG/SVG exportat de manera que es pugui restaurar l’escena.\nAugmentarà la mida del fitxer exportat.", "addWatermark": "Afegir \"Fet amb Excalidraw\"", "handDrawn": "Dibuixat a mà", "normal": "Normal", @@ -60,38 +61,37 @@ "architect": "Arquitecte", "artist": "Artista", "cartoonist": "Dibuixant", - "fileTitle": "", + "fileTitle": "Títol de fitxer", "colorPicker": "Selector de colors", - "canvasBackground": "Fons de la tela", - "drawingCanvas": "Tela de dibuix", + "canvasBackground": "Fons del llenç", + "drawingCanvas": "Llenç de dibuix", "layers": "Capes", "actions": "Accions", "language": "Llengua", "createRoom": "Compartir una sessió de col·laboració en directe", "duplicateSelection": "Duplicar", - "untitled": "", + "untitled": "Sense títol", "name": "Nom", "yourName": "El teu nom", "madeWithExcalidraw": "Fet amb Excalidraw", "group": "Agrupar la selecció", "ungroup": "Desagrupar la selecció", "collaborators": "Col·laboradors", - "toggleGridMode": "Commutar línies de graella", - "toggleStats": "", + "gridMode": "Mode quadrícula", "addToLibrary": "Afegir a la biblioteca", "removeFromLibrary": "Eliminar de la biblioteca", "libraryLoadingMessage": "Carregant la biblioteca...", - "libraries": "", - "loadingScene": "Carregant escena ...", - "align": "", - "alignTop": "", - "alignBottom": "", - "alignLeft": "", - "alignRight": "", - "centerVertically": "", - "centerHorizontally": "", - "distributeHorizontally": "", - "distributeVertically": "" + "libraries": "Explorar biblioteques", + "loadingScene": "Carregant escena...", + "align": "Alinear", + "alignTop": "Alinear a dalt", + "alignBottom": "Alinear a baix", + "alignLeft": "Alinear a l’esquerra", + "alignRight": "Alinear a la dreta", + "centerVertically": "Centrar verticalment", + "centerHorizontally": "Centrar horitzontalment", + "distributeHorizontally": "Distribuir horitzontalment", + "distributeVertically": "Distribuir verticalment" }, "buttons": { "clearReset": "Netejar el llenç", @@ -118,15 +118,16 @@ "redo": "Refer", "roomDialog": "Començar col·laboració en directe", "createNewRoom": "Crear sala nova", - "toggleFullScreen": "Commutar pantalla completa", - "toggleDarkMode": "Commutar modo fosc", - "toggleZenMode": "Commutar modo zen", + "fullScreen": "Pantalla completa", + "darkMode": "Mode fosc", + "lightMode": "Mode clar", + "zenMode": "Mode Zen", "exitZenMode": "Sortir de modo zen" }, "alerts": { "clearReset": "Tot el llenç s'esborrarà. Estàs segur?", "couldNotCreateShareableLink": "No s'ha pogut crear un enllaç per compartir.", - "couldNotCreateShareableLinkTooBig": "", + "couldNotCreateShareableLinkTooBig": "No s’ha pogut crear un enllaç compartible: l’escena és massa gran", "couldNotLoadInvalidFile": "No s'ha pogut carregar un fitxer no vàlid", "importBackendFailed": "Importació fallida.", "cannotExportEmptyCanvas": "No es pot exportar un llenç buit.", @@ -136,8 +137,8 @@ "loadSceneOverridePrompt": "Si carregas aquest dibuix extern, substituirá el que tens. Vols continuar?", "errorLoadingLibrary": "S'ha produït un error en carregar la biblioteca de tercers.", "confirmAddLibrary": "Això afegirà {{numShapes}} forma(es) a la vostra biblioteca. Estàs segur?", - "imageDoesNotContainScene": "", - "cannotRestoreFromImage": "" + "imageDoesNotContainScene": "En aquest moment no s’admet la importació d’imatges.\n\nVolies importar una escena? Sembla que aquesta imatge no conté cap dada d’escena. Ho has activat durant l'exportació?", + "cannotRestoreFromImage": "L’escena no s’ha pogut restaurar des d’aquest fitxer d’imatge" }, "toolBar": { "selection": "Selecció", @@ -161,6 +162,7 @@ "freeDraw": "Fer clic i arrosegar, deixar anar al punt final", "text": "Consell: també pots afegir text fent doble clic a qualsevol lloc amb l'eina de selecció", "linearElementMulti": "Fer clic a l'ultim punt, o polsar Escape o Enter per acabar", + "lockAngle": "Pots restringir l’angle mantenint premuda MAJÚS", "resize": "Per restringir les proporcions mentres es canvia la mida, mantenir premut el majúscul (SHIFT); per canviar la mida des del centre, mantenir premut ALT", "rotate": "Per restringir els angles mentre gira, mantenir premut el majúscul (SHIFT)", "lineEditor_info": "Fes doble clic o premi Enter per editar punts", @@ -168,9 +170,9 @@ "lineEditor_nothingSelected": "Selecciona un punt per moure o eliminar, o manté premut Alt i fes clic per afegir punts nous" }, "canvasError": { - "cannotShowPreview": "", - "canvasTooBig": "", - "canvasTooBigTip": "" + "cannotShowPreview": "No es pot mostrar la vista prèvia", + "canvasTooBig": "El llenç pot ser massa gran.", + "canvasTooBigTip": "Consell: prova d’acostar una mica els elements més allunyats." }, "errorSplash": { "headingMain_pre": "S'ha produït un error. Intentar ", @@ -213,22 +215,22 @@ "textNewLine": "Afegir línea nova (text)", "textFinish": "Acabar d'editar (text)", "zoomToFit": "Zoom per veure tots els elements", - "zoomToSelection": "", + "zoomToSelection": "Amplia la selecció", "preventBinding": "Prevenir vinculació de la fletxa" }, "encrypted": { "tooltip": "Els vostres dibuixos estan xifrats de punta a punta de manera que els servidors d’Excalidraw no els veuran mai." }, "stats": { - "angle": "", - "element": "", - "elements": "", - "height": "", - "scene": "", - "selected": "", - "storage": "", - "title": "", - "total": "", - "width": "" + "angle": "Angle", + "element": "Element", + "elements": "Elements", + "height": "Altura", + "scene": "Escena", + "selected": "Seleccionat", + "storage": "Emmagatzematge", + "title": "Estadístiques per nerds", + "total": "Total", + "width": "Amplada" } } diff --git a/src/locales/de-DE.json b/src/locales/de-DE.json index 34bbd3beb..15f420b88 100644 --- a/src/locales/de-DE.json +++ b/src/locales/de-DE.json @@ -1,6 +1,7 @@ { "labels": { "paste": "Einfügen", + "pasteCharts": "Diagramme einfügen", "selectAll": "Alle auswählen", "multiSelect": "Element zur Auswahl hinzufügen", "moveCanvas": "Leinwand verschieben", @@ -76,8 +77,7 @@ "group": "Auswahl gruppieren", "ungroup": "Gruppierung aufheben", "collaborators": "Mitarbeitende", - "toggleGridMode": "Gitterlinien ein-/ausschalten", - "toggleStats": "Statistiken für Nerds ein-/ausschalten", + "gridMode": "Rastermodus", "addToLibrary": "Zur Bibliothek hinzufügen", "removeFromLibrary": "Aus Bibliothek entfernen", "libraryLoadingMessage": "Lade Bibliothek...", @@ -118,9 +118,10 @@ "redo": "Wiederholen", "roomDialog": "Live-Kollaborationssitzung starten", "createNewRoom": "Neuen Raum erstellen", - "toggleFullScreen": "Vollbild umschalten", - "toggleDarkMode": "Dunkles Design umschalten", - "toggleZenMode": "Zen-Modus umschalten", + "fullScreen": "Vollbildanzeige", + "darkMode": "Dunkles Design", + "lightMode": "Helles Design", + "zenMode": "Zen-Modus", "exitZenMode": "Zen-Modus verlassen" }, "alerts": { @@ -136,7 +137,7 @@ "loadSceneOverridePrompt": "Das Laden der externen Zeichnung ersetzt den vorhandenen Inhalt. Möchtest Du fortfahren?", "errorLoadingLibrary": "Beim Laden der Drittanbieter-Bibliothek ist ein Fehler aufgetreten.", "confirmAddLibrary": "Dieses fügt {{numShapes}} Form(en) zu deiner Bibliothek hinzu. Bist du sicher?", - "imageDoesNotContainScene": "Bilddatei enthält keine Zeichnungsdaten. Hast du das Einbetten beim Export aktiviert?", + "imageDoesNotContainScene": "Das Importieren von Bildern wird derzeit nicht unterstützt.\n\nMöchtest du eine Szene importieren? Dieses Bild scheint keine Zeichnungsdaten zu enthalten. Hast du dies beim Exportieren aktiviert?", "cannotRestoreFromImage": "Die Zeichnung konnte aus dieser Bilddatei nicht wiederhergestellt werden" }, "toolBar": { @@ -161,6 +162,7 @@ "freeDraw": "Klicke und ziehe. Lass los, wenn du fertig bist", "text": "Tipp: Du kannst auch Text hinzufügen indem Du mit dem Auswahlwerkzeug auf eine beliebige Stelle doppelklickst", "linearElementMulti": "Zum Beenden auf den letzten Punkt klicken oder Escape oder Eingabe drücken", + "lockAngle": "Du kannst Winkel einschränken, indem du SHIFT gedrückt hältst", "resize": "Du kannst die Proportionen einschränken, indem du SHIFT während der Größenänderung gedrückt hältst. Halte ALT gedrückt, um die Größe vom Zentrum aus zu ändern", "rotate": "Du kannst Winkel einschränken, indem du SHIFT während der Drehung gedrückt hältst", "lineEditor_info": "Doppelklicken oder Eingabetaste drücken, um Punkte zu bearbeiten", @@ -213,7 +215,7 @@ "textNewLine": "Neue Zeile hinzufügen (Text)", "textFinish": "Bearbeiten beenden (Text)", "zoomToFit": "Zoomen um alle Elemente einzupassen", - "zoomToSelection": "", + "zoomToSelection": "Zoomauswahl", "preventBinding": "Pfeil-Bindung verhindern" }, "encrypted": { diff --git a/src/locales/el-GR.json b/src/locales/el-GR.json index 3a0894a12..5c91f44b3 100644 --- a/src/locales/el-GR.json +++ b/src/locales/el-GR.json @@ -1,6 +1,7 @@ { "labels": { "paste": "Επικόλληση", + "pasteCharts": "Επικόλληση γραφημάτων", "selectAll": "Επιλογή όλων", "multiSelect": "Προσθέστε το στοιχείο στην επιλογή", "moveCanvas": "Μετακίνηση καμβά", @@ -37,7 +38,7 @@ "fontSize": "Μέγεθος γραμματοσειράς", "fontFamily": "Γραμματοσειρά", "onlySelected": "Μόνο τα Επιλεγμένα", - "withBackground": "Με Φόντο", + "withBackground": "Με φόντο", "exportEmbedScene": "Ενσωμάτωση της σκηνής στο αρχείο προς εξαγωγή", "exportEmbedScene_details": "Τα δεδομένα σκηνής θα αποθηκευτούν στο αρχείο PNG/SVG προς εξαγωγή ώστε η σκηνή να είναι δυνατό να αποκατασταθεί από αυτό.\nΘα αυξήσει το μέγεθος του αρχείου προς εξαγωγή.", "addWatermark": "Προσθήκη \"Φτιαγμένο με Excalidraw\"", @@ -76,8 +77,7 @@ "group": "Δημιουργία ομάδας από επιλογή", "ungroup": "Κατάργηση ομάδας από επιλογή", "collaborators": "Συνεργάτες", - "toggleGridMode": "Εναλλαγή λειτουργίας πλέγματος", - "toggleStats": "", + "gridMode": "Εμφάνιση σε πλέγμα", "addToLibrary": "Προσθήκη στη βιβλιοθήκη", "removeFromLibrary": "Αφαίρεση από τη βιβλιοθήκη", "libraryLoadingMessage": "Φόρτωση βιβλιοθήκης...", @@ -90,8 +90,8 @@ "alignRight": "Στοίχιση δεξιά", "centerVertically": "Κέντρο κάθετα", "centerHorizontally": "Κέντρο οριζόντια", - "distributeHorizontally": "", - "distributeVertically": "" + "distributeHorizontally": "Οριζόντια κατανομή", + "distributeVertically": "Κατακόρυφη κατανομή" }, "buttons": { "clearReset": "Επαναφορά του καμβά", @@ -118,15 +118,16 @@ "redo": "Επαναφορά", "roomDialog": "Έναρξη ζωντανής συνεργασίας", "createNewRoom": "Δημιουργία νέου χώρου", - "toggleFullScreen": "Εναλλαγή πλήρους οθόνης", - "toggleDarkMode": "Εναλλαγή εμφάνισης σε dark", - "toggleZenMode": "Εναλλαγή λειτουργίας Zen", + "fullScreen": "Πλήρης οθόνη", + "darkMode": "Σκοτεινή λειτουργία", + "lightMode": "Φωτεινή λειτουργία", + "zenMode": "Λειτουργία Zεν", "exitZenMode": "Έξοδος απο την λειτουργία Zen" }, "alerts": { "clearReset": "Αυτό θα σβήσει ολόκληρο τον καμβά. Είσαι σίγουρος;", "couldNotCreateShareableLink": "Δεν ήταν δυνατή η δημιουργία συνδέσμου κοινής χρήσης.", - "couldNotCreateShareableLinkTooBig": "", + "couldNotCreateShareableLinkTooBig": "Δεν ήταν δυνατή η δημιουργία κοινόχρηστου συνδέσμου: η σκηνή είναι πολύ μεγάλη", "couldNotLoadInvalidFile": "Δεν μπόρεσε να ανοίξει εσφαλμένο αρχείο", "importBackendFailed": "Η εισαγωγή από το backend απέτυχε.", "cannotExportEmptyCanvas": "Δεν είναι δυνατή η εξαγωγή κενού καμβά.", @@ -136,7 +137,7 @@ "loadSceneOverridePrompt": "Η φόρτωση εξωτερικού σχεδίου θα αντικαταστήσει το υπάρχον περιεχόμενο. Επιθυμείτε να συνεχίσετε;", "errorLoadingLibrary": "Υπήρξε ένα σφάλμα κατά τη φόρτωση της βιβλιοθήκης τρίτου μέρους.", "confirmAddLibrary": "Αυτό θα προσθέσει {{numShapes}} σχήμα(τα) στη βιβιλιοθήκη σας. Είστε σίγουροι;", - "imageDoesNotContainScene": "Το αρχείο εικόνας δεν έχει δεδομένα σκηνής. Το είχατε ενεργοποιήσει αυτό κατά την εξαγωγή;", + "imageDoesNotContainScene": "Η εισαγωγή εικόνων δεν υποστηρίζεται αυτή τη στιγμή.\n\nΜήπως θέλετε να εισαγάγετε μια σκηνή; Αυτή η εικόνα δεν φαίνεται να περιέχει δεδομένα σκηνής. Έχετε ενεργοποιήσει αυτό κατά την εξαγωγή;", "cannotRestoreFromImage": "Η σκηνή δεν ήταν δυνατό να αποκατασταθεί από αυτό το αρχείο εικόνας" }, "toolBar": { @@ -161,6 +162,7 @@ "freeDraw": "Κάντε κλικ και σύρατε, απελευθερώσατε όταν έχετε τελειώσει", "text": "Tip: μπορείτε επίσης να προσθέστε κείμενο με διπλό-κλικ οπουδήποτε με το εργαλείο επιλογών", "linearElementMulti": "Κάνε κλικ στο τελευταίο σημείο ή πάτησε Escape ή Enter για να τελειώσεις", + "lockAngle": "Μπορείτε να περιορίσετε τη γωνία κρατώντας πατημένο το SHIFT", "resize": "Μπορείς να περιορίσεις τις αναλογίες κρατώντας το SHIFT ενώ αλλάζεις μέγεθος,\nκράτησε πατημένο το ALT για αλλαγή μεγέθους από το κέντρο", "rotate": "Μπορείς να περιορίσεις τις γωνίες κρατώντας πατημένο το πλήκτρο SHIFT κατά την περιστροφή", "lineEditor_info": "Διπλό-κλικ ή πιέστε Enter για να επεξεργαστείτε τα σημεία", @@ -168,9 +170,9 @@ "lineEditor_nothingSelected": "Επιλέξτε ένα σημείο για μετακίνηση ή αφαίρεση, ή κρατήστε παρατεταμένα το Alt και κάντε κλικ για να προσθέσετε νέα σημεία" }, "canvasError": { - "cannotShowPreview": "", - "canvasTooBig": "", - "canvasTooBigTip": "" + "cannotShowPreview": "Αδυναμία εμφάνισης προεπισκόπησης", + "canvasTooBig": "Ο καμβάς μπορεί να είναι μεγάλος.", + "canvasTooBigTip": "Συμβουλή: προσπαθήστε να μετακινήσετε τα πιο απομακρυσμένα στοιχεία λίγο πιο κοντά μαζί." }, "errorSplash": { "headingMain_pre": "Συνέβη κάποιο σφάλμα. Προσπάθησε ", @@ -213,7 +215,7 @@ "textNewLine": "Προσθήκη νέας γραμμής (κείμενο)", "textFinish": "Ολοκλήρωση επεξεργασίας (κείμενο)", "zoomToFit": "Zoom ώστε να χωρέσουν όλα τα στοιχεία", - "zoomToSelection": "", + "zoomToSelection": "Εστίαση στην επιλογή", "preventBinding": "Αποτροπή δέσμευσης βέλων" }, "encrypted": { @@ -224,10 +226,10 @@ "element": "Στοιχείο", "elements": "Στοιχεία", "height": "Ύψος", - "scene": "", + "scene": "Σκηνή", "selected": "Επιλεγμένα", "storage": "Χώρος", - "title": "", + "title": "Στατιστικά για σπασίκλες", "total": "Σύνολο ", "width": "Πλάτος" } diff --git a/src/locales/en.json b/src/locales/en.json index 6f16fc986..b48b10565 100644 --- a/src/locales/en.json +++ b/src/locales/en.json @@ -1,6 +1,7 @@ { "labels": { "paste": "Paste", + "pasteCharts": "Paste charts", "selectAll": "Select all", "multiSelect": "Add element to selection", "moveCanvas": "Move canvas", diff --git a/src/locales/es-ES.json b/src/locales/es-ES.json index ae311c457..f83d779b4 100644 --- a/src/locales/es-ES.json +++ b/src/locales/es-ES.json @@ -1,10 +1,11 @@ { "labels": { "paste": "Pegar", + "pasteCharts": "Pegar gráficos", "selectAll": "Seleccionar todo", "multiSelect": "Añadir elemento a la selección", "moveCanvas": "Mover el lienzo", - "cut": "", + "cut": "Cortar", "copy": "Copiar", "copyAsPng": "Copiar al portapapeles como PNG", "copyAsSvg": "Copiar al portapapeles como SVG", @@ -21,7 +22,7 @@ "strokeWidth": "Grosor del trazo", "strokeStyle": "Estilo del trazo", "strokeStyle_solid": "Sólido", - "strokeStyle_dashed": "Linea discontinua", + "strokeStyle_dashed": "Discontinua", "strokeStyle_dotted": "Punteado", "sloppiness": "Estilo de trazo", "opacity": "Opacidad", @@ -29,17 +30,17 @@ "edges": "Bordes", "sharp": "Afilado", "round": "Redondo", - "arrowheads": "", - "arrowhead_none": "", - "arrowhead_arrow": "", - "arrowhead_bar": "", - "arrowhead_dot": "", + "arrowheads": "Puntas de flecha", + "arrowhead_none": "Ninguna", + "arrowhead_arrow": "Flecha", + "arrowhead_bar": "Barra", + "arrowhead_dot": "Punto", "fontSize": "Tamaño de la fuente", "fontFamily": "Tipo de fuente", "onlySelected": "Sólo seleccionados", "withBackground": "Con fondo", - "exportEmbedScene": "", - "exportEmbedScene_details": "", + "exportEmbedScene": "Insertar escena en el archivo exportado", + "exportEmbedScene_details": "Los datos de escena se guardarán en el archivo PNG/SVG exportado, así la escena puede ser restaurada de la misma.\nEsto aumentará el tamaño del archivo exportado.", "addWatermark": "Agregar \"Hecho con Excalidraw\"", "handDrawn": "Dibujado a mano", "normal": "Normal", @@ -60,7 +61,7 @@ "architect": "Arquitecto", "artist": "Artista", "cartoonist": "Caricatura", - "fileTitle": "", + "fileTitle": "Título del archivo", "colorPicker": "Selector de color", "canvasBackground": "Fondo del lienzo", "drawingCanvas": "Lienzo de dibujo", @@ -69,29 +70,28 @@ "language": "Idioma", "createRoom": "Compartir una sesión de colaboración en vivo", "duplicateSelection": "Duplicar", - "untitled": "", + "untitled": "Sin título", "name": "Nombre", "yourName": "Tu nombre", "madeWithExcalidraw": "Hecho con Excalidraw", - "group": "Selección de grupo", - "ungroup": "Desagrupar", + "group": "Agrupar selección", + "ungroup": "Desagrupar selección", "collaborators": "Colaboradores", - "toggleGridMode": "Alternar modo cuadrícula", - "toggleStats": "", + "gridMode": "Modo cuadrícula", "addToLibrary": "Añadir a la biblioteca", "removeFromLibrary": "Eliminar de la biblioteca", "libraryLoadingMessage": "Cargando biblioteca...", - "libraries": "", + "libraries": "Explorar bibliotecas", "loadingScene": "Cargando escena...", - "align": "", - "alignTop": "", - "alignBottom": "", - "alignLeft": "", - "alignRight": "", - "centerVertically": "", - "centerHorizontally": "", - "distributeHorizontally": "", - "distributeVertically": "" + "align": "Alinear", + "alignTop": "Alineación superior", + "alignBottom": "Alineación inferior", + "alignLeft": "Alinear a la izquierda", + "alignRight": "Alinear a la derecha", + "centerVertically": "Centrar verticalmente", + "centerHorizontally": "Centrar horizontalmente", + "distributeHorizontally": "Distribuir horizontalmente", + "distributeVertically": "Distribuir verticalmente" }, "buttons": { "clearReset": "Limpiar lienzo y reiniciar el color de fondo", @@ -100,7 +100,7 @@ "exportToSvg": "Exportar a SVG", "copyToClipboard": "Copiar al portapapeles", "copyPngToClipboard": "Copiar PNG al portapapeles", - "scale": "Escala", + "scale": "Escalar", "save": "Guardar", "saveAs": "Guardar como", "load": "Cargar", @@ -110,7 +110,7 @@ "scrollBackToContent": "Volver al contenido", "zoomIn": "Acercarse", "zoomOut": "Alejarse", - "resetZoom": "Restablecer zoom", + "resetZoom": "Restablecer acercamiento", "menu": "Menú", "done": "Hecho", "edit": "Editar", @@ -118,26 +118,27 @@ "redo": "Rehacer", "roomDialog": "Iniciar colaboración en vivo", "createNewRoom": "Crear nueva sala", - "toggleFullScreen": "Alternar pantalla completa", - "toggleDarkMode": "Cambiar a modo oscuro", - "toggleZenMode": "Alternar modo zen", + "fullScreen": "Pantalla completa", + "darkMode": "Modo oscuro", + "lightMode": "Modo claro", + "zenMode": "Modo Zen", "exitZenMode": "Salir del modo Zen" }, "alerts": { "clearReset": "Esto limpiará todo el lienzo. Estás seguro?", "couldNotCreateShareableLink": "No se pudo crear un enlace para compartir.", - "couldNotCreateShareableLinkTooBig": "", - "couldNotLoadInvalidFile": "No se pudo cargar el archivo inválido", + "couldNotCreateShareableLinkTooBig": "No se pudo crear el enlace para compartir: la escena es demasiado grande", + "couldNotLoadInvalidFile": "No se pudo cargar el archivo no válido", "importBackendFailed": "La importación falló.", "cannotExportEmptyCanvas": "No se puede exportar un lienzo vació", "couldNotCopyToClipboard": "No se ha podido copiar al portapapeles, intente usar Chrome como navegador.", "decryptFailed": "No se pudieron descifrar los datos.", - "uploadedSecurly": "La carga ha sido asegurada con cifrado de extremo a extremo, lo que significa que el servidor de Excalidraw y terceros no pueden leer el contenido.", + "uploadedSecurly": "La carga ha sido asegurada con cifrado de principio a fin, lo que significa que el servidor de Excalidraw y terceros no pueden leer el contenido.", "loadSceneOverridePrompt": "Si carga este dibujo externo, reemplazará el que tiene. ¿Desea continuar?", "errorLoadingLibrary": "Se ha producido un error al cargar la biblioteca de terceros.", "confirmAddLibrary": "Esto añadirá {{numShapes}} forma(s) a tu biblioteca. ¿Estás seguro?", - "imageDoesNotContainScene": "", - "cannotRestoreFromImage": "" + "imageDoesNotContainScene": "La importación de imágenes no está homologada en este momento.\n\n¿Deseas importar una escena? Esta imagen no parece contener ningún dato de escena. ¿Lo has activado durante la exportación?", + "cannotRestoreFromImage": "No se pudo restaurar la escena desde este archivo de imagen" }, "toolBar": { "selection": "Selección", @@ -157,42 +158,43 @@ "shapes": "Formas" }, "hints": { - "linearElement": "Haga clic para dibujar multiples puntos o arrastre para una sola línea", + "linearElement": "Haz clic para dibujar múltiples puntos, arrastrar para solo una línea", "freeDraw": "Haz clic y arrastra, suelta al terminar", "text": "Consejo: también puedes añadir texto haciendo doble clic en cualquier lugar con la herramienta de selección", - "linearElementMulti": "Haga clic en el último punto o pulse Escape o Enter para finalizar", + "linearElementMulti": "Haz clic en el último punto o presiona Escape o Enter para finalizar", + "lockAngle": "Puedes restringir el ángulo manteniendo presionado el botón SHIFT", "resize": "Para mantener las proporciones mantén SHIFT presionado mientras modificas el tamaño, \nmantén presionado ALT para modificar el tamaño desde el centro", - "rotate": "Puede restringir los ángulos manteniendo presionado SHIFT mientras gira", - "lineEditor_info": "haga doble clic o pulse Enter para editar puntos", + "rotate": "Puedes restringir los ángulos manteniendo presionado SHIFT mientras giras", + "lineEditor_info": "Doble clic o pulse Enter para editar puntos", "lineEditor_pointSelected": "Presione Suprimir para eliminar el punto, CtrlOrCmd+D para duplicarlo, o arrástrelo para moverlo", - "lineEditor_nothingSelected": "Seleccione un punto para mover o eliminar, o mantenga pulsado Alt y haga clic para añadir nuevos puntos" + "lineEditor_nothingSelected": "Selecciona un punto sea para mover o eliminar, o mantén pulsado Alt y haz clic para añadir nuevos puntos" }, "canvasError": { - "cannotShowPreview": "", - "canvasTooBig": "", - "canvasTooBigTip": "" + "cannotShowPreview": "No se puede mostrar la vista previa", + "canvasTooBig": "El lienzo podría ser demasiado grande.", + "canvasTooBigTip": "Sugerencia: intenta acercar un poco más los elementos más lejanos." }, "errorSplash": { "headingMain_pre": "Se encontró un error. Intente ", "headingMain_button": "recargando la página.", "clearCanvasMessage": "Si la recarga no funciona, intente ", "clearCanvasMessage_button": "limpiando el lienzo.", - "clearCanvasCaveat": " Esto resultará en la pérdida del trabajo ", + "clearCanvasCaveat": " Esto provocará la pérdida de su trabajo ", "trackedToSentry_pre": "El error con el identificador ", "trackedToSentry_post": " fue rastreado en nuestro sistema.", - "openIssueMessage_pre": "Fuimos muy cautelosos para no incluir la información de tu escena en el error. Si tu escena no es privada, por favor considera seguir nuestro ", - "openIssueMessage_button": "seguimiento de errores.", + "openIssueMessage_pre": "Fuimos muy cautelosos de no incluir la información de tu escena en el error. Si tu escena no es privada, por favor considera seguir nuestro ", + "openIssueMessage_button": "rastreador de errores.", "openIssueMessage_post": " Por favor, incluya la siguiente información copiándola y pegándola en el issue de GitHub.", "sceneContent": "Contenido de la escena:" }, "roomDialog": { - "desc_intro": "Puedes invitar a gente a tu escena actual para colaborar contigo.", - "desc_privacy": "No te preocupes, la sesión usa encriptación de extremo a extremo, por lo que todo lo que se dibuje se mantendrá privado. Ni siquiera nuestro servidor podrá ver lo que haces.", + "desc_intro": "Puede invitar a otras personas a tu actual escena para que colaboren contigo.", + "desc_privacy": "No te preocupes, la sesión usa encriptación de punta a punta, por lo que todo lo que se dibuje se mantendrá privadamente. Ni siquiera nuestro servidor podrá ver lo que haces.", "button_startSession": "Iniciar sesión", "button_stopSession": "Detener sesión", "desc_inProgressIntro": "La sesión de colaboración en vivo está ahora en progreso.", - "desc_shareLink": "Comparte este enlace con tus colaboradores:", - "desc_exitSession": "Detener la sesión te desconectará de la sala, pero podrás seguir trabajando con la escena localmente. Ten en cuenta que esto no afectará a otras personas, y que seguirán siendo capaces de colaborar en su versión." + "desc_shareLink": "Comparte este enlace con cualquier persona con quien quieras colaborar:", + "desc_exitSession": "Detener la sesión te desconectará de la sala, pero podrás seguir trabajando con la escena en su computadora, esto es de modo local. Ten en cuenta que esto no afectará a otras personas, y que las mismas seguirán siendo capaces de colaborar en tu escena." }, "errorDialog": { "title": "Error" @@ -201,34 +203,34 @@ "title": "Atajos del teclado", "shapes": "Formas", "or": "o", - "click": "hacer clic", + "click": "clic", "drag": "arrastrar", - "curvedArrow": "Flecha curva", + "curvedArrow": "Flecha curvada", "curvedLine": "Línea curva", "editor": "Editor", "view": "Vista", "blog": "Lee nuestro blog", - "howto": "Sigue nuestras guías", + "howto": "Siga nuestras guías", "github": "¿Has encontrado un problema? Envíalo", "textNewLine": "Añadir nueva línea (texto)", "textFinish": "Finalizar edición (texto)", - "zoomToFit": "Ajustar para mostrar todos los elementos", - "zoomToSelection": "", - "preventBinding": "Evitar enlace de flecha" + "zoomToFit": "Ajustar la vista para mostrar todos los elementos", + "zoomToSelection": "Hacer zoom a la selección", + "preventBinding": "Evitar yuxtaposición de flechas" }, "encrypted": { "tooltip": "Tus dibujos están cifrados de punto a punto, por lo que los servidores de Excalidraw nunca los verán." }, "stats": { - "angle": "", - "element": "", - "elements": "", - "height": "", - "scene": "", - "selected": "", - "storage": "", - "title": "", - "total": "", - "width": "" + "angle": "Ángulo", + "element": "Elemento", + "elements": "Elementos", + "height": "Alto", + "scene": "Escena", + "selected": "Seleccionado", + "storage": "Almacenamiento", + "title": "Estadísticas para nerds", + "total": "Total", + "width": "Ancho" } } diff --git a/src/locales/fa-IR.json b/src/locales/fa-IR.json index 2d2362e23..229949301 100644 --- a/src/locales/fa-IR.json +++ b/src/locales/fa-IR.json @@ -1,10 +1,11 @@ { "labels": { "paste": "جای گذاری", + "pasteCharts": "قراردادن نمودار", "selectAll": "انتخاب همه", "multiSelect": "یک ایتم به انتخاب شده ها اضافه کنید.", "moveCanvas": "بوم را حرکت بدهید", - "cut": "", + "cut": "جابجایی", "copy": "کپی", "copyAsPng": "کپی در حافطه موقت به صورت PNG", "copyAsSvg": "کپی در حافطه موقت به صورت SVG", @@ -13,8 +14,8 @@ "bringToFront": "جلو آوردن", "sendBackward": "پس فرستادن", "delete": "حذف", - "copyStyles": "کپی استایل", - "pasteStyles": "چسباندن استایل", + "copyStyles": "کپی سبک", + "pasteStyles": "جای گذاری سبک", "stroke": "خط", "background": "پس زمینه", "fill": "رنگ آمیزی", @@ -29,11 +30,11 @@ "edges": "لبه ها", "sharp": "تیز", "round": "دور", - "arrowheads": "", - "arrowhead_none": "", - "arrowhead_arrow": "", - "arrowhead_bar": "", - "arrowhead_dot": "", + "arrowheads": "سر پیکان", + "arrowhead_none": "هیچ کدام", + "arrowhead_arrow": "فلش", + "arrowhead_bar": "میله ای", + "arrowhead_dot": "نقطه", "fontSize": "اندازه قلم", "fontFamily": "نوع قلم", "onlySelected": "فقط انتخاب شده ها", @@ -60,7 +61,7 @@ "architect": "معمار", "artist": "هنرمند", "cartoonist": "کارتونیست", - "fileTitle": "", + "fileTitle": "عنوان فایل", "colorPicker": "انتخابگر رنگ", "canvasBackground": "بوم", "drawingCanvas": "بوم نقاشی", @@ -69,19 +70,18 @@ "language": "زبان", "createRoom": "اشتراک گذاری جلسه همکاری زنده", "duplicateSelection": "تکرار", - "untitled": "", + "untitled": "بدون عنوان", "name": "نام", "yourName": "نام شما", "madeWithExcalidraw": "ساخته شده با Excalidraw", "group": "گروهبندی انتخابها", "ungroup": "حذف گروهبندی انتخابها", "collaborators": "همکاران", - "toggleGridMode": "سويچ خطوط راهنما", - "toggleStats": "", + "gridMode": "حالت شبکه ای", "addToLibrary": "افزودن به کتابخانه", "removeFromLibrary": "حذف از کتابخانه", "libraryLoadingMessage": "بارگذاری کتابخانه...", - "libraries": "", + "libraries": "مرور کردن کتابخانه ها", "loadingScene": "باگذاری صحنه...", "align": "تراز", "alignTop": "تراز به بالا", @@ -118,9 +118,10 @@ "redo": "از سر", "roomDialog": "همکاری آنلاین را شروع کنید", "createNewRoom": "ایجاد یک اتاق جدید", - "toggleFullScreen": "تغییر به حالت تمام صفحه", - "toggleDarkMode": "تغییر به حالت تاریک", - "toggleZenMode": "تغییر به حالت تمرکز", + "fullScreen": "تمام‌صفحه", + "darkMode": "حالت تیره", + "lightMode": "حالت روشن", + "zenMode": "حالت ذن", "exitZenMode": "خروج از حالت تمرکز" }, "alerts": { @@ -136,7 +137,7 @@ "loadSceneOverridePrompt": "بارگزاری یک طرح خارجی محتوای فعلی رو از بین میبرد. آیا میخواهید ادامه دهید؟", "errorLoadingLibrary": "خطایی در بارگذاری کتابخانه ثالث وجود داشت.", "confirmAddLibrary": "{{numShapes}} از اشکال به کتابخانه شما اضافه خواهد شد. مطمئن هستید؟", - "imageDoesNotContainScene": "فایل تصویر دارای محتوای صحنه نیست. آیا در هنگام خروجی گرفتن آن را فعال کرده‌اید؟", + "imageDoesNotContainScene": "وارد کردن تصویر در این لحظه امکان پذیر نمی باشد.\nآیا مایل به وارد کردن یک صحنه هستید؟ این تصویر به نظر می رسد که فاقد هرگونه اطلاعاتی مربوط به صحنه باشد. آیا این گزینه را در زمان وارد کردن تصویر فعال کرده اید؟", "cannotRestoreFromImage": "صحنه را نمی توان از این فایل تصویری بازیابی کرد" }, "toolBar": { @@ -161,6 +162,7 @@ "freeDraw": "کلیک کنید و بکشید و وقتی کار تمام شد رها کنید", "text": "نکته: با برنامه انتخاب شده شما میتوانید با دوبار کلیک کردن هرکجا میخواید متن اظاف کنید", "linearElementMulti": "روی آخرین نقطه کلیک کنید یا کلید ESC را بزنید یا کلید Enter را بزنید برای اتمام کار", + "lockAngle": "با نگه داشتن SHIFT هنگام چرخش می توانید زاویه ها را محدود کنید", "resize": "می توانید با نگه داشتن SHIFT در هنگام تغییر اندازه، نسبت ها را محدود کنید،ALT را برای تغییر اندازه از مرکز نگه دارید", "rotate": "با نگه داشتن SHIFT هنگام چرخش می توانید زاویه ها را محدود کنید", "lineEditor_info": "دوبار کلیک کنید یا Enter را فشار دهید تا نقاط را ویرایش کنید", @@ -177,7 +179,7 @@ "headingMain_button": "در حال بازنشانی صفحه.", "clearCanvasMessage": "اگر بازنشانی صفحه مشکل را حل نکرد این را امتحان کنید ", "clearCanvasMessage_button": "در حال تمیز کردن بوم", - "clearCanvasCaveat": " این باعث میشود کارهای شما از بین برود ", + "clearCanvasCaveat": " این باعث میشود کارهای شما ذخیره نشود ", "trackedToSentry_pre": "خطا در شناسه ", "trackedToSentry_post": " در سیستم ما رهگیری شد.", "openIssueMessage_pre": "ما خیلی محتاط هستیم که اطلاعات شما را در خطا قرار ندهیم. با این حال اگر اطلاعات شما خصوصی نیست لطفا پیگیری کنید ", @@ -213,22 +215,22 @@ "textNewLine": "یک خط جدید اضافه کنید (متن)", "textFinish": "پایان ویرایش (متن)", "zoomToFit": "بزرگنمایی برای دیدن تمام آیتم ها", - "zoomToSelection": "", + "zoomToSelection": "بزرگنمایی قسمت انتخاب شده", "preventBinding": "مانع شدن از چسبیدن فلش ها" }, "encrypted": { "tooltip": "شما در یک محیط رمزگزاری شده دو طرفه در حال طراحی هستید پس Excalidraw هرگز طرح های شما را نمیبند." }, "stats": { - "angle": "", - "element": "", - "elements": "", - "height": "", - "scene": "", - "selected": "", - "storage": "", - "title": "", - "total": "", - "width": "" + "angle": "زاویه", + "element": "اِلمان", + "elements": "اِلمان ها", + "height": "ارتفاع", + "scene": "صحنه", + "selected": "انتخاب شده", + "storage": "حافظه", + "title": "آمار برای نردها", + "total": "مجموع", + "width": "عرض" } } diff --git a/src/locales/fi-FI.json b/src/locales/fi-FI.json index 6f9437ed6..da4e000b3 100644 --- a/src/locales/fi-FI.json +++ b/src/locales/fi-FI.json @@ -1,6 +1,7 @@ { "labels": { "paste": "Liitä", + "pasteCharts": "Liitä kaaviot", "selectAll": "Valitse kaikki", "multiSelect": "Lisää kohde valintaan", "moveCanvas": "Siirrä piirtoaluetta", @@ -76,8 +77,7 @@ "group": "Ryhmitä valinta", "ungroup": "Pura valittu ryhmä", "collaborators": "Yhteistyökumppanit", - "toggleGridMode": "Ruudukko päälle/pois", - "toggleStats": "Nörttien tilastot päälle/pois", + "gridMode": "Ruudukkotila", "addToLibrary": "Lisää kirjastoon", "removeFromLibrary": "Poista kirjastosta", "libraryLoadingMessage": "Ladataan kirjastoa...", @@ -118,9 +118,10 @@ "redo": "Tee uudelleen", "roomDialog": "Aloita live-yhteistyö", "createNewRoom": "Luo huone", - "toggleFullScreen": "Koko näytön tila päälle/pois", - "toggleDarkMode": "Pimeä tila päälle/pois", - "toggleZenMode": "Zen-tila päälle", + "fullScreen": "Koko näyttö", + "darkMode": "Tumma tila", + "lightMode": "Vaalea tila", + "zenMode": "Zen-tila", "exitZenMode": "Poistu zen-tilasta" }, "alerts": { @@ -136,7 +137,7 @@ "loadSceneOverridePrompt": "Ulkopuolisen piirroksen lataaminen korvaa nykyisen sisältösi. Haluatko jatkaa?", "errorLoadingLibrary": "Kolmannen osapuolen kirjastoa ladattaessa tapahtui virhe.", "confirmAddLibrary": "Tämä lisää {{numShapes}} muotoa kirjastoosi. Oletko varma?", - "imageDoesNotContainScene": "Kuvatiedosto ei sisällä teostietoja. Valitsitko sisällyttää ne tallennusvaiheessa?", + "imageDoesNotContainScene": "Kuvien lisääminen ei ole tällä hetkellä mahdollista.\n\nHaluatko tuoda piirroksen? Tämä kuva ei näytä sisältävän tarvittavia tietoja. Oletko ottanut piirrostietojen tallennuksen käyttöön viennin aikana?", "cannotRestoreFromImage": "Teosta ei voitu palauttaa tästä kuvatiedostosta" }, "toolBar": { @@ -161,6 +162,7 @@ "freeDraw": "Paina ja raahaa, päästä irti kun olet valmis", "text": "Vinkki: voit myös lisätä tekstiä kaksoisnapsauttamalla mihin tahansa valintatyökalulla", "linearElementMulti": "Klikkaa viimeistä pistettä, paina Escape tai paina Enter lopettaaksesi", + "lockAngle": "Voit rajoittaa kulmaa pitämällä SHIFT pohjassa", "resize": "Voit rajoittaa mittasuhteet pitämällä SHIFT pohjassa kun muutat kokoa, pidä ALT pohjassa muuttaaksesi kokoa keskipisteen suhteen", "rotate": "Voit rajoittaa kulman pitämällä SHIFT pohjassa pyörittäessäsi", "lineEditor_info": "Kaksoisnapauta tai paina Enter muokataksesi pisteitä", diff --git a/src/locales/fr-FR.json b/src/locales/fr-FR.json index b46fe3160..04bc89eae 100644 --- a/src/locales/fr-FR.json +++ b/src/locales/fr-FR.json @@ -1,9 +1,10 @@ { "labels": { "paste": "Coller", + "pasteCharts": "Coller les graphiques", "selectAll": "Tout sélectionner", "multiSelect": "Ajouter l'élément à la sélection", - "moveCanvas": "Déplacer le canvas", + "moveCanvas": "Déplacer le canevas", "cut": "Couper", "copy": "Copier", "copyAsPng": "Copier dans le presse-papier en PNG", @@ -40,7 +41,7 @@ "withBackground": "Avec arrière-plan", "exportEmbedScene": "Intégrer la scène au fichier exporté", "exportEmbedScene_details": "Les données de scène seront enregistrées dans le fichier PNG/SVG exporté, afin que la scène puisse être restaurée à partir de celui-ci.\nCela augmentera la taille du fichier exporté.", - "addWatermark": "Ajouter \"Fabriqué avec Excalidraw\"", + "addWatermark": "Ajouter \"Fait avec Excalidraw\"", "handDrawn": "Manuscrite", "normal": "Normale", "code": "Code", @@ -62,7 +63,7 @@ "cartoonist": "Caricaturiste", "fileTitle": "Titre du fichier", "colorPicker": "Sélecteur de couleur", - "canvasBackground": "Fond du canevas", + "canvasBackground": "Arrière-plan du canevas", "drawingCanvas": "Canvas de dessin", "layers": "Calques", "actions": "Actions", @@ -72,29 +73,28 @@ "untitled": "Sans-titre", "name": "Nom", "yourName": "Votre nom", - "madeWithExcalidraw": "Fabriqué avec Excalidraw", + "madeWithExcalidraw": "Fait avec Excalidraw", "group": "Grouper la sélection", "ungroup": "Dégrouper la sélection", "collaborators": "Collaborateurs", - "toggleGridMode": "Basculer le mode grille", - "toggleStats": "Activer/désactiver les stats pour les nerds", + "gridMode": "Mode grille", "addToLibrary": "Ajouter à la bibliothèque", "removeFromLibrary": "Supprimer de la bibliothèque", "libraryLoadingMessage": "Chargement de la bibliothèque...", "libraries": "Explorer les bibliothèques", "loadingScene": "Chargement de la scène...", - "align": "Aligner", + "align": "Alignement", "alignTop": "Aligner en haut", "alignBottom": "Aligner en bas", "alignLeft": "Aligner à gauche", "alignRight": "Aligner à droite", "centerVertically": "Centrer verticalement", "centerHorizontally": "Centrer horizontalement", - "distributeHorizontally": "Répartir horizontalement", - "distributeVertically": "Répartir verticalement" + "distributeHorizontally": "Distribuer horizontalement", + "distributeVertically": "Distribuer verticalement" }, "buttons": { - "clearReset": "Effacer le canvas & réinitialiser la couleur d'arrière-plan", + "clearReset": "Réinitialiser le canevas", "export": "Exporter", "exportToPng": "Exporter en PNG", "exportToSvg": "Exporter en SVG", @@ -118,25 +118,26 @@ "redo": "Rétablir", "roomDialog": "Démarrer le collaboration en temps réel", "createNewRoom": "Créer un nouveau salon", - "toggleFullScreen": "Activer/désactiver le mode plein écran", - "toggleDarkMode": "Activer/désactiver le mode sombre", - "toggleZenMode": "Activer/désactiver le mode zen", + "fullScreen": "Plein écran", + "darkMode": "Mode sombre", + "lightMode": "Mode Clair", + "zenMode": "Mode Zen", "exitZenMode": "Quitter le mode zen" }, "alerts": { - "clearReset": "L'intégralité du canvas va être effacé. Êtes-vous sur ?", + "clearReset": "L'intégralité du canevas va être effacée. Êtes-vous sûr ?", "couldNotCreateShareableLink": "Impossible de créer un lien de partage.", "couldNotCreateShareableLinkTooBig": "Impossible de créer un lien partageable : la scène est trop volumineuse", "couldNotLoadInvalidFile": "Impossible de charger un fichier invalide", - "importBackendFailed": "L'import depuis le backend a échoué.", - "cannotExportEmptyCanvas": "Impossible d'exporter un canvas vide.", + "importBackendFailed": "L'importation depuis le backend a échoué.", + "cannotExportEmptyCanvas": "Impossible d'exporter un canevas vide.", "couldNotCopyToClipboard": "Impossible de copier dans le presse-papier. Essayez d'utiliser le navigateur Chrome.", "decryptFailed": "Les données n'ont pas pu être déchiffrées.", "uploadedSecurly": "Le téléchargement a été sécurisé avec un chiffrement de bout en bout, ce qui signifie que ni Excalidraw ni personne d'autre ne peut en lire le contenu.", "loadSceneOverridePrompt": "Le chargement d'un dessin externe remplacera votre contenu actuel. Souhaitez-vous continuer ?", "errorLoadingLibrary": "Une erreur s'est produite lors du chargement de la bibliothèque tierce.", "confirmAddLibrary": "Cela va ajouter {{numShapes}} forme(s) à votre bibliothèque. Êtes-vous sûr(e) ?", - "imageDoesNotContainScene": "Le fichier image ne contient pas de données de scène. L'avez-vous activé lors de l'export ?", + "imageDoesNotContainScene": "L'importation des images n'est pas prise en charge pour le moment.\n\nVoulez-vous importer une scène ? Cette image ne semble pas contenir de données de scène. Avez-vous activé cette option lors de l'exportation ?", "cannotRestoreFromImage": "Impossible de restaurer la scène depuis ce fichier image" }, "toolBar": { @@ -161,6 +162,7 @@ "freeDraw": "Cliquez et faites glissez, relâchez quand vous avez terminé", "text": "Astuce : vous pouvez également ajouter du texte en double-cliquant n'importe où avec l'outil de sélection", "linearElementMulti": "Cliquez sur le dernier point ou appuyez sur Échap ou Entrée pour terminer", + "lockAngle": "Vous pouvez contraindre l'angle en maintenant SHIFT", "resize": "Vous pouvez conserver les proportions en maintenant la touche SHIFT pendant le redimensionnement,\nen maintenant la touche ALT pour redimensionner par rapport au centre", "rotate": "Vous pouvez contraindre les angles en maintenant MAJ enfoncé pendant la rotation", "lineEditor_info": "Double-cliquez ou appuyez sur Entrée pour éditer les points", @@ -169,14 +171,14 @@ }, "canvasError": { "cannotShowPreview": "Impossible d’afficher l’aperçu", - "canvasTooBig": "Le tableau peut être trop grand.", - "canvasTooBigTip": "Astuce : essayez de rapprocher un peu les éléments les plus éloignés ensemble." + "canvasTooBig": "Le canevas est peut-être trop grand.", + "canvasTooBigTip": "Conseil : essayez de rapprocher un peu plus les éléments les plus éloignés." }, "errorSplash": { "headingMain_pre": "Une erreur est survenue. Essayez ", "headingMain_button": "rechargement de la page.", "clearCanvasMessage": "Si le rechargement ne résout pas l'erreur, essayez ", - "clearCanvasMessage_button": "effacement du canvas.", + "clearCanvasMessage_button": "effacement du canevas.", "clearCanvasCaveat": " Cela entraînera une perte du travail ", "trackedToSentry_pre": "L'erreur avec l'identifiant ", "trackedToSentry_post": " a été enregistrée dans notre système.", @@ -213,7 +215,7 @@ "textNewLine": "Ajouter une nouvelle ligne (texte)", "textFinish": "Terminer l'édition (texte)", "zoomToFit": "Zoomer pour visualiser tous les éléments", - "zoomToSelection": "Zoom sur la sélection", + "zoomToSelection": "Zoomer sur la sélection", "preventBinding": "Empêcher la liaison de la flèche" }, "encrypted": { @@ -227,7 +229,7 @@ "scene": "Scène", "selected": "Sélectionné", "storage": "Stockage", - "title": "Stats pour nerds", + "title": "Stats pour les nerds", "total": "Total", "width": "Largeur" } diff --git a/src/locales/he-IL.json b/src/locales/he-IL.json index a3b43ee23..9d8fb25b2 100644 --- a/src/locales/he-IL.json +++ b/src/locales/he-IL.json @@ -1,10 +1,11 @@ { "labels": { "paste": "הדבק", + "pasteCharts": "הדבק גרפים", "selectAll": "בחר הכל", - "multiSelect": "", - "moveCanvas": "", - "cut": "", + "multiSelect": "הוסף אובייקט לבחירה", + "moveCanvas": "הזז את הקנבס", + "cut": "חתוך", "copy": "העתק", "copyAsPng": "העתק ללוח כ PNG", "copyAsSvg": "העתק ללוח כ SVG", @@ -26,20 +27,20 @@ "sloppiness": "סגנון", "opacity": "אטימות", "textAlign": "יישור טקסט", - "edges": "", - "sharp": "", - "round": "", - "arrowheads": "", - "arrowhead_none": "", - "arrowhead_arrow": "", - "arrowhead_bar": "", - "arrowhead_dot": "", + "edges": "קצוות", + "sharp": "חד", + "round": "עגול", + "arrowheads": "ראשי חצים", + "arrowhead_none": "ללא", + "arrowhead_arrow": "חץ", + "arrowhead_bar": "שורה", + "arrowhead_dot": "נקודה", "fontSize": "גודל גופן", "fontFamily": "סוג הגופן", "onlySelected": "רק מה שנבחר", "withBackground": "עם רקע", - "exportEmbedScene": "", - "exportEmbedScene_details": "", + "exportEmbedScene": "שלב את התצוגה בקובץ המיוצא", + "exportEmbedScene_details": "מידע התצוגה יישמר לקובץ המיוצא מסוג PNG/SVG כך שיהיה ניתן לשחזרה ממנו.\nהפעולה תגדיל את גודל הקובץ המיוצא.", "addWatermark": "הוסף \"נוצר באמצעות Excalidraw\"", "handDrawn": "כתב יד", "normal": "רגיל", @@ -60,7 +61,7 @@ "architect": "ארכיטקט", "artist": "אמן", "cartoonist": "קריקטוריסט", - "fileTitle": "", + "fileTitle": "כותרת הקובץ", "colorPicker": "בחירת צבע", "canvasBackground": "רקע הלוח", "drawingCanvas": "לוח ציור", @@ -69,29 +70,28 @@ "language": "שפה", "createRoom": "התחל שיתוף פעולה חי", "duplicateSelection": "שכפל", - "untitled": "", + "untitled": "ללא כותרת", "name": "שם", "yourName": "שם", "madeWithExcalidraw": "נוצר באמצעות Excalidraw", "group": "אחד לקבוצה", "ungroup": "פרק קבוצה", - "collaborators": "", - "toggleGridMode": "", - "toggleStats": "", - "addToLibrary": "", - "removeFromLibrary": "", - "libraryLoadingMessage": "", - "libraries": "", - "loadingScene": "", - "align": "", - "alignTop": "", - "alignBottom": "", - "alignLeft": "", - "alignRight": "", - "centerVertically": "", - "centerHorizontally": "", - "distributeHorizontally": "", - "distributeVertically": "" + "collaborators": "שותפים", + "gridMode": "מצב רשת", + "addToLibrary": "הוסף לספריה", + "removeFromLibrary": "הסר מספריה", + "libraryLoadingMessage": "טוען ספריה...", + "libraries": "דפדף בספריות", + "loadingScene": "טוען תצוגה...", + "align": "יישר", + "alignTop": "יישר למעלה", + "alignBottom": "יישר למטה", + "alignLeft": "יישר לשמאל", + "alignRight": "יישר לימין", + "centerVertically": "מרכז אנכית", + "centerHorizontally": "מרכז אופקית", + "distributeHorizontally": "חלוקה אופקית", + "distributeVertically": "חלוקה אנכית" }, "buttons": { "clearReset": "אפס את הלוח", @@ -100,9 +100,9 @@ "exportToSvg": "יצא ל SVG", "copyToClipboard": "העתק ללוח", "copyPngToClipboard": "העתק PNG ללוח", - "scale": "", + "scale": "קנה מידה", "save": "שמור", - "saveAs": "", + "saveAs": "שמירה בשם", "load": "טען", "getShareableLink": "קבל קישור לשיתוף", "close": "סגור", @@ -118,26 +118,27 @@ "redo": "בצע מחדש", "roomDialog": "התחל שיתוף חי", "createNewRoom": "צור חדר", - "toggleFullScreen": "הפעל/הפסק מסך מלא", - "toggleDarkMode": "", - "toggleZenMode": "התחל/הפסק מצב תפריט מרחף", + "fullScreen": "מסך מלא", + "darkMode": "מצב כהה", + "lightMode": "מצב בהיר", + "zenMode": "מצב זן", "exitZenMode": "צא ממצב תפריט מרחף" }, "alerts": { "clearReset": "פעולה זו תנקה את כל הלוח. אתה בטוח?", "couldNotCreateShareableLink": "לא ניתן לייצר לינק לשיתוף.", - "couldNotCreateShareableLinkTooBig": "", + "couldNotCreateShareableLinkTooBig": "לא הצלחנו לייצר קישור לשיתוף: התצוגה גדולה מדי", "couldNotLoadInvalidFile": "לא ניתן לטעון קובץ שאיננו תואם", "importBackendFailed": "ייבוא מהשרת נכשל.", "cannotExportEmptyCanvas": "לא ניתן לייצא לוח ריק.", "couldNotCopyToClipboard": "לא ניתן להעתיק ללוח. נסה להשתמש בדפדפן Chrome.", "decryptFailed": "לא ניתן לפענח מידע.", "uploadedSecurly": "ההעלאה הוצפנה מקצה לקצה, ולכן שרת Excalidraw וצד שלישי לא יכולים לקרוא את התוכן.", - "loadSceneOverridePrompt": "", - "errorLoadingLibrary": "", - "confirmAddLibrary": "", - "imageDoesNotContainScene": "", - "cannotRestoreFromImage": "" + "loadSceneOverridePrompt": "טעינה של ציור חיצוני תחליף את התוכן הקיים שלך. האם תרצה להמשיך?", + "errorLoadingLibrary": "קרתה שגיאה בטעינת הספריה החיצונית.", + "confirmAddLibrary": "הפעולה תוסיף {{numShapes}} צורה(ות) לספריה שלך. האם אתה בטוח?", + "imageDoesNotContainScene": "אין תמיכה בייבוא תמונות כעת.\n\nהאם אתה רוצה לייבא תצוגה? התמונה הזאת אינה מכילה מידע על תצוגה. האם הפעלת את האפשרות הזאת בזמן הוצאת המידע?", + "cannotRestoreFromImage": "לא הצלחנו לשחזר את התצוגה מקובץ התמונה" }, "toolBar": { "selection": "בחירה", @@ -148,7 +149,7 @@ "arrow": "חץ", "line": "קו", "text": "טקסט", - "library": "", + "library": "ספריה", "lock": "השאר את הכלי הנבחר פעיל גם לאחר סיום הציור" }, "headings": { @@ -159,18 +160,19 @@ "hints": { "linearElement": "הקלק בשביל לבחור נקודות מרובות, גרור בשביל קו בודד", "freeDraw": "לחץ וגרור, שחרר כשסיימת", - "text": "", + "text": "טיפ: אפשר להוסיף טקסט על ידי לחיצה כפולה בכל מקום עם כלי הבחירה", "linearElementMulti": "הקלק על הנקודה האחרונה או הקש Escape או Enter לסיום", + "lockAngle": "אתה יכול להגביל זווית ע״י לחיצה על SHIFT", "resize": "ניתן להגביל פרופורציות על ידי לחיצה על SHIFT תוך כדי שינוי גודל,\nהחזק ALT בשביל לשנות גודל ביחס למרכז", "rotate": "ניתן להגביל זוויות על ידי לחיצה על SHIFT תוך כדי סיבוב", - "lineEditor_info": "", - "lineEditor_pointSelected": "", - "lineEditor_nothingSelected": "" + "lineEditor_info": "לחץ לחיצה כפולה או אנטר לעריכת הנקודות", + "lineEditor_pointSelected": "לחץ על Delete להסרת נקודה, CtrlOrCmd+D לשכפל, או גרור להזזה", + "lineEditor_nothingSelected": "בחר נקודה להזזה או הסרה, או החזק את כפתור Alt והקלק להוספת נקודות חדשות" }, "canvasError": { - "cannotShowPreview": "", - "canvasTooBig": "", - "canvasTooBigTip": "" + "cannotShowPreview": "לא הצלחנו להציג את התצוגה המקדימה", + "canvasTooBig": "הקנבס עלול להיות גדול מדי.", + "canvasTooBigTip": "טיפ: נסה להזיז את האלמנטים הרחוקים ביותר מעט קרוב יותר יחד." }, "errorSplash": { "headingMain_pre": "אירעה שגיאה. נסה ", @@ -213,22 +215,22 @@ "textNewLine": "הוסף שורה חדשה (טקסט)", "textFinish": "סיים עריכה (טקסט)", "zoomToFit": "זום להתאמת כל האלמנטים למסך", - "zoomToSelection": "", - "preventBinding": "" + "zoomToSelection": "התמקד בבחירה", + "preventBinding": "מנע השתלבות חצים" }, "encrypted": { "tooltip": "הרישומים שלך מוצפנים מקצה לקצה כך שהשרתים של Excalidraw לא יראו אותם לעולם." }, "stats": { - "angle": "", - "element": "", - "elements": "", - "height": "", - "scene": "", - "selected": "", - "storage": "", - "title": "", - "total": "", - "width": "" + "angle": "זווית", + "element": "אלמנט", + "elements": "אלמנטים", + "height": "גובה", + "scene": "תצוגה", + "selected": "נבחר/ים", + "storage": "אחסון", + "title": "סטטיסטיקות לחנונים", + "total": "סה״כ", + "width": "רוחב" } } diff --git a/src/locales/hi-IN.json b/src/locales/hi-IN.json index bce13e1ee..a87fa7586 100644 --- a/src/locales/hi-IN.json +++ b/src/locales/hi-IN.json @@ -1,6 +1,7 @@ { "labels": { "paste": "चिपकाएँ", + "pasteCharts": "चार्ट चिपकाएँ", "selectAll": "सभी चुनें", "multiSelect": "आकार को चयन में जोड़ें", "moveCanvas": "कैनवास को स्थानांतरित करें", @@ -29,17 +30,17 @@ "edges": "किनारा", "sharp": "नुकीला", "round": "गोल", - "arrowheads": "", - "arrowhead_none": "", + "arrowheads": "तीर शीर्ष", + "arrowhead_none": "कोई भी नहीं", "arrowhead_arrow": "तीर", - "arrowhead_bar": "", - "arrowhead_dot": "", + "arrowhead_bar": "बार", + "arrowhead_dot": "बिंदु", "fontSize": "फ़ॉन्ट का आकार", "fontFamily": "फ़ॉन्ट का परिवार", "onlySelected": "केवल चयनित", "withBackground": "बैकग्राउंड के साथ", - "exportEmbedScene": "", - "exportEmbedScene_details": "", + "exportEmbedScene": "निर्यात एम्बेड दृश्य", + "exportEmbedScene_details": "निर्यात एम्बेड दृश्य विवरण", "addWatermark": "ऐड \"मेड विथ एक्सकैलिडराव\"", "handDrawn": "हाथ से बनाया हुआ", "normal": "साधारण", @@ -60,7 +61,7 @@ "architect": "वास्तुकार", "artist": "कलाकार", "cartoonist": "व्यंग्य चित्रकार", - "fileTitle": "", + "fileTitle": "फ़ाइल का शीर्षक", "colorPicker": "रंग चयन", "canvasBackground": "कैनवास बैकग्राउंड", "drawingCanvas": "कैनवास बना रहे हैं", @@ -76,22 +77,21 @@ "group": "समूह चयन", "ungroup": "समूह चयन असमूहीकृत करें", "collaborators": "सहयोगी", - "toggleGridMode": "टॉगल ग्रिड मोड", - "toggleStats": "", + "gridMode": "ग्रिड मॉड", "addToLibrary": "लाइब्रेरी से जोड़ें", "removeFromLibrary": "लाइब्रेरी से निकालें", "libraryLoadingMessage": "लाइब्रेरी खुल रही है", - "libraries": "", + "libraries": "लाइब्रेरी ब्राउज़ करें", "loadingScene": "दृश्य खुल रहा है", - "align": "", - "alignTop": "", - "alignBottom": "", - "alignLeft": "", - "alignRight": "", - "centerVertically": "", - "centerHorizontally": "", - "distributeHorizontally": "", - "distributeVertically": "" + "align": "संरेखित करें", + "alignTop": "ऊपर संरेखित करें", + "alignBottom": "नीचे संरेखित करें", + "alignLeft": "बायें संरेखित करें", + "alignRight": "दायें संरेखित करें", + "centerVertically": "लंबवत केन्द्रित", + "centerHorizontally": "क्षैतिज केन्द्रित", + "distributeHorizontally": "क्षैतिज रूप से वितरित करें", + "distributeVertically": "खड़ी रूप से वितरित करें" }, "buttons": { "clearReset": "कैनवास रीसेट करें", @@ -100,7 +100,7 @@ "exportToSvg": "Svg के रूप में निर्यात करे", "copyToClipboard": "क्लिपबोर्ड पर प्रतिलिपि बनाएँ", "copyPngToClipboard": "क्लिपबोर्ड पर कॉपी करें,पीएनजी के रूप में", - "scale": "", + "scale": "पैमाना", "save": "सहेजें", "saveAs": "सेव करे इस तरह", "load": "लोड करें", @@ -118,15 +118,16 @@ "redo": "फिर से करें", "roomDialog": "लाइव सहयोग शुरू करें", "createNewRoom": "एक नया कमरा बनाएं", - "toggleFullScreen": "पूर्णस्क्रीन चालू करें", - "toggleDarkMode": "", - "toggleZenMode": "टॉगल ज़ेन मोड", + "fullScreen": "पूरी स्क्रीन", + "darkMode": "डार्क मोड", + "lightMode": "लाइट मोड", + "zenMode": "ज़ेन मोड", "exitZenMode": "जेन मोड से बाहर निकलें" }, "alerts": { "clearReset": "इससे पूरा कैनवास साफ हो जाएगा। क्या आपको यकीन है?", "couldNotCreateShareableLink": "साझा करने योग्य लिंक नहीं बनाया जा सका।", - "couldNotCreateShareableLinkTooBig": "", + "couldNotCreateShareableLinkTooBig": "लिंक शेयर नहीं कर सकता: दृश्य बहुत बड़ा", "couldNotLoadInvalidFile": "अमान्य फ़ाइल लोड नहीं की जा सकी", "importBackendFailed": "बैकएंड से आयात करना विफल रहा।", "cannotExportEmptyCanvas": "खाली कैनवास निर्यात नहीं कर सकता।", @@ -134,10 +135,10 @@ "decryptFailed": "डेटा को डिक्रिप्ट नहीं किया जा सका।", "uploadedSecurly": "अपलोड को एंड-टू-एंड एन्क्रिप्शन के साथ सुरक्षित किया गया है, जिसका मतलब है कि एक्सक्लूसिव सर्वर और थर्ड पार्टी कंटेंट नहीं पढ़ सकते हैं।", "loadSceneOverridePrompt": "लोड हो रहा है बाहरी ड्राइंग आपके मौजूदा सामग्री को बदल देगा। क्या आप जारी रखना चाहते हैं?", - "errorLoadingLibrary": "", - "confirmAddLibrary": "", - "imageDoesNotContainScene": "", - "cannotRestoreFromImage": "" + "errorLoadingLibrary": "लाइब्रेरी लोड करने में त्रुटि", + "confirmAddLibrary": "लाइब्रेरी जोड़ें पुष्‍टि करें आकार संख्या", + "imageDoesNotContainScene": "दृश्य में छवि नहीं है", + "cannotRestoreFromImage": "छवि फ़ाइल बहाल दृश्य नहीं है" }, "toolBar": { "selection": "चयन", @@ -148,7 +149,7 @@ "arrow": "तीर", "line": "रेखा", "text": "पाठ", - "library": "", + "library": "लाइब्रेरी", "lock": "ड्राइंग के बाद चयनित टूल को सक्रिय रखें" }, "headings": { @@ -159,8 +160,9 @@ "hints": { "linearElement": "कई बिंदुओं को शुरू करने के लिए क्लिक करें, सिंगल लाइन के लिए खींचें", "freeDraw": "क्लिक करें और खींचें। समाप्त करने के लिए, छोड़ो", - "text": "", + "text": "आप चयन टूल से कहीं भी डबल-क्लिक करके टेक्स्ट जोड़ सकते हैं", "linearElementMulti": "अंतिम बिंदु पर क्लिक करें या समाप्त होने के लिए एस्केप या एंटर दबाएं", + "lockAngle": "आप घूर्णन करते समय SHIFT पकड़कर कोणों को मोड़ सकते हैं", "resize": "आकार बदलते समय आप SHIFT को पकड़ कर अनुपात में कमी कर सकते हैं,\nकेंद्र से आकार बदलने के लिए ALT दबाए रखें", "rotate": "आप घूर्णन करते समय SHIFT पकड़कर कोणों को विवश कर सकते हैं", "lineEditor_info": "बिंदुओं को संपादित करने के लिए Enter पर डबल-क्लिक करें या दबाएँ", @@ -168,9 +170,9 @@ "lineEditor_nothingSelected": "स्थानांतरित करने या हटाने के लिए एक बिंदु का चयन करें, या Alt दबाए रखें और नए बिंदुओं को जोड़ने के लिए क्लिक करें" }, "canvasError": { - "cannotShowPreview": "", - "canvasTooBig": "", - "canvasTooBigTip": "" + "cannotShowPreview": "पूर्वावलोकन नहीं दिखा सकते हैं", + "canvasTooBig": "कैनवास बहुत बड़ा", + "canvasTooBigTip": "कैनवास बहुत बड़ा टिप" }, "errorSplash": { "headingMain_pre": "एक त्रुटि का सामना करना पड़ा। प्रयत्न ", @@ -213,21 +215,21 @@ "textNewLine": "नई पंक्ति (पाठ) जोड़ें", "textFinish": "संपादन समाप्त करें (पाठ)", "zoomToFit": "सभी तत्वों को फिट करने के लिए ज़ूम करें", - "zoomToSelection": "", - "preventBinding": "" + "zoomToSelection": "सिलेक्शन तक ज़ूम करे", + "preventBinding": "तीर बंधन रोकें" }, "encrypted": { "tooltip": "आपके चित्र अंत-से-अंत एन्क्रिप्टेड हैं, इसलिए एक्सक्लूसिव्रॉव के सर्वर उन्हें कभी नहीं देखेंगे।" }, "stats": { "angle": "कोण", - "element": "", - "elements": "", + "element": "एलिमेंट", + "elements": "एलिमेंट", "height": "ऊंचाई", "scene": "दृश्य", "selected": "चयनित", "storage": "संग्रह", - "title": "", + "title": "बेवकूफ के लिए आँकड़े", "total": "कुल", "width": "चौड़ाई" } diff --git a/src/locales/hu-HU.json b/src/locales/hu-HU.json index 20a643713..d6c503453 100644 --- a/src/locales/hu-HU.json +++ b/src/locales/hu-HU.json @@ -1,97 +1,97 @@ { "labels": { "paste": "Beillesztés", + "pasteCharts": "Grafikon beillesztése", "selectAll": "Összes kijelölése", - "multiSelect": "", - "moveCanvas": "", - "cut": "", + "multiSelect": "Elem hozzáadása a kijelöléshez", + "moveCanvas": "Vászon mozgatása", + "cut": "Kivágás", "copy": "Másolás", "copyAsPng": "Vágólapra másolás mint PNG", "copyAsSvg": "Vágólapra másolás mint SVG", "bringForward": "Előrébb hozás", - "sendToBack": "", - "bringToFront": "", - "sendBackward": "", + "sendToBack": "Hátraküldés", + "bringToFront": "Előrehozás", + "sendBackward": "Hátrébb küldés", "delete": "Törlés", - "copyStyles": "", - "pasteStyles": "", + "copyStyles": "Stílus másolása", + "pasteStyles": "Stílus beillesztése", "stroke": "Körvonal", "background": "Háttér", "fill": "Kitöltés", - "strokeWidth": "", - "strokeStyle": "", - "strokeStyle_solid": "", - "strokeStyle_dashed": "", - "strokeStyle_dotted": "", + "strokeWidth": "Körvonal vastagsága", + "strokeStyle": "Körvonal stílusa", + "strokeStyle_solid": "Kitöltött", + "strokeStyle_dashed": "Szaggatott", + "strokeStyle_dotted": "Pontozott", "sloppiness": "Stílus", "opacity": "Áttetszőség", - "textAlign": "", - "edges": "", - "sharp": "", - "round": "", - "arrowheads": "", - "arrowhead_none": "", - "arrowhead_arrow": "", - "arrowhead_bar": "", - "arrowhead_dot": "", - "fontSize": "", - "fontFamily": "", - "onlySelected": "Csak a kiválasztott", - "withBackground": "Háttérrel együtt", - "exportEmbedScene": "", - "exportEmbedScene_details": "", - "addWatermark": "", - "handDrawn": "", + "textAlign": "Szöveg igazítása", + "edges": "Szélek", + "sharp": "Éles", + "round": "Kerek", + "arrowheads": "Nyílhegyek", + "arrowhead_none": "Nincs", + "arrowhead_arrow": "Nyíl", + "arrowhead_bar": "Oszlop", + "arrowhead_dot": "Pont", + "fontSize": "Betűméret", + "fontFamily": "Betűkészlet család", + "onlySelected": "Csak a kijelölt", + "withBackground": "Háttérrel", + "exportEmbedScene": "Jelenet beágyazása az exportált fájlba", + "exportEmbedScene_details": "A jelenetet leíró adatok hozzá lesznek adva a PNG/SVG fájlhoz, így a jelenetet vissza lehet majd tölteni belőle. Ez megnöveli a fájl méretét.", + "addWatermark": "Add hozzá, hogy \"Excalidraw-val készült\"", + "handDrawn": "Kézzel rajzolt", "normal": "Normál", - "code": "Code", + "code": "Kód", "small": "Kicsi", "medium": "Közepes", "large": "Nagy", - "veryLarge": "", + "veryLarge": "Nagyon nagy", "solid": "Kitöltött", "hachure": "Vonalkázott", - "crossHatch": "", + "crossHatch": "Keresztcsíkozott", "thin": "Vékony", "bold": "Félkövér", "left": "Bal", - "center": "", - "right": "", - "extraBold": "", + "center": "Közép", + "right": "Jobb", + "extraBold": "Extra Félkövér", "architect": "Tervezői", "artist": "Művészi", "cartoonist": "Karikatúrás", - "fileTitle": "", + "fileTitle": "Fájl címe", "colorPicker": "Színválasztó", "canvasBackground": "Vászon háttérszíne", - "drawingCanvas": "", + "drawingCanvas": "Rajzvászon", "layers": "Rétegek", "actions": "Műveletek", "language": "Nyelv", "createRoom": "Élő együttmüködés megosztása", - "duplicateSelection": "", - "untitled": "", + "duplicateSelection": "Duplikálás", + "untitled": "Névtelen", "name": "Név", - "yourName": "", - "madeWithExcalidraw": "", - "group": "", - "ungroup": "", - "collaborators": "", - "toggleGridMode": "", - "toggleStats": "", - "addToLibrary": "", - "removeFromLibrary": "", - "libraryLoadingMessage": "", - "libraries": "", - "loadingScene": "", - "align": "", - "alignTop": "", - "alignBottom": "", - "alignLeft": "", - "alignRight": "", - "centerVertically": "", - "centerHorizontally": "", - "distributeHorizontally": "", - "distributeVertically": "" + "yourName": "Neved", + "madeWithExcalidraw": "Excalidraw-val készült", + "group": "Csoportosítás", + "ungroup": "Csoportbontás", + "collaborators": "Közreműködők", + "gridMode": "Hálómód", + "addToLibrary": "Hozzáadás a könyvtárhoz", + "removeFromLibrary": "Eltávólítás a könyvtárból", + "libraryLoadingMessage": "Könyvtár betöltése...", + "libraries": "Könyvtárak böngészése", + "loadingScene": "Jelenet betöltése...", + "align": "Igazítás", + "alignTop": "Felülre igazítás", + "alignBottom": "Alulra igazítás", + "alignLeft": "Balra igazítás", + "alignRight": "Jobbra igazítás", + "centerVertically": "Függőlegesen középre igazított", + "centerHorizontally": "Vízszintesen középre igazított", + "distributeHorizontally": "Vízszintes elosztás", + "distributeVertically": "Függőleges elosztás" }, "buttons": { "clearReset": "Vászon törlése", @@ -100,13 +100,13 @@ "exportToSvg": "Exportálás SVG-be", "copyToClipboard": "Vágólapra másolás", "copyPngToClipboard": "PNG másolása a vágólapra", - "scale": "", + "scale": "Nagyítás", "save": "Mentés", - "saveAs": "", + "saveAs": "Mentés másként", "load": "Betöltés", "getShareableLink": "Megosztható link létrehozása", "close": "Bezárás", - "selectLanguage": "", + "selectLanguage": "Nyelv kiválasztása", "scrollBackToContent": "Visszagörgetés a tartalomhoz", "zoomIn": "Nagyítás", "zoomOut": "Kicsinyítés", @@ -114,121 +114,123 @@ "menu": "Menü", "done": "Kész", "edit": "Szerkesztés", - "undo": "Visszavonás", - "redo": "Újra végrehajtás", + "undo": "Vissza", + "redo": "Újra", "roomDialog": "Élő együttműködés indítása", "createNewRoom": "Új szoba létrehozása", - "toggleFullScreen": "", - "toggleDarkMode": "", - "toggleZenMode": "", - "exitZenMode": "" + "fullScreen": "Teljes képernyő", + "darkMode": "Sötét mód", + "lightMode": "Világos mód", + "zenMode": "Letisztult mód", + "exitZenMode": "Kilépés a letisztult módból" }, "alerts": { "clearReset": "Ez a művelet törli a vászont. Biztos benne?", "couldNotCreateShareableLink": "Nem sikerült megosztható linket létrehozni.", - "couldNotCreateShareableLinkTooBig": "", - "couldNotLoadInvalidFile": "", + "couldNotCreateShareableLinkTooBig": "Nem sikerült megosztható linket látrehozni: túl nagy a jelenet", + "couldNotLoadInvalidFile": "Nem sikerült betölteni a helytelen fájlt", "importBackendFailed": "Nem sikerült betölteni a szerverről.", "cannotExportEmptyCanvas": "Üres vászont nem lehet exportálni.", - "couldNotCopyToClipboard": "Nem sikerült vágólapra menteni. Próbálja meg Chrome böngészővel.", - "decryptFailed": "Nem sikerült dekódolni az adatot.", - "uploadedSecurly": "A feltöltést végpontok közötti titkosítással biztosítottuk, ami azt jelenti, hogy az Excalidraw szerver és harmadik felek nem tudják elolvasni a feltöltés tartalmát.", - "loadSceneOverridePrompt": "", - "errorLoadingLibrary": "", - "confirmAddLibrary": "", - "imageDoesNotContainScene": "", - "cannotRestoreFromImage": "" + "couldNotCopyToClipboard": "Nem sikerült vágólapra menteni. Próbáld meg Chrome böngészővel.", + "decryptFailed": "Nem sikerült visszafejteni a titkosított adatot.", + "uploadedSecurly": "A feltöltést végpontok közötti titkosítással biztosítottuk, ami azt jelenti, hogy egy harmadik fél nem tudja megnézni a tartalmát, beleértve az Excalidraw szervereit is.", + "loadSceneOverridePrompt": "A betöltött külső rajz felül fogja írnia meglévőt. Szeretnéd folytatni?", + "errorLoadingLibrary": "Hibába ütközött a harmarmadik féltől származó könyvtár betöltése.", + "confirmAddLibrary": "Ez a művelet {{numShapes}} formát fog hozzáadni a könyvtáradhoz. Biztos vagy benne?", + "imageDoesNotContainScene": "Képek importálása egyelőre nem támogatott.\n\nEgy jelenetet szeretnél betölteni? Úgy tűnik ez a kép fájl nem tartalmazza a szükséges adatokat. Exportáláskor ezt egy külön opcióval lehet beállítani.", + "cannotRestoreFromImage": "A jelenet visszaállítása nem sikerült ebből a kép fájlból" }, "toolBar": { - "selection": "Kiválasztás", - "draw": "", + "selection": "Kijelölés", + "draw": "Szabadkézi rajz", "rectangle": "Téglalap", "diamond": "Rombusz", "ellipse": "Ellipszis", "arrow": "Nyíl", "line": "Vonal", "text": "Szöveg", - "library": "", - "lock": "Rajzolás után az aktív eszközt tartsa kiválasztva" + "library": "Könyvtár", + "lock": "Rajzolás után az aktív eszközt tartsa kijelölve" }, "headings": { "canvasActions": "Vászon műveletek", - "selectedShapeActions": "Kiválasztott forma műveletei", - "shapes": "Formák" + "selectedShapeActions": "Kijelölt forma műveletei", + "shapes": "Alakzatok" }, "hints": { - "linearElement": "Kattintson a több pont elindításához, húzza az egyenes vonalhoz", - "freeDraw": "", - "text": "", - "linearElementMulti": "Kattintson az utolsó pontra, vagy nyomja meg az Escape vagy az Enter billentyűt a befejezéshez", - "resize": "", + "linearElement": "Kattintással görbe, az eger húzásával pedig egyenes nyilat rajzolhatsz", + "freeDraw": "Kattints és húzd, majd engedd el, amikor végeztél", + "text": "Tipp: A kijelölés eszközzel a dupla kattintás új szöveget hoz létre", + "linearElementMulti": "Kattints a következő ív pozíciójára, vagy fejezd be a nyilat az Escape vagy Enter megnyomásával", + "lockAngle": "A SHIFT billentyű lenyomva tartásával korlátozhatja forgatás szögét", + "resize": "A SHIFT billentyű lenyomva tartásával az átméretezés megtartja az arányokat,\naz ALT lenyomva tartásával pedig a középpont egy helyben marad", "rotate": "A SHIFT billentyű lenyomva tartásával korlátozhatja a szögek illesztését", - "lineEditor_info": "", - "lineEditor_pointSelected": "", - "lineEditor_nothingSelected": "" + "lineEditor_info": "Kattints duplán, vagy nyomj entert a pontok szerkesztéséhez", + "lineEditor_pointSelected": "Nyomd meg a delete gombot a pont eltávolításához, Ctrl vagy Cmd + D-t a duplikáláshoz, vagy húzva mozgasd", + "lineEditor_nothingSelected": "Válassz ki egy pontot a mozgatáshoz vagy törtléshez, vagy az Alt lenyomása mellett kattintva hozz létre új pontokat" }, "canvasError": { - "cannotShowPreview": "", - "canvasTooBig": "", - "canvasTooBigTip": "" + "cannotShowPreview": "Előnézet nem jeleníthető meg", + "canvasTooBig": "A vászon talán túl nagy.", + "canvasTooBigTip": "Tipp: próbáld meg a legtávolabbi elemeket közelebb hozni egy máshoz." }, "errorSplash": { - "headingMain_pre": "Hiba történt. Próbálja ", + "headingMain_pre": "Hiba történt. Próbáld ", "headingMain_button": "újratölteni az oldalt.", - "clearCanvasMessage": "Ha az újratöltés nem működik, próbálja ", - "clearCanvasMessage_button": "törölni a vászont.", - "clearCanvasCaveat": " Ezzel elveszik minden eddigi munkája ", + "clearCanvasMessage": "Ha az újratöltés nem működik, próbáld ", + "clearCanvasMessage_button": "letörölni a vászont.", + "clearCanvasCaveat": " Ezzel az eddigi munka elveszik ", "trackedToSentry_pre": "A hibakód azonosítóval ", "trackedToSentry_post": " nyomon van követve a rendszerünkben.", - "openIssueMessage_pre": "Nagyon vigyáztunk, hogy ne adjunk meg a jelenetre vonatkozó információkat a hibában. Ha a jeleneted nem bizalmas, kérjük fontolja meg a jelenet hozzáadását a hibakövető rendszerünkben ", - "openIssueMessage_button": "hibabejelentő.", + "openIssueMessage_pre": "Vigyáztunk arra, hogy a jelenthez tartozó információ ne jelenjen meg a hibaüzenetben. Ha a jeleneted nem bizalmas, kérjük add hozzá a ", + "openIssueMessage_button": "hibakövető rendszerünkhöz.", "openIssueMessage_post": " Kérjük, másolja be az alábbi információkat a GitHub problémába.", "sceneContent": "Jelenet tartalma:" }, "roomDialog": { "desc_intro": "Meghívhat embereket a jelenlegi jelenetbe, hogy együttműködjenek önnel.", - "desc_privacy": "Ne aggódjon, a munkamenet végpontok közötti titkosítást használ, tehát bármit rajzol, privát marad. Még a szerverünk sem fogja látni, hogy mit rajzolt.", + "desc_privacy": "Ne aggódj, a munkamenet végpontok közötti titkosítást használ, tehát bármit rajzolsz, privát marad. Még a szerverünkről se lehet belenézni.", "button_startSession": "Munkamenet indítása", "button_stopSession": "Munkamenet leállítása", "desc_inProgressIntro": "Az élő együttműködési munkamenet folyamatban van.", "desc_shareLink": "Ossza meg ezt a linket bárkivel, akivel együtt szeretne működni:", - "desc_exitSession": "" + "desc_exitSession": "Az munkamenet leállítása kilépteti önt a szobából, de folytathatja a munkát a saját gépén. Vegye figyelembe, hogy ez nem érinti más emberek munkáját és ők továbbra is együttműködhetnek a saját változatukon." }, "errorDialog": { - "title": "" + "title": "Hiba" }, "shortcutsDialog": { - "title": "", - "shapes": "", - "or": "", - "click": "", - "drag": "", - "curvedArrow": "", - "curvedLine": "", - "editor": "", - "view": "", - "blog": "", - "howto": "", - "github": "", - "textNewLine": "", - "textFinish": "", - "zoomToFit": "", - "zoomToSelection": "", - "preventBinding": "" + "title": "Gyorsbillentyűk", + "shapes": "Formák", + "or": "vagy", + "click": "klikk", + "drag": "húzd", + "curvedArrow": "Ívelt nyíl", + "curvedLine": "Ívelt vonal", + "editor": "Szerkesztő", + "view": "Nézet", + "blog": "Olvasd a blogunkat", + "howto": "Kövesd az útmutatóinkat", + "github": "Hibát találtál? Küld be", + "textNewLine": "Új sor hozzáadása (szöveg)", + "textFinish": "Szerkesztés befejezése (szöveg)", + "zoomToFit": "Az összes elem látótérbe hozása", + "zoomToSelection": "Kijelölésre nagyítás", + "preventBinding": "A nyíl ne ragadjon" }, "encrypted": { - "tooltip": "" + "tooltip": "A rajzaidat végpontok közötti titkosítással tároljuk, tehát az Excalidraw szervereiről se tud más belenézni." }, "stats": { - "angle": "", - "element": "", - "elements": "", - "height": "", - "scene": "", - "selected": "", - "storage": "", - "title": "", - "total": "", - "width": "" + "angle": "Szög", + "element": "Elem", + "elements": "Elemek", + "height": "Magasság", + "scene": "Jelenet", + "selected": "Kijelölt", + "storage": "Tárhely", + "title": "Statisztikák", + "total": "Összesen", + "width": "Szélesség" } } diff --git a/src/locales/id-ID.json b/src/locales/id-ID.json index 60fb87846..76fadab92 100644 --- a/src/locales/id-ID.json +++ b/src/locales/id-ID.json @@ -1,6 +1,7 @@ { "labels": { "paste": "Tempel", + "pasteCharts": "Tempel diagram", "selectAll": "Pilih semua", "multiSelect": "Tambahkan elemen ke pilihan", "moveCanvas": "Pindahkan kanvas", @@ -37,7 +38,7 @@ "fontSize": "Ukuran font", "fontFamily": "Jenis font", "onlySelected": "Hanya yang Dipilih", - "withBackground": "Dengan Latar", + "withBackground": "Dengan latar", "exportEmbedScene": "Sematkan pemandangan ke dalam file yang diekspor", "exportEmbedScene_details": "Data pemandangan akan disimpan dalam file PNG/SVG yang diekspor, sehingga pemandangan itu dapat dipulihkan darinya.\nAkan membesarkan ukuran file yang diekspor.", "addWatermark": "Tambahkan \"Dibuat dengan Excalidraw\"", @@ -76,8 +77,7 @@ "group": "Kelompokan pilihan", "ungroup": "Pisahkan pilihan", "collaborators": "Kolaborator", - "toggleGridMode": "Aktifkan/Matikan mode kisi", - "toggleStats": "Aktifkan statistik untuk nerd", + "gridMode": "Mode grid", "addToLibrary": "Tambahkan ke pustaka", "removeFromLibrary": "Hapus dari pustaka", "libraryLoadingMessage": "Memuat pustaka...", @@ -118,9 +118,10 @@ "redo": "Ulangi", "roomDialog": "Mulai kolaborasi langsung", "createNewRoom": "Buat ruang baru", - "toggleFullScreen": "Beralih ke layar penuh", - "toggleDarkMode": "Aktifkan/Matikan mode gelap", - "toggleZenMode": "Aktifkan/Matikan mode zen", + "fullScreen": "Layar penuh", + "darkMode": "Mode gelap", + "lightMode": "Mode terang", + "zenMode": "Mode zen", "exitZenMode": "Keluar dari mode zen" }, "alerts": { @@ -136,7 +137,7 @@ "loadSceneOverridePrompt": "Memuat gambar external akan mengganti konten Anda yang ada. Apakah Anda ingin melanjutkan?", "errorLoadingLibrary": "Terdapat kesalahan dalam memuat pustaka pihak ketiga.", "confirmAddLibrary": "Ini akan menambahkan {{numShapes}} bentuk ke pustaka Anda. Anda yakin?", - "imageDoesNotContainScene": "File gambar tidak berisi data pemandangan. Apa Anda sudah aktifkan ini selama ekspor?", + "imageDoesNotContainScene": "Mengimpor gambar tidak didukung saat ini.\n\nApakah Anda ingin impor pemandangan? Gambar ini tidak berisi data pemandangan. Sudah ka Anda aktifkan ini ketika ekspor?", "cannotRestoreFromImage": "Pemandangan tidak dapat dipulihkan dari file gambar ini" }, "toolBar": { @@ -161,6 +162,7 @@ "freeDraw": "Klik dan seret, lepaskan jika Anda selesai", "text": "Tip: Anda juga dapat menambahkan teks dengan klik ganda di mana saja dengan alat pemilihan", "linearElementMulti": "Klik pada titik akhir atau tekan Escape atau Enter untuk menyelesaikan", + "lockAngle": "Anda dapat menjaga sudut dengan menahan SHIFT", "resize": "Anda dapat menjaga proposi dengan menekan SHIFT sambil mengubah ukuran,\ntekan AlT untuk mengubah ukuran dari tengah", "rotate": "Anda dapat menjaga sudut dengan menahan SHIFT sambil memutar", "lineEditor_info": "Klik ganda atau tekan Enter untuk mengedit titik", @@ -213,7 +215,7 @@ "textNewLine": "Tambahkan baris baru (teks)", "textFinish": "Selesai mengedit (teks)", "zoomToFit": "Perbesar agar sesuai dengan semua elemen", - "zoomToSelection": "", + "zoomToSelection": "Perbesar ke seleksi", "preventBinding": "Cegah pengikatan panah" }, "encrypted": { diff --git a/src/locales/it-IT.json b/src/locales/it-IT.json index ab01d2210..0faf287fd 100644 --- a/src/locales/it-IT.json +++ b/src/locales/it-IT.json @@ -1,6 +1,7 @@ { "labels": { "paste": "Incolla", + "pasteCharts": "Incolla grafici", "selectAll": "Seleziona tutto", "multiSelect": "Aggiungi elemento alla selezione", "moveCanvas": "Sposta tela", @@ -37,7 +38,7 @@ "fontSize": "Dimensione carattere", "fontFamily": "Carattere", "onlySelected": "Solo selezionati", - "withBackground": "Con Sfondo", + "withBackground": "Con sfondo", "exportEmbedScene": "Incorpora la scena nel file esportato", "exportEmbedScene_details": "I dati della scena saranno salvati nel file PNG/SVG esportato in modo che la scena possa essere ripristinata da esso.\nQuesto aumenterà la dimensione del file esportato.", "addWatermark": "Aggiungi \"Creato con Excalidraw\"", @@ -76,10 +77,9 @@ "group": "Crea gruppo da selezione", "ungroup": "Dividi gruppo da selezione", "collaborators": "Collaboratori", - "toggleGridMode": "Attiva/disattiva modalità griglia", - "toggleStats": "Attiva/disattiva statistiche per nerd", - "addToLibrary": "Aggiungi alla biblioteca", - "removeFromLibrary": "Rimuovi dalla biblioteca", + "gridMode": "Modalità griglia", + "addToLibrary": "Aggiungi alla libreria", + "removeFromLibrary": "Rimuovi dalla libreria", "libraryLoadingMessage": "Caricamento della biblioteca...", "libraries": "Sfoglia librerie", "loadingScene": "Caricamento della scena...", @@ -118,9 +118,10 @@ "redo": "Ripeti", "roomDialog": "Inizia collaborazione in diretta", "createNewRoom": "Crea nuova stanza", - "toggleFullScreen": "Attiva/Disattiva schermo intero", - "toggleDarkMode": "Attiva tema scuro", - "toggleZenMode": "Attiva/Disattiva modalità zen", + "fullScreen": "Schermo intero", + "darkMode": "Tema scuro", + "lightMode": "Tema chiaro", + "zenMode": "Modalità Zen", "exitZenMode": "Uscire dalla modalità zen" }, "alerts": { @@ -135,8 +136,8 @@ "uploadedSecurly": "L'upload è stato protetto con la crittografia end-to-end, il che significa che il server Excalidraw e terze parti non possono leggere il contenuto.", "loadSceneOverridePrompt": "Se carichi questo disegno esterno, sostituirà quello che hai. Vuoi continuare?", "errorLoadingLibrary": "Si è verificato un errore nel caricamento della libreria di terze parti.", - "confirmAddLibrary": "Questo aggiungerà {{numShapes}} forma(e) alla tua biblioteca. Sei sicuro?", - "imageDoesNotContainScene": "Il file immagine non contiene dati di scena. È stato abilitato durante l'esportazione?", + "confirmAddLibrary": "Questo aggiungerà {{numShapes}} forma(e) alla tua libreria. Sei sicuro?", + "imageDoesNotContainScene": "L'importazione di immagini al momento non è supportata.\n\nVuoi importare una scena? Questa immagine non sembra contenere alcun dato di scena. Hai abilitato questa opzione durante l'esportazione?", "cannotRestoreFromImage": "Impossibile ripristinare la scena da questo file immagine" }, "toolBar": { @@ -148,7 +149,7 @@ "arrow": "Freccia", "line": "Linea", "text": "Testo", - "library": "Biblioteca", + "library": "Libreria", "lock": "Mantieni lo strumento selezionato attivo dopo aver disegnato" }, "headings": { @@ -161,6 +162,7 @@ "freeDraw": "Clicca e trascina, rilascia quando avrai finito", "text": "Suggerimento: puoi anche aggiungere del testo facendo doppio clic ovunque con lo strumento di selezione", "linearElementMulti": "Clicca sull'ultimo punto o premi Esc o Invio per finire", + "lockAngle": "Puoi limitare l'angolo tenendo premuto SHIFT", "resize": "Per vincolare le proporzioni, tenir premuto MAIUSC durante il ridimensionamento;\nper ridimensionare dal centro, tenir premuto ALT", "rotate": "Puoi mantenere gli angoli tenendo premuto SHIFT durante la rotazione", "lineEditor_info": "Fai doppio click o premi invio per modificare i punti", diff --git a/src/locales/ja-JP.json b/src/locales/ja-JP.json index c7fd2c0e4..6e8525165 100644 --- a/src/locales/ja-JP.json +++ b/src/locales/ja-JP.json @@ -1,6 +1,7 @@ { "labels": { "paste": "貼り付け", + "pasteCharts": "", "selectAll": "すべて選択", "multiSelect": "複数選択", "moveCanvas": "キャンバスを移動", @@ -37,7 +38,7 @@ "fontSize": "フォントの大きさ", "fontFamily": "フォントの種類", "onlySelected": "選択中のみ", - "withBackground": "背景を含める", + "withBackground": "", "exportEmbedScene": "エクスポートされたファイルにシーンを埋め込みます", "exportEmbedScene_details": "シーンデータはエクスポートされたPNG/SVGファイルに保存され、シーンを復元することができます。\nエクスポートされたファイルのサイズは増加します。", "addWatermark": "\"Made with Excalidraw\"と表示", @@ -76,8 +77,7 @@ "group": "図形のグループ化", "ungroup": "グループ化を解除", "collaborators": "共同編集者", - "toggleGridMode": "グリッドモードに切り替える", - "toggleStats": "", + "gridMode": "", "addToLibrary": "ライブラリに追加", "removeFromLibrary": "ライブラリから削除", "libraryLoadingMessage": "ライブラリを読み込み中...", @@ -118,9 +118,10 @@ "redo": "やり直し", "roomDialog": "共同編集を開始する", "createNewRoom": "新しい部屋を作成する", - "toggleFullScreen": "全画面表示に切り替える", - "toggleDarkMode": "ダークモードに切り替える", - "toggleZenMode": "集中モードに切り替える", + "fullScreen": "", + "darkMode": "", + "lightMode": "", + "zenMode": "", "exitZenMode": "集中モードをやめる" }, "alerts": { @@ -136,7 +137,7 @@ "loadSceneOverridePrompt": "外部図面を読み込むと、既存のコンテンツが置き換わります。続行しますか?", "errorLoadingLibrary": "サードパーティライブラリの読み込み中にエラーが発生しました。", "confirmAddLibrary": "{{numShapes}} 個の図形をライブラリに追加します。よろしいですか?", - "imageDoesNotContainScene": "画像ファイルにシーンデータが含まれていません。エクスポート中にこれを有効にしましたか?", + "imageDoesNotContainScene": "", "cannotRestoreFromImage": "このイメージファイルからシーンを復元できませんでした" }, "toolBar": { @@ -161,6 +162,7 @@ "freeDraw": "クリックしてドラッグします。離すと終了します", "text": "ヒント: 選択ツールを使用して任意の場所をダブルクリックしてテキストを追加することもできます", "linearElementMulti": "最後のポイントをクリックするか、エスケープまたはEnterを押して終了します", + "lockAngle": "", "resize": "サイズを変更中にSHIFTを押しすと比率を制御できます。Altを押すと中央からサイズを変更できます。", "rotate": "回転中にSHIFT キーを押すと角度を制限することができます", "lineEditor_info": "ポイントを編集するには、ダブルクリックまたはEnterキーを押します", diff --git a/src/locales/ko-KR.json b/src/locales/ko-KR.json index 3d77e7f9d..61c026ce0 100644 --- a/src/locales/ko-KR.json +++ b/src/locales/ko-KR.json @@ -1,11 +1,12 @@ { "labels": { "paste": "붙여넣기", + "pasteCharts": "차트 붙여넣기", "selectAll": "전체 선택", "multiSelect": "선택 영역에 추가하기", "moveCanvas": "캔버스 이동", - "cut": "", - "copy": "복사하기", + "cut": "잘라내기", + "copy": "복사", "copyAsPng": "클립보드로 PNG 이미지 복사", "copyAsSvg": "클립보드로 SVG 이미지 복사", "bringForward": "앞으로 가져오기", @@ -17,31 +18,31 @@ "pasteStyles": "스타일 붙여넣기", "stroke": "선 색상", "background": "배경색", - "fill": "채우기 스타일", - "strokeWidth": "선 두께", - "strokeStyle": "선 스타일", + "fill": "채우기", + "strokeWidth": "선 굵기", + "strokeStyle": "선", "strokeStyle_solid": "실선", "strokeStyle_dashed": "파선", "strokeStyle_dotted": "점선", - "sloppiness": "선 스타일", + "sloppiness": "대충 긋기", "opacity": "불투명도", "textAlign": "텍스트 정렬", "edges": "가장자리", - "sharp": "선명하게", + "sharp": "뾰족하게", "round": "둥글게", - "arrowheads": "", - "arrowhead_none": "", - "arrowhead_arrow": "", - "arrowhead_bar": "", - "arrowhead_dot": "", - "fontSize": "폰트 크기", - "fontFamily": "폰트 스타일", + "arrowheads": "화살촉", + "arrowhead_none": "없음", + "arrowhead_arrow": "화살표", + "arrowhead_bar": "막대", + "arrowhead_dot": "점", + "fontSize": "글자 크기", + "fontFamily": "글꼴", "onlySelected": "선택한 항목만", "withBackground": "배경 포함", - "exportEmbedScene": "", - "exportEmbedScene_details": "", + "exportEmbedScene": "화면을 내보낸 파일에 담기", + "exportEmbedScene_details": "화면 정보가 내보내는 PNG/SVG 파일에 저장되어 이후에 파일에서 화면을 복구할 수 있습니다. 파일 크기가 증가합니다.", "addWatermark": "\"Made with Excalidraw\" 추가", - "handDrawn": "필기체", + "handDrawn": "손글씨", "normal": "일반", "code": "코드", "small": "작게", @@ -57,41 +58,40 @@ "center": "가운데", "right": "오른쪽", "extraBold": "매우 굵게", - "architect": "", - "artist": "", - "cartoonist": "", - "fileTitle": "", + "architect": "건축가", + "artist": "예술가", + "cartoonist": "만화가", + "fileTitle": "파일명", "colorPicker": "색상 선택기", "canvasBackground": "캔버스 배경", "drawingCanvas": "캔버스 그리기", "layers": "레이어", - "actions": "", + "actions": "동작", "language": "언어", "createRoom": "실시간 협업 세션 공유", "duplicateSelection": "복제", - "untitled": "", - "name": "", + "untitled": "제목 없음", + "name": "이름", "yourName": "이름 입력", "madeWithExcalidraw": "Made with Excalidraw", "group": "그룹 생성", "ungroup": "그룹 해제", "collaborators": "공동 작업자", - "toggleGridMode": "격자 모드 켜기/끄기", - "toggleStats": "", + "gridMode": "격자 방식", "addToLibrary": "라이브러리에 추가", "removeFromLibrary": "라이브러리에서 제거", "libraryLoadingMessage": "라이브러리 불러오는 중...", - "libraries": "", + "libraries": "라이브러리 찾기", "loadingScene": "화면 불러오는 중...", - "align": "", - "alignTop": "", - "alignBottom": "", - "alignLeft": "", - "alignRight": "", - "centerVertically": "", - "centerHorizontally": "", - "distributeHorizontally": "", - "distributeVertically": "" + "align": "정렬", + "alignTop": "상단 정렬", + "alignBottom": "하단 정렬", + "alignLeft": "왼쪽 정렬", + "alignRight": "오른쪽 정렬", + "centerVertically": "수직으로 중앙 정렬", + "centerHorizontally": "수평으로 중앙 정렬", + "distributeHorizontally": "수평으로 분배", + "distributeVertically": "수직으로 분배" }, "buttons": { "clearReset": "캔버스 초기화", @@ -100,17 +100,17 @@ "exportToSvg": "SVG로 내보내기", "copyToClipboard": "클립보드로 복사", "copyPngToClipboard": "클립보드로 PNG 이미지 복사", - "scale": "", + "scale": "크기", "save": "저장", "saveAs": "다른 이름으로 저장", "load": "불러오기", "getShareableLink": "공유 가능한 링크 생성", "close": "닫기", "selectLanguage": "언어 선택", - "scrollBackToContent": "콘텐츠 영역으로 스크롤 이동하기", + "scrollBackToContent": "콘텐츠 영역으로 스크롤하기", "zoomIn": "확대", "zoomOut": "축소", - "resetZoom": "줌 초기화", + "resetZoom": "확대/축소 초기화", "menu": "메뉴", "done": "완료", "edit": "수정", @@ -118,26 +118,27 @@ "redo": "다시 실행", "roomDialog": "실시간 협업 시작하기", "createNewRoom": "방 만들기", - "toggleFullScreen": "전체화면", - "toggleDarkMode": "다크 모드 켜기/끄기", - "toggleZenMode": "젠 모드 켜기/끄기", + "fullScreen": "전체화면", + "darkMode": "다크 모드", + "lightMode": "밝은 모드", + "zenMode": "젠 모드", "exitZenMode": "젠 모드 종료하기" }, "alerts": { - "clearReset": "모든 작업 내용을 초기화 합니다. 계속 진행할까요?", + "clearReset": "모든 작업 내용이 초기화됩니다. 계속하시겠습니까?", "couldNotCreateShareableLink": "공유 가능한 링크를 생성할 수 없습니다.", - "couldNotCreateShareableLinkTooBig": "", + "couldNotCreateShareableLinkTooBig": "공유 가능한 링크를 생성할 수 없습니다: 화면이 너무 큽니다.", "couldNotLoadInvalidFile": "유효하지 않은 파일입니다.", "importBackendFailed": "서버로부터 불러 오지 못했습니다.", "cannotExportEmptyCanvas": "빈 캔버스를 내보낼 수 없습니다.", - "couldNotCopyToClipboard": "클립 보드에 복사 할 수 없습니다. Chrome 브라우저에서 시도해 주세요.", + "couldNotCopyToClipboard": "클립 보드에 복사할 수 없습니다. Chrome 브라우저에서 시도해 주세요.", "decryptFailed": "데이터를 복호화하지 못했습니다.", "uploadedSecurly": "업로드는 종단 간 암호화로 보호되므로 Excalidraw 서버 및 타사가 콘텐츠를 읽을 수 없습니다.", "loadSceneOverridePrompt": "외부 파일을 불러 오면 기존 콘텐츠가 대체됩니다. 계속 진행할까요?", - "errorLoadingLibrary": "", - "confirmAddLibrary": "", - "imageDoesNotContainScene": "", - "cannotRestoreFromImage": "" + "errorLoadingLibrary": "외부 라이브러리를 불러오는 중에 문제가 발생했습니다.", + "confirmAddLibrary": "{{numShapes}}개의 모양이 라이브러리에 추가됩니다. 계속하시겠어요?", + "imageDoesNotContainScene": "이미지에서 불러오기는 현재 지원되지 않습니다.\n\n화면을 불러오려고 하셨나요? 이미지에 화면 정보가 없는 것 같습니다. 내보낼 때 화면을 포함했나요?", + "cannotRestoreFromImage": "이미지 파일에서 화면을 복구할 수 없었습니다" }, "toolBar": { "selection": "선택", @@ -146,44 +147,45 @@ "diamond": "다이아몬드", "ellipse": "타원", "arrow": "화살표", - "line": "라인", + "line": "선", "text": "텍스트", "library": "라이브러리", "lock": "선택된 도구 유지하기" }, "headings": { - "canvasActions": "", - "selectedShapeActions": "", - "shapes": "" + "canvasActions": "캔버스 동작", + "selectedShapeActions": "선택된 모양 동작", + "shapes": "모양" }, "hints": { "linearElement": "여러 점을 연결하려면 클릭하고, 직선을 그리려면 바로 드래그하세요.", "freeDraw": "클릭 후 드래그하세요. 완료되면 놓으세요.", - "text": "", + "text": "팁: 선택 툴로 아무 곳이나 더블 클릭해 텍스트를 추가할 수도 있습니다.", "linearElementMulti": "마지막 지점을 클릭하거나 Esc 또는 Enter 키를 눌러 완료하세요.", - "resize": "", + "lockAngle": "SHIFT 키를 누르면서 회전하면 각도를 제한할 수 있습니다.", + "resize": "SHIFT 키를 누르면서 조정하면 크기의 비율이 제한됩니다.\nALT를 누르면서 조정하면 중앙을 기준으로 크기를 조정합니다.", "rotate": "SHIFT 키를 누르면서 회전하면 각도를 제한할 수 있습니다.", - "lineEditor_info": "포인트를 수정하려면 두 번 클릭하거나 엔터 키를 누르세요.", + "lineEditor_info": "지점을 수정하려면 두 번 클릭하거나 Enter 키를 누르세요.", "lineEditor_pointSelected": "제거하려면 Delete 키, 복제하려면 CtrlOrCmd+D, 이동하려면 드래그하세요.", - "lineEditor_nothingSelected": "" + "lineEditor_nothingSelected": "옮기거나 지울 지점을 선택하거나, Alt를 누른 상태로 클릭해 새 지점을 만드세요" }, "canvasError": { - "cannotShowPreview": "", - "canvasTooBig": "", - "canvasTooBigTip": "" + "cannotShowPreview": "미리보기를 볼 수 없습니다", + "canvasTooBig": "캔버스가 너무 큽니다.", + "canvasTooBigTip": "팁: 멀리 있는 요소들을 좀 더 가까이로 붙여 보세요." }, "errorSplash": { - "headingMain_pre": "", + "headingMain_pre": "오류가 발생했습니다. ", "headingMain_button": "페이지 새로고침", - "clearCanvasMessage": "", - "clearCanvasMessage_button": "캔버스를 초기화 중입니다.", - "clearCanvasCaveat": "", - "trackedToSentry_pre": "", - "trackedToSentry_post": "", - "openIssueMessage_pre": "", - "openIssueMessage_button": "", + "clearCanvasMessage": "새로고침으로 해결되지 않을 경우, ", + "clearCanvasMessage_button": "캔버스 비우기", + "clearCanvasCaveat": " 작업 내용을 잃게 됩니다 ", + "trackedToSentry_pre": "오류 ", + "trackedToSentry_post": " 가 시스템에서 발견되었습니다.", + "openIssueMessage_pre": "저희는 화면 정보를 오류에 포함하지 않도록 매우 주의하고 있습니다. 혹시 화면에 민감한 내용이 없다면 이곳에 업로드를 고려해주세요.", + "openIssueMessage_button": "버그 트래커", "openIssueMessage_post": " 아래 정보를 GitHub 이슈에 복사 및 붙여넣기해 주세요.", - "sceneContent": "" + "sceneContent": "화면 내용:" }, "roomDialog": { "desc_intro": "현재 화면에 공동 작업자를 초대해 협업할 수 있습니다.", @@ -192,14 +194,14 @@ "button_stopSession": "세션 중단", "desc_inProgressIntro": "실시간 협업 세션이 진행 중입니다.", "desc_shareLink": "공동 작업자에게 이 링크를 공유하세요.", - "desc_exitSession": "" + "desc_exitSession": "세션을 중단하면 연결은 끊어지나 작업을 이어갈 수 있습니다. 이 작업은 다른 작업자에게 영향을 미치지 않으며 각자의 공동 작업은 계속 유지됩니다." }, "errorDialog": { - "title": "에러" + "title": "오류" }, "shortcutsDialog": { "title": "키보드 단축키", - "shapes": "그리기", + "shapes": "모양", "or": "또는", "click": "클릭", "drag": "드래그", @@ -210,25 +212,25 @@ "blog": "블로그 읽어보기", "howto": "가이드 참고하기", "github": "이슈 제보하기", - "textNewLine": "줄바꾸기", - "textFinish": "편집 완료", - "zoomToFit": "", - "zoomToSelection": "", - "preventBinding": "" + "textNewLine": "줄바꿈 (텍스트)", + "textFinish": "편집 완료 (텍스트)", + "zoomToFit": "모든 요소가 보이도록 확대/축소", + "zoomToSelection": "선택 영역으로 확대/축소", + "preventBinding": "화살표가 붙지 않게 하기" }, "encrypted": { - "tooltip": "" + "tooltip": "그림은 종단 간 암호화되므로 Excalidraw의 서버는 절대로 내용을 알 수 없습니다." }, "stats": { - "angle": "", - "element": "", - "elements": "", - "height": "", - "scene": "", - "selected": "", - "storage": "", - "title": "", - "total": "", - "width": "" + "angle": "각도", + "element": "요소", + "elements": "요소", + "height": "높이", + "scene": "화면", + "selected": "선택됨", + "storage": "저장공간", + "title": "덕후들을 위한 통계", + "total": "합계", + "width": "너비" } } diff --git a/src/locales/my-MM.json b/src/locales/my-MM.json index 06aa72464..dd355f5d7 100644 --- a/src/locales/my-MM.json +++ b/src/locales/my-MM.json @@ -1,6 +1,7 @@ { "labels": { "paste": "ထား", + "pasteCharts": "", "selectAll": "အကုန်ရွေး", "multiSelect": "ရွေးထားသည့်ထဲပုံထည့်", "moveCanvas": "ကားချပ်ရွှေ့", @@ -33,11 +34,11 @@ "arrowhead_none": "ဘာမျှမရှိ", "arrowhead_arrow": "မြှား", "arrowhead_bar": "", - "arrowhead_dot": "", + "arrowhead_dot": "အစက်", "fontSize": "စာလုံးအရွယ်", "fontFamily": "စာလုံးပုံစံ", "onlySelected": "ရွေးထားသလောက်", - "withBackground": "နောက်ခံပါထည့်", + "withBackground": "", "exportEmbedScene": "မြင်ကွင်းပါမြှုပ်နှံ၍ထုတ်ပါ", "exportEmbedScene_details": "ထုတ်ယူလိုက်သော PNG/SVG ထဲမြင်ကွင်းအချက်အလက်များပါဝင်သဖြင့် ပြန်လည်ရယူနိုင်သော်လည်း ဖိုင်အရွယ်အစားကြီးပါမည်။", "addWatermark": "\"Excalidraw ဖြင့်ဖန်တီးသည်။\" စာသားထည့်", @@ -76,8 +77,7 @@ "group": "အုပ်စုဖွဲ့", "ungroup": "အုပ်စုဖျက်သိမ်း", "collaborators": "ပူးပေါင်းပါဝင်သူများ", - "toggleGridMode": "ဇယားကွက်ဖော်/ဖျောက်", - "toggleStats": "", + "gridMode": "", "addToLibrary": "မှတ်တမ်းတင်", "removeFromLibrary": "မှတ်တမ်းမှထုတ်", "libraryLoadingMessage": "မှတ်တမ်းအား တင်သွင်းနေသည်...", @@ -118,9 +118,10 @@ "redo": "ထပ်လုပ်", "roomDialog": "တိုက်ရိုက်ပူးပေါင်းမှုစတင်", "createNewRoom": "အခန်းသစ်ဖွဲ့", - "toggleFullScreen": "မြင်ကွင်းကျယ်ဖွင့်/ပိတ်", - "toggleDarkMode": "အလင်း/အမှောင်", - "toggleZenMode": "ဇင်မြင်ကွင်းဖွင့်/ပိတ်", + "fullScreen": "", + "darkMode": "", + "lightMode": "", + "zenMode": "", "exitZenMode": "ဇင်မြင်ကွင်းမှထွက်" }, "alerts": { @@ -136,7 +137,7 @@ "loadSceneOverridePrompt": "လက်ရှိရေးဆွဲထားသမျှအား ပြင်ပမှတင်သွင်းသောပုံနှင့်အစားထိုးပါမည်။ ဆက်လက်ဆောင်ရွက်လိုပါသလား။", "errorLoadingLibrary": "ပြင်ပမှမှတ်တမ်းအားတင်သွင်းရာတွင်အမှားအယွင်းရှိနေသည်။", "confirmAddLibrary": "{{numShapes}} ခုသောပုံသဏ္ဌာန်အားမှတ်တမ်းတင်ပါမည်။ အတည်ပြုပါ။", - "imageDoesNotContainScene": "ပုံတွင် မြင်ကွင်းအချက်အလက်များမပါဝင်ပါ။ ပုံထုတ်ယူချိန်တွင်ထည့်သွင်းခဲ့ပါသလား။", + "imageDoesNotContainScene": "", "cannotRestoreFromImage": "ဤပုံဖြင့်မြင်ကွင်းပြန်လည်မရယူနိုင်ပါ။" }, "toolBar": { @@ -161,6 +162,7 @@ "freeDraw": "ကလစ်နှိပ်၍ တရွတ်ဆွဲပါ၊ ပြီးလျှင်လွှတ်ပါ။", "text": "မှတ်ချက်။ ။မည်သည့်ကိရိယာရွေးထားသည်ဖြစ်စေ ကလစ်နှစ်ချက်နှိပ်၍စာသားထည့်နိုင်သည်", "linearElementMulti": "နောက်ဆုံးအမှတ်ပေါ်တွင်ကလစ်နှိပ်ခြင်း၊ Escape (သို့) Enter နှိပ်ခြင်းတို့ဖြင့်အဆုံးသတ်နိုင်", + "lockAngle": "", "resize": "အချိုးအစားကန့်သတ်ရန် Shift နှင့် ဗဟိုမှချိန်ညှိရန် Alt တို့ကိုနှိပ်ထားနိုင်သည်", "rotate": "Shift ကိုနှိပ်ထားခြင်းဖြင့် ထောင့်အလိုက်လှည့်နိုင်သည်", "lineEditor_info": "အမှတ်များပြင်ဆင်သတ်မှတ်ရင် ကလစ်နှစ်ချက် (သို့) Enter ကိုနှိပ်ပါ", diff --git a/src/locales/nb-NO.json b/src/locales/nb-NO.json index 6bfe88f6a..7c0075672 100644 --- a/src/locales/nb-NO.json +++ b/src/locales/nb-NO.json @@ -1,6 +1,7 @@ { "labels": { "paste": "Lim inn", + "pasteCharts": "Lim inn diagrammer", "selectAll": "Velg alt", "multiSelect": "Legg til element i utvalg", "moveCanvas": "Flytt lerretet", @@ -37,7 +38,7 @@ "fontSize": "Skriftstørrelse", "fontFamily": "Fontfamilie", "onlySelected": "Kun valgte", - "withBackground": "Inkluder bakgrunn", + "withBackground": "Med bakgrunn", "exportEmbedScene": "Bygg inn scenen i den eksporterte filen", "exportEmbedScene_details": "Scenedata vil bli lagret i den eksporterte PNG/SVG-filen, slik at scenen kan gjenopprettes fra den.\nDet vil øke den eksporterte filstørrelsen.", "addWatermark": "Legg til \"Laget med Excalidraw\"", @@ -76,8 +77,7 @@ "group": "Gruppér utvalg", "ungroup": "Avgruppér utvalg", "collaborators": "Samarbeidspartnere", - "toggleGridMode": "Slå av/på rutenett", - "toggleStats": "Skru av/på statistikk for nerder", + "gridMode": "Rutevisning", "addToLibrary": "Legg til i bibliotek", "removeFromLibrary": "Fjern fra bibliotek", "libraryLoadingMessage": "Laster bibliotek...", @@ -118,9 +118,10 @@ "redo": "Gjør om", "roomDialog": "Start sanntids-samarbeid", "createNewRoom": "Opprett et nytt rom", - "toggleFullScreen": "Skru fullskjerm av/på", - "toggleDarkMode": "Skru mørk modus av/på", - "toggleZenMode": "Slå av/på zen-modus", + "fullScreen": "Fullskjerm", + "darkMode": "Mørk modus", + "lightMode": "Lys modus", + "zenMode": "Zen-modus", "exitZenMode": "Avslutt zen-modus" }, "alerts": { @@ -136,7 +137,7 @@ "loadSceneOverridePrompt": "Å laste inn ekstern tegning vil erstatte det eksisterende innholdet. Ønsker du å fortsette?", "errorLoadingLibrary": "Det oppstod en feil under lasting av tredjepartsbiblioteket.", "confirmAddLibrary": "Dette vil legge til {{numShapes}} figur(er) i biblioteket ditt. Er du sikker?", - "imageDoesNotContainScene": "Bildefilen inneholder ikke scenedata. Har du aktivert dette under eksport?", + "imageDoesNotContainScene": "Importering av bilder støttes ikke for øyeblikket.\n\nVil du importere en scene? Dette bildet ser ikke ut til å inneholde noen scene-data. Har du aktivert dette under eksporten?", "cannotRestoreFromImage": "Scenen kunne ikke gjenopprettes fra denne bildefilen" }, "toolBar": { @@ -161,6 +162,7 @@ "freeDraw": "Klikk og dra, slipp når du er ferdig", "text": "Tips: du kan også legge til tekst ved å dobbeltklikke hvor som helst med utvalgsverktøyet", "linearElementMulti": "Klikk på siste punkt eller trykk Escape eller Enter for å fullføre", + "lockAngle": "Du kan låse vinkelen ved å holde nede SHIFT", "resize": "Du kan beholde forholdet ved å trykke SHIFT mens du endrer størrelse,\ntrykk ALT for å endre størrelsen fra midten", "rotate": "Du kan låse vinklene ved å holde SHIFT mens du roterer", "lineEditor_info": "Dobbeltklikk eller trykk Enter for å redigere punkter", diff --git a/src/locales/nl-NL.json b/src/locales/nl-NL.json index e9df29cc4..59269210c 100644 --- a/src/locales/nl-NL.json +++ b/src/locales/nl-NL.json @@ -1,15 +1,16 @@ { "labels": { "paste": "Plakken", + "pasteCharts": "Plak grafieken", "selectAll": "Alles selecteren", "multiSelect": "Voeg element toe aan selectie", "moveCanvas": "Canvas verplaatsen", - "cut": "", + "cut": "Knip", "copy": "Kopiëren", "copyAsPng": "Kopieer als PNG", - "copyAsSvg": "Kopieer als SVG", + "copyAsSvg": "Kopieer naar klembord als SVG", "bringForward": "Breng naar voren", - "sendToBack": "Breng naar achtergrond", + "sendToBack": "Stuur naar achtergrond", "bringToFront": "Breng naar voorgrond", "sendBackward": "Breng naar achter", "delete": "Verwijderen", @@ -29,17 +30,17 @@ "edges": "Randen", "sharp": "Hoekig", "round": "Rond", - "arrowheads": "", - "arrowhead_none": "", - "arrowhead_arrow": "", - "arrowhead_bar": "", - "arrowhead_dot": "", + "arrowheads": "Pijlpunten", + "arrowhead_none": "Geen", + "arrowhead_arrow": "Pijl", + "arrowhead_bar": "Balk", + "arrowhead_dot": "Punt", "fontSize": "Tekstgrootte", "fontFamily": "Lettertype", "onlySelected": "Enkel geselecteerde", "withBackground": "Met achtergrond", - "exportEmbedScene": "", - "exportEmbedScene_details": "", + "exportEmbedScene": "Scène in geëxporteerd bestand invoegen", + "exportEmbedScene_details": "Scènegegevens worden in het geëxporteerde PNG/SVG-bestand opgeslagen zodat de scène kan worden hersteld.\nDe grootte van de geëxporteerde bestanden zal toenemen.", "addWatermark": "Voeg \"Gemaakt met Excalidraw\" toe", "handDrawn": "Handgetekend", "normal": "Normaal", @@ -60,7 +61,7 @@ "architect": "Architect", "artist": "Artiest", "cartoonist": "Cartoonist", - "fileTitle": "", + "fileTitle": "Bestandsnaam", "colorPicker": "Kleurenkiezer", "canvasBackground": "Canvas achtergrond", "drawingCanvas": "Canvas", @@ -69,29 +70,28 @@ "language": "Taal", "createRoom": "Deel een live-samenwerkingssessie", "duplicateSelection": "Dupliceer", - "untitled": "", + "untitled": "Naamloos", "name": "Naam", "yourName": "Jouw naam", "madeWithExcalidraw": "Gemaakt met Excalidraw", "group": "Groeperen", "ungroup": "Groep opheffen", "collaborators": "Deelnemers", - "toggleGridMode": "Rasterlijnen in-/uitschakelen", - "toggleStats": "", + "gridMode": "Rasterweergave", "addToLibrary": "Voeg toe aan bibliotheek", "removeFromLibrary": "Verwijder uit bibliotheek", "libraryLoadingMessage": "Bibliotheek laden...", - "libraries": "", + "libraries": "Blader door bibliotheken", "loadingScene": "Scène laden...", - "align": "", - "alignTop": "", - "alignBottom": "", - "alignLeft": "", - "alignRight": "", - "centerVertically": "", - "centerHorizontally": "", - "distributeHorizontally": "", - "distributeVertically": "" + "align": "Uitlijnen", + "alignTop": "Boven uitlijnen", + "alignBottom": "Onder uitlijnen", + "alignLeft": "Links uitlijnen", + "alignRight": "Rechts uitlijnen", + "centerVertically": "Verticaal Centreren", + "centerHorizontally": "Horizontaal Centreren", + "distributeHorizontally": "Horizontaal verspreiden", + "distributeVertically": "Verticaal distribueren" }, "buttons": { "clearReset": "Canvas opnieuw instellen", @@ -118,15 +118,16 @@ "redo": "Herstel ongedaan maken", "roomDialog": "Live-samenwerkingssessie starten", "createNewRoom": "Creëer live-samenwerkingssessie", - "toggleFullScreen": "Volledig scherm in-/uitschakelen", - "toggleDarkMode": "Donkere modus in-/uitschakelen", - "toggleZenMode": "Zen modus in-/uitschakelen", + "fullScreen": "Volledig scherm", + "darkMode": "Donkere modus", + "lightMode": "Lichte modus", + "zenMode": "Zen modus", "exitZenMode": "Verlaat zen modus" }, "alerts": { "clearReset": "Dit zal het hele canvas verwijderen. Weet je het zeker?", "couldNotCreateShareableLink": "Kon geen deelbare link aanmaken.", - "couldNotCreateShareableLinkTooBig": "", + "couldNotCreateShareableLinkTooBig": "Kan geen deelbare link aanmaken: de scène is te groot", "couldNotLoadInvalidFile": "Kan ongeldig bestand niet laden", "importBackendFailed": "Importeren vanuit backend mislukt.", "cannotExportEmptyCanvas": "Kan geen leeg canvas exporteren.", @@ -136,8 +137,8 @@ "loadSceneOverridePrompt": "Het laden van externe tekening zal uw bestaande inhoud vervangen. Wil je doorgaan?", "errorLoadingLibrary": "Bij het laden van de externe bibliotheek is een fout opgetreden.", "confirmAddLibrary": "Hiermee worden {{numShapes}} vorm(n) aan uw bibliotheek toegevoegd. Ben je het zeker?", - "imageDoesNotContainScene": "", - "cannotRestoreFromImage": "" + "imageDoesNotContainScene": "Afbeeldingen importeren wordt op dit moment niet ondersteund.\n\nWil je een scène importeren? Deze afbeelding lijkt geen scène gegevens te bevatten. Heb je dit geactiveerd tijdens het exporteren?", + "cannotRestoreFromImage": "Scène kan niet worden hersteld vanuit dit afbeeldingsbestand" }, "toolBar": { "selection": "Selectie", @@ -161,6 +162,7 @@ "freeDraw": "Klik en sleep, laat los als je klaar bent", "text": "Tip: je kunt tekst toevoegen door ergens dubbel te klikken met de selectietool", "linearElementMulti": "Klik op het laatste punt of druk op Escape of Enter om te stoppen", + "lockAngle": "Je kunt de hoek beperken door SHIFT ingedrukt te houden", "resize": "Houd tijdens het vergroten SHIFT ingedrukt om verhoudingen te behouden,\ngebruik ALT om vanuit het midden te vergroten/verkleinen", "rotate": "Je kan hoeken beperken door SHIFT ingedrukt te houden wanneer je draait", "lineEditor_info": "Dubbelklik of druk op Enter om punten te bewerken", @@ -168,9 +170,9 @@ "lineEditor_nothingSelected": "Selecteer een punt om te verplaatsen of te verwijderen, of houd Alt ingedrukt en klik om nieuwe punten toe te voegen" }, "canvasError": { - "cannotShowPreview": "", - "canvasTooBig": "", - "canvasTooBigTip": "" + "cannotShowPreview": "Kan voorbeeld niet tonen", + "canvasTooBig": "Het canvas is mogelijk te groot.", + "canvasTooBigTip": "Tip: beweeg de verste elementen iets dichter bij elkaar." }, "errorSplash": { "headingMain_pre": "Fout opgetreden. Probeer ", @@ -192,7 +194,7 @@ "button_stopSession": "Sessie afbreken", "desc_inProgressIntro": "De live-samenwerkingssessie is nu gestart.", "desc_shareLink": "Deel deze link met iedereen waarmee je wil samenwerken:", - "desc_exitSession": "" + "desc_exitSession": "Het stoppen van de sessie zal je loskoppelen van de kamer, maar je kunt lokaal doorwerken met de scène.\nPas op: dit heeft geen invloed op andere mensen en dat zij nog steeds in staat zullen zijn om samen te werken aan hun versie." }, "errorDialog": { "title": "Fout" @@ -213,22 +215,22 @@ "textNewLine": "Nieuwe regel toevoegen (tekst)", "textFinish": "Voltooi bewerken (tekst)", "zoomToFit": "Zoom in op alle elementen", - "zoomToSelection": "", - "preventBinding": "" + "zoomToSelection": "Inzoomen op selectie", + "preventBinding": "Pijlbinding voorkomen" }, "encrypted": { "tooltip": "Je tekeningen zijn beveiligd met end-to-end encryptie, dus Excalidraw's servers zullen nooit zien wat je tekent." }, "stats": { - "angle": "", - "element": "", - "elements": "", - "height": "", - "scene": "", - "selected": "", - "storage": "", - "title": "", - "total": "", - "width": "" + "angle": "Hoek", + "element": "Element", + "elements": "Elementen", + "height": "Hoogte", + "scene": "Scene", + "selected": "Geselecteerd", + "storage": "Opslag", + "title": "Statistieken voor nerds", + "total": "Totaal", + "width": "Breedte" } } diff --git a/src/locales/nn-NO.json b/src/locales/nn-NO.json index ead3e4c9d..5fa2f9971 100644 --- a/src/locales/nn-NO.json +++ b/src/locales/nn-NO.json @@ -1,10 +1,11 @@ { "labels": { "paste": "Lim inn", + "pasteCharts": "Lim inn diagrammer", "selectAll": "Vel alt", "multiSelect": "Legg til element i utval", "moveCanvas": "Flytt lerretet", - "cut": "", + "cut": "Klipp ut", "copy": "Kopier", "copyAsPng": "Kopier til utklippstavla som PNG", "copyAsSvg": "Kopier til utklippstavla som SVG", @@ -29,17 +30,17 @@ "edges": "Kanter", "sharp": "Skarp", "round": "Rund", - "arrowheads": "", - "arrowhead_none": "", - "arrowhead_arrow": "", - "arrowhead_bar": "", - "arrowhead_dot": "", + "arrowheads": "Pilhovud", + "arrowhead_none": "Ingen", + "arrowhead_arrow": "Pil", + "arrowhead_bar": "Stolpe", + "arrowhead_dot": "Prikk", "fontSize": "Skriftstorleik", "fontFamily": "Skrifttype", "onlySelected": "Kun valde", - "withBackground": "Inkluder bakgrunn", - "exportEmbedScene": "", - "exportEmbedScene_details": "", + "withBackground": "Med bakgrunn", + "exportEmbedScene": "Bygg scena inn i eksportert fil", + "exportEmbedScene_details": "Scenedata vert lagra i den eksporterte PNG- eller SVG-fila slik at scena kan bli gjenopprettast frå den. Dette vil auke eksportert filstorleik.", "addWatermark": "Legg til «Laga med Excalidraw»", "handDrawn": "Handteikna", "normal": "Normal", @@ -60,7 +61,7 @@ "architect": "Arkitekt", "artist": "Kunstnar", "cartoonist": "Teiknar", - "fileTitle": "", + "fileTitle": "Filnamn", "colorPicker": "Fargeveljar", "canvasBackground": "Lerretsbakgrunn", "drawingCanvas": "Lerret", @@ -69,29 +70,28 @@ "language": "Språk", "createRoom": "Del ei sanntids-samarbeidsøkt", "duplicateSelection": "Dupliser", - "untitled": "", + "untitled": "Utan namn", "name": "Namn", "yourName": "Namnet ditt", "madeWithExcalidraw": "Laga med Excalidraw", "group": "Grupper utval", "ungroup": "Avgrupper utval", "collaborators": "Samarbeidarar", - "toggleGridMode": "Sla på/av rutenett", - "toggleStats": "", + "gridMode": "Rutevisning", "addToLibrary": "Legg til i bibliotek", "removeFromLibrary": "Fjern frå bibliotek", "libraryLoadingMessage": "Laster bibliotek...", - "libraries": "", + "libraries": "Blad gjennom bibliotek", "loadingScene": "Laster scene...", - "align": "", - "alignTop": "", - "alignBottom": "", - "alignLeft": "", - "alignRight": "", - "centerVertically": "", - "centerHorizontally": "", - "distributeHorizontally": "", - "distributeVertically": "" + "align": "Juster", + "alignTop": "Juster til topp", + "alignBottom": "Juster til botn", + "alignLeft": "Juster til venstre", + "alignRight": "Juster til høgre", + "centerVertically": "Midtstill vertikalt", + "centerHorizontally": "Midtstill horisontalt", + "distributeHorizontally": "Sprei horisontalt", + "distributeVertically": "Sprei vertikalt" }, "buttons": { "clearReset": "Tilbakestill lerretet", @@ -100,7 +100,7 @@ "exportToSvg": "Eksporter til SVG", "copyToClipboard": "Kopier til utklippstavla", "copyPngToClipboard": "Kopier PNG til utklippstavla", - "scale": "", + "scale": "Skaler", "save": "Lagre", "saveAs": "Lagre som", "load": "Opne", @@ -118,15 +118,16 @@ "redo": "Gjer om", "roomDialog": "Start sanntids-samarbeid", "createNewRoom": "Lag nytt rom", - "toggleFullScreen": "Slå på/av fullskjerm", - "toggleDarkMode": "Skru av/på skumringsmodus", - "toggleZenMode": "Slå på/av zen-modus", + "fullScreen": "Fullskjerm", + "darkMode": "Mørk modus", + "lightMode": "Lys modus", + "zenMode": "Zen-modus", "exitZenMode": "Avslutt zen-modus" }, "alerts": { "clearReset": "Dette vil tømme lerretet. Er du sikker?", "couldNotCreateShareableLink": "Kunne ikkje lage delingslenke.", - "couldNotCreateShareableLinkTooBig": "", + "couldNotCreateShareableLinkTooBig": "Kunne ikkje opprette deleleg lenke: scena er for stor", "couldNotLoadInvalidFile": "Kunne ikkje laste inn ugyldig fil", "importBackendFailed": "Importering av backend feila.", "cannotExportEmptyCanvas": "Kan ikkje eksportere eit tomt lerret.", @@ -136,8 +137,8 @@ "loadSceneOverridePrompt": "Innlasting av ekstern teikning erstattar ditt eksisterande innhald. Ynskjer du å fortsette?", "errorLoadingLibrary": "Det oppstod ein feil under lastinga av tredjepartsbibliotek.", "confirmAddLibrary": "Dette vil legge til {{numShapes}} form(er) i biblioteket ditt. Er du sikker?", - "imageDoesNotContainScene": "", - "cannotRestoreFromImage": "" + "imageDoesNotContainScene": "Importering av bilder støttes ikkje for p. t.\n\nVil du importere ein scene? Dette bildet ser ikkje ut til å inneholde noen scene-data. Har du aktivert dette under eksporten?", + "cannotRestoreFromImage": "Scena kunne ikkje gjenopprettast frå denne biletfila" }, "toolBar": { "selection": "Vel", @@ -161,6 +162,7 @@ "freeDraw": "Klikk og drag, slepp når du er ferdig", "text": "Tips: du kan òg leggje til tekst ved å dobbeltklikke kor som helst med utvalgsverktyet", "linearElementMulti": "Klikk på siste punkt eller trykk Escape eller Enter for å fullføre", + "lockAngle": "Du kan begrense vinkelen ved å holde nede SKIFT", "resize": "Du kan halde fram med forholdet ved å trykke SHIFT medan du endrar storleik,\ntrykk ALT for å endre storleiken frå midten", "rotate": "Du kan låse vinklane ved å halde SHIFT medan du roterer", "lineEditor_info": "Dobbeltklikk eller trykk Enter for å redigere punkt", @@ -168,9 +170,9 @@ "lineEditor_nothingSelected": "Vel eit punkt å flytte eller fjerne, eller hald Alt og klikk for å legge til nye punkt" }, "canvasError": { - "cannotShowPreview": "", - "canvasTooBig": "", - "canvasTooBigTip": "" + "cannotShowPreview": "Kan ikkje vise førehandsvising", + "canvasTooBig": "Lerretet er mogleg for stort.", + "canvasTooBigTip": "Tips: prøv å flytte elementa som er lengst frå kvarandre, litt nærare kvarandre." }, "errorSplash": { "headingMain_pre": "Ein feil oppstod. Prøv ", @@ -213,22 +215,22 @@ "textNewLine": "Legg til ny linje (tekst)", "textFinish": "Fullfør redigering (tekst)", "zoomToFit": "Zoom for å sjå alle elementa", - "zoomToSelection": "", + "zoomToSelection": "Zoom til utval", "preventBinding": "Hindre pilkobling" }, "encrypted": { "tooltip": "Teikningane dine er ende-til-ende-krypterte slik at Excalidraw sine serverar aldri får sjå dei." }, "stats": { - "angle": "", - "element": "", - "elements": "", - "height": "", - "scene": "", - "selected": "", - "storage": "", - "title": "", - "total": "", - "width": "" + "angle": "Vinkel", + "element": "Element", + "elements": "Element", + "height": "Høgde", + "scene": "Scene", + "selected": "Valde", + "storage": "Lagring", + "title": "Statistikk for nerdar", + "total": "Totalt", + "width": "Breidde" } } diff --git a/src/locales/pa-IN.json b/src/locales/pa-IN.json new file mode 100644 index 000000000..8cf973761 --- /dev/null +++ b/src/locales/pa-IN.json @@ -0,0 +1,236 @@ +{ + "labels": { + "paste": "ਪੇਸਟ ਕਰੋ", + "pasteCharts": "ਚਾਰਟ ਪੇਸਟ ਕਰੋ", + "selectAll": "ਸਾਰੇ ਚੁਣੋ", + "multiSelect": "ਐਲੀਮੈਂਟ ਨੂੰ ਚੋਣ ਵਿੱਚ ਜੋੜੋ", + "moveCanvas": "ਕੈਨਵਸ ਹਿਲਾਓ", + "cut": "ਕੱਟੋ", + "copy": "ਕਾਪੀ ਕਰੋ", + "copyAsPng": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ PNG ਵਜੋਂ ਕਾਪੀ ਕਰੋ", + "copyAsSvg": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ SVG ਵਜੋਂ ਕਾਪੀ ਕਰੋ", + "bringForward": "ਅੱਗੇ ਲਿਆਓ", + "sendToBack": "ਸਭ ਤੋਂ ਪਿੱਛੇ ਭੇਜੋ", + "bringToFront": "ਸਭ ਤੋਂ ਅੱਗੇ ਲਿਆਓ", + "sendBackward": "ਪਿੱਛੇ ਭੇਜੋ", + "delete": "ਮਿਟਾਓ", + "copyStyles": "ਸਟਾਇਲ ਕਾਪੀ ਕਰੋ", + "pasteStyles": "ਸਟਾਇਲ ਪੇਸਟ ਕਰੋ", + "stroke": "ਰੇਖਾ", + "background": "ਬੈਕਗਰਾਉਂਡ", + "fill": "ਭਰਨਾ", + "strokeWidth": "ਰੇਖਾ ਦੀ ਚੌੜਾਈ", + "strokeStyle": "ਰੇਖਾ ਦਾ ਸਟਾਇਲ", + "strokeStyle_solid": "ਠੋਸ", + "strokeStyle_dashed": "ਡੈਸ਼ ਵਾਲੀ", + "strokeStyle_dotted": "ਬਿੰਦੀਆਂ ਵਾਲੀ", + "sloppiness": "ਬੇਤਰਤੀਬੀ", + "opacity": "ਅਪਾਰਦਰਸ਼ਤਾ", + "textAlign": "ਲਿਖਤ ਇਕਸਾਰਤਾ", + "edges": "ਕਿਨਾਰੇ", + "sharp": "ਤਿੱਖੇ", + "round": "ਗੋਲ", + "arrowheads": "ਤੀਰ ਦੇ ਸਿਰੇ", + "arrowhead_none": "ਕੋਈ ਨਹੀਂ", + "arrowhead_arrow": "ਤੀਰ", + "arrowhead_bar": "ਡੰਡੀ", + "arrowhead_dot": "ਬਿੰਦੀ", + "fontSize": "ਫੌਂਟ ਅਕਾਰ", + "fontFamily": "ਫੌਂਟ ਪਰਿਵਾਰ", + "onlySelected": "ਸਿਰਫ ਚੁਣੇ ਹੋਏ ਹੀ", + "withBackground": "ਬੈਕਗਰਾਉਂਂਡ ਨਾਲ", + "exportEmbedScene": "ਦ੍ਰਿਸ਼ ਨੂੰ ਨਿਰਯਾਤ ਕੀਤੀ ਫਾਈਲ ਵਿੱਚ ਮੜ੍ਹੋ", + "exportEmbedScene_details": "ਦ੍ਰਿਸ਼ ਦਾ ਡਾਟਾ ਨਿਰਯਾਤ ਕੀਤੀ PNG/SVG ਫਾਈਲ ਵਿੱਚ ਸਾਂਭ ਦਿੱਤਾ ਜਾਵੇਗਾ ਤਾਂ ਜੋ ਇਸ ਵਿੱਚੋਂ ਦ੍ਰਿਸ਼ ਨੂੰ ਬਹਾਲ ਕੀਤਾ ਜਾ ਸਕੇ। ਇਹ ਨਿਰਯਾਤ ਕੀਤੀ ਜਾਣ ਵਾਲੀ ਫਾਈਲ ਦਾ ਅਕਾਰ ਵਧਾ ਦੇਵੇਗਾ।", + "addWatermark": "\"Excalidraw ਨਾਲ ਬਣਾਇਆ\" ਜੋੜੋ", + "handDrawn": "ਹੱਥਲਿਖਤ", + "normal": "ਆਮ", + "code": "ਕੋਡ", + "small": "ਛੋਟਾ", + "medium": "ਮੱਧਮ", + "large": "ਵੱਡਾ", + "veryLarge": "ਬਹੁਤ ਵੱਡਾ", + "solid": "ਠੋਸ", + "hachure": "ਤਿਰਛੀਆਂ ਗਰਿੱਲਾਂ", + "crossHatch": "ਜਾਲੀ", + "thin": "ਪਤਲੀ", + "bold": "ਮੋਟੀ", + "left": "ਖੱਬੇ", + "center": "ਵਿਚਕਾਰ", + "right": "ਸੱਜੇ", + "extraBold": "ਬਹੁਤ ਮੋਟੀ", + "architect": "ਭਵਨ ਨਿਰਮਾਣਕਾਰੀ", + "artist": "ਕਲਾਕਾਰ", + "cartoonist": "ਕਾਰਟੂਨਿਸਟ", + "fileTitle": "ਫਾਈਲ ਦਾ ਸਿਰਨਾਵਾਂ", + "colorPicker": "ਰੰਗ ਚੋਣਕਾਰ", + "canvasBackground": "ਕੈਨਵਸ ਦਾ ਬੈਕਗਰਾਉਂਡ", + "drawingCanvas": "ਡਰਾਇੰਗ ਕੈਨਵਸ", + "layers": "ਪਰਤਾਂ", + "actions": "ਕਾਰਵਾਈਆਂ", + "language": "ਭਾਸ਼ਾ", + "createRoom": "ਲਾਇਵ ਸਹਿਯੋਗ ਇਜਲਾਸ ਸਾਂਝਾ ਕਰੋ", + "duplicateSelection": "ਡੁਪਲੀਕੇਟ ਬਣਾਓ", + "untitled": "ਬੇ-ਸਿਰਨਾਵਾਂ", + "name": "ਨਾਂ", + "yourName": "ਤੁਹਾਡਾ ਨਾਂ", + "madeWithExcalidraw": "Excalidraw ਨਾਲ ਬਣਾਇਆ", + "group": "ਚੋਣ ਦਾ ਗਰੁੱਪ ਬਣਾਓ", + "ungroup": "ਚੋਣ ਦਾ ਗਰੁੱਪ ਤੋੜੋ", + "collaborators": "ਸਹਿਯੋਗੀ", + "gridMode": "ਜਾਲੀਦਾਰ ਮੋਡ", + "addToLibrary": "ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚ ਜੋੜੋ", + "removeFromLibrary": "ਲਾਇਬ੍ਰੇਰੀ 'ਚੋਂ ਹਟਾਓ", + "libraryLoadingMessage": "ਲਾਇਬ੍ਰੇਰੀ ਲੋਡ ਕੀਤੀ ਜਾ ਰਹੀ ਹੈ...", + "libraries": "ਲਾਇਬ੍ਰੇਰੀਆਂ ਬਰਾਉਜ਼ ਕਰੋ", + "loadingScene": "ਦ੍ਰਿਸ਼ ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ...", + "align": "ਇਕਸਾਰ", + "alignTop": "ਉੱਪਰ ਇਕਸਾਰ ਕਰੋ", + "alignBottom": "ਹੇਠਾਂ ਇਕਸਾਰ ਕਰੋ", + "alignLeft": "ਖੱਬੇ ਇਕਸਾਰ ਕਰੋ", + "alignRight": "ਸੱਜੇ ਇਕਸਾਰ ਕਰੋ", + "centerVertically": "ਲੇਟਵੇਂ ਵਿਚਕਾਰ ਕਰੋ", + "centerHorizontally": "ਖੜ੍ਹਵੇਂ ਵਿਚਕਾਰ ਕਰੋ", + "distributeHorizontally": "ਖੜ੍ਹਵੇਂ ਇਕਸਾਰ ਵੰਡੋ", + "distributeVertically": "ਲੇਟਵੇਂ ਇਕਸਾਰ ਵੰਡੋ" + }, + "buttons": { + "clearReset": "ਕੈਨਵਸ ਰੀਸੈੱਟ ਕਰੋ", + "export": "ਨਿਰਯਾਤ", + "exportToPng": "PNG ਵਿੱਚ ਨਿਰਯਾਤ ਕਰੋ", + "exportToSvg": "SVG ਵਿੱਚ ਨਿਰਯਾਤ ਕਰੋ", + "copyToClipboard": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ ਕਾਪੀ ਕਰੋ", + "copyPngToClipboard": "PNG ਨੂੰ ਕਲਿੱਪਬੋਰਡ 'ਤੇ ਕਾਪੀ ਕਰੋ", + "scale": "ਪੈਮਾਇਸ਼", + "save": "ਸਾਂਭੋ", + "saveAs": "ਇਸ ਵਜੋਂ ਸਾਂਭੋ", + "load": "ਲੋਡ ਕਰੋ", + "getShareableLink": "ਸਾਂਝੀ ਕਰਨ ਵਾਲੀ ਲਿੰਕ ਲਵੋ", + "close": "ਬੰਦ ਕਰੋ", + "selectLanguage": "ਭਾਸ਼ਾ ਚੁਣੋ", + "scrollBackToContent": "ਸਮੱਗਰੀ 'ਤੇ ਵਾਪਸ ਸਕਰੋਲ ਕਰੋ", + "zoomIn": "ਜ਼ੂਮ ਵਧਾਓ", + "zoomOut": "ਜ਼ੂਮ ਘਟਾਓ", + "resetZoom": "ਜ਼ੂਮ ਰੀਸੈੱਟ ਕਰੋ", + "menu": "ਮੇਨੂ", + "done": "ਹੋ ਗਿਆ", + "edit": "ਸੋਧੋ", + "undo": "ਅਣਕੀਤਾ ਕਰੋ", + "redo": "ਮੁੜ-ਕਰੋ", + "roomDialog": "ਲਾਇਵ ਸਹਿਯੋਗ ਸ਼ੁਰੂ ਕਰੋ", + "createNewRoom": "ਨਵਾਂ ਕਮਰਾ ਬਣਾਓ", + "fullScreen": "ਪੂਰੀ ਸਕਰੀਨ", + "darkMode": "ਡਾਰਕ ਮੋਡ", + "lightMode": "ਲਾਇਟ ਮੋਡ", + "zenMode": "ਜ਼ੈੱਨ ਮੋਡ", + "exitZenMode": "ਜ਼ੈੱਨ ਮੋਡ 'ਚੋਂ ਬਾਹਰ ਨਿਕਲੋ" + }, + "alerts": { + "clearReset": "ਇਹ ਸਾਰਾ ਕੈਨਵਸ ਸਾਫ ਕਰ ਦੇਵੇਗਾ। ਕੀ ਤੁਸੀਂ ਪੱਕਾ ਇੰਝ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?", + "couldNotCreateShareableLink": "ਸਾਂਝੀ ਕਰਨ ਵਾਲੀ ਲਿੰਕ ਨਹੀਂ ਬਣਾ ਸਕੇ।", + "couldNotCreateShareableLinkTooBig": "ਸਾਂਝੀ ਕਰਨ ਵਾਲੀ ਲਿੰਕ ਨਹੀਂ ਬਣਾ ਸਕੇ: ਦ੍ਰਿਸ਼ ਬਹੁਤ ਵੱਡਾ ਹੈ", + "couldNotLoadInvalidFile": "ਨਜਾਇਜ਼ ਫਾਈਲ ਲੋਡ ਨਹੀਂ ਕਰ ਸਕੇ", + "importBackendFailed": "ਬੈਕਐੱਨਡ ਤੋਂ ਆਯਾਤ ਕਰਨ ਵਿੱਚ ਅਸਫਲ ਰਹੇ।", + "cannotExportEmptyCanvas": "ਖਾਲੀ ਕੈਨਵਸ ਨਿਰਯਾਤ ਨਹੀਂ ਕਰ ਸਕਦੇ।", + "couldNotCopyToClipboard": "ਕਲਿੱਪਬੋਰਡ 'ਤੇ ਕਾਪੀ ਨਹੀਂ ਕਰ ਸਕੇ। ਕਰੋਮ ਬਰਾਉਜ਼ਰ ਵਰਤ ਕੇ ਦੇਖੋ।", + "decryptFailed": "ਡਾਟਾ ਡੀਕਰਿਪਟ ਨਹੀਂ ਕਰ ਸਕੇ।", + "uploadedSecurly": "ਅੱਪਲੋਡ ਸਿਰੇ-ਤੋਂ-ਸਿਰੇ ਤੱਕ ਇਨਕਰਿਪਸ਼ਨ ਨਾਲ ਸੁਰੱਖਿਅਤ ਕੀਤੀ ਹੋਈ ਹੈ, ਜਿਸਦਾ ਮਤਲਬ ਇਹ ਹੈ ਕਿ Excalidraw ਸਰਵਰ ਅਤੇ ਤੀਜੀ ਧਿਰ ਦੇ ਬੰਦੇ ਸਮੱਗਰੀ ਨੂੰ ਪੜ੍ਹ ਨਹੀਂ ਸਕਦੇ।", + "loadSceneOverridePrompt": "ਬਾਹਰੀ ਡਰਾਇੰਗ ਨੂੰ ਲੋਡ ਕਰਨਾ ਤੁਹਾਡੀ ਮੌਜੂਦਾ ਸਮੱਗਰੀ ਦੀ ਥਾਂ ਲੈ ਲਵੇਗਾ। ਕੀ ਤੁਸੀਂ ਜਾਰੀ ਰੱਖਣਾ ਚਾਹੁੰਦੇ ਹੋ?", + "errorLoadingLibrary": "ਤੀਜੀ ਧਿਰ ਦੀ ਲਾਇਬ੍ਰੇਰੀ ਨੂੰ ਲੋਡ ਕਰਨ ਵਿੱਚ ਗਲਤੀ ਹੋਈ ਸੀ।", + "confirmAddLibrary": "ਇਹ ਤੁਹਾਡੀ ਲਾਇਬ੍ਰੇਰੀ ਵਿੱਚ {{numShapes}} ਆਕ੍ਰਿਤੀ(ਆਂ) ਨੂੰ ਜੋੜ ਦੇਵੇਗਾ। ਕੀ ਤੁਸੀਂ ਪੱਕਾ ਇੰਝ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ?", + "imageDoesNotContainScene": "ਫਿਲਹਾਲ ਤਸਵੀਰਾਂ ਨੂੰ ਆਯਾਤ ਕਰਨ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦਾ।\n\nਕੀ ਤੁਸੀਂ ਦ੍ਰਿਸ਼ ਨੂੰ ਆਯਾਤ ਕਰਨਾ ਚਾਹੁੰਦੇ ਸੀ? ਇਸ ਤਸਵੀਰ ਵਿੱਚ ਦ੍ਰਿਸ਼ ਦਾ ਕੋਈ ਵੀ ਡਾਟਾ ਨਜ਼ਰ ਨਹੀਂ ਆ ਰਿਹਾ। ਕੀ ਨਿਰਯਾਤ ਦੌਰਾਨ ਤੁਸੀਂ ਇਹ ਸਮਰੱਥ ਕੀਤਾ ਸੀ?", + "cannotRestoreFromImage": "ਇਸ ਤਸਵੀਰ ਫਾਈਲ ਤੋਂ ਦ੍ਰਿਸ਼ ਬਹਾਲ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਿਆ" + }, + "toolBar": { + "selection": "ਚੋਣਕਾਰ", + "draw": "ਖੁੱਲ੍ਹੀ ਵਾਹੀ", + "rectangle": "ਆਇਤ", + "diamond": "ਹੀਰਾ", + "ellipse": "ਅੰਡਾਕਾਰ", + "arrow": "ਤੀਰ", + "line": "ਲਕੀਰ", + "text": "ਪਾਠ", + "library": "ਲਾਇਬ੍ਰੇਰੀ", + "lock": "ਡਰਾਇੰਗ ਤੋਂ ਬਾਅਦ ਵੀ ਚੁਣੇ ਹੋਏ ਸੰਦ ਨੂੰ ਸਰਗਰਮ ਰੱਖੋ " + }, + "headings": { + "canvasActions": "ਕੈਨਵਸ ਦੀਆਂ ਕਾਰਵਾਈਆਂ", + "selectedShapeActions": "ਚੁਣੀ ਆਕ੍ਰਿਤੀ ਦੀਆਂ ਕਾਰਵਾਈਆਂ", + "shapes": "ਆਕ੍ਰਿਤੀਆਂ" + }, + "hints": { + "linearElement": "ਇੱਕ ਤੋਂ ਜ਼ਿਆਦਾ ਬਿੰਦੂਆਂ ਲਈ ਕਲਿੱਕ ਕਰਕੇ ਸ਼ੁਰੂਆਤ ਕਰੋ, ਇਕਹਿਰੀ ਲਕੀਰ ਲਈ ਘਸੀਟੋ", + "freeDraw": "ਕਲਿੱਕ ਕਰਕੇ ਘਸੀਟੋ, ਪੂਰਾ ਹੋਣ 'ਤੇ ਛੱਡ ਦਿਉ", + "text": "ਨੁਸਖਾ: ਤੁਸੀਂ ਚੋਣਕਾਰ ਸੰਦ ਰਾਹੀਂ ਕਿਤੇ ਵੀ ਡਬਲ-ਕਲਿੱਕ ਕਰਕੇ ਵੀ ਪਾਠ ਜੋੜ ਸਕਦੇ ਹੋ", + "linearElementMulti": "ਮੁਕੰਮਲ ਕਰਨ ਲਈ ਆਖਰੀ ਬਿੰਦੂ 'ਤੇ ਕਲਿੱਕ ਕਰੋ ਜਾਂ ਇਸਕੇਪ ਜਾਂ ਐਂਟਰ ਦਬਾਓ", + "lockAngle": "ਤੁਸੀਂ SHIFT ਦਬਾਈ ਰੱਖ ਕੇ ਕੋਣਾਂ ਨੂੰ ਕਾਬੂ ਕਰ ਸਕਦੇ ਹੋ", + "resize": "ਤੁਸੀਂ ਅਕਾਰ ਬਦਲਦੇ ਸਮੇਂ SHIFT ਦਬਾਈ ਰੱਖ ਕੇ ਅਨੁਪਾਤ ਨੂੰ ਕਾਬੂ ਕਰ ਸਕਦੇ ਹੋ, ਵਿਚਕਾਰ ਤੋਂ ਅਕਾਰ ਬਦਲਣ ਲਈ ALT ਦਬਾਓ", + "rotate": "ਤੁਸੀਂ ਘੁਮਾਉਂਦੇ ਹੋਏ SHIFT ਦਬਾਈ ਰੱਖ ਕੇ ਕੋਣਾਂ ਨੂੰ ਕਾਬੂ ਕਰ ਸਕਦੇ ਹੋ", + "lineEditor_info": "ਬਿੰਦੂਆਂ ਨੂੰ ਸੋਧਣ ਲਈ ਡਬਲ-ਕਲਿੱਕ ਜਾਂ ਐਂਟਰ ਦਬਾਓ", + "lineEditor_pointSelected": "ਬਿੰਦੀ ਹਟਾਉਣ ਲਈ ਡਲੀਟ ਦਬਾਓ, ਡੁਪਲੀਕੇਟ ਬਣਾਉਣ ਲਈ CtrlOrCmd+D, ਜਾਂ ਹਿਲਾਉਣ ਲਈ ਘਸੀਟੋ", + "lineEditor_nothingSelected": "ਹਿਲਾਉਣ ਜਾਂ ਹਟਾਉਣ ਲਈ ਬਿੰਦੂ ਚੁਣੋ, ਜਾਂ ਨਵਾਂ ਬਿੰਦੂ ਜੋੜਨ ਲਈ Alt ਦਬਾਕੇ ਕਲਿੱਕ ਕਰੋ" + }, + "canvasError": { + "cannotShowPreview": "ਝਲਕ ਨਹੀਂ ਦਿਖਾ ਸਕਦੇ", + "canvasTooBig": "ਸ਼ਾਇਦ ਕੈਨਵਸ ਬਹੁਤ ਜ਼ਿਆਦਾ ਵੱਡਾ ਹੈ।", + "canvasTooBigTip": "ਨੁਸਖਾ: ਸਭ ਤੋਂ ਦੂਰ ਸਥਿੱਤ ਐਲੀਮੈਂਟਾਂ ਨੂੰ ਥੋੜ੍ਹਾ ਜਿਹਾ ਨੇੜੇ ਲਿਆ ਕੇ ਦੇਖੋ।" + }, + "errorSplash": { + "headingMain_pre": "ਗਲਤੀ ਹੋਈ। ਇਹ ਕਰਕੇ ਦੇਖੋ ", + "headingMain_button": "ਪੰਨਾ ਮੁੜ-ਲੋਡ ਕਰੋ।", + "clearCanvasMessage": "ਜੇ ਮੁੜ-ਲੋਡ ਕਰਨਾ ਕੰਮ ਨਾ ਕਰੇ, ਤਾਂ ਇਹ ਕਰਕੇ ਦੇਖੋ ", + "clearCanvasMessage_button": "ਕੈਨਵਸ ਸਾਫ ਕਰੋ।", + "clearCanvasCaveat": " ਇਹ ਸਾਰਾ ਕੰਮ ਗਵਾ ਦੇਵੇਗਾ ", + "trackedToSentry_pre": "ਗਲਤੀ ਸੂਚਕ ", + "trackedToSentry_post": " ਸਾਡੇ ਸਿਸਟਮ 'ਤੇ ਟਰੈਕ ਕੀਤਾ ਗਿਆ ਸੀ।", + "openIssueMessage_pre": "ਅਸੀਂ ਬੜੇ ਸਾਵਧਾਨ ਸੀ ਕਿ ਗਲਤੀ ਵਿੱਚ ਤੁਹਾਡੇ ਦ੍ਰਿਸ਼ ਦੀ ਜਾਣਕਾਰੀ ਸ਼ਾਮਲ ਨਾ ਕਰੀਏ। ਜੇ ਤੁਹਾਡਾ ਦ੍ਰਿਸ਼ ਨਿੱਜੀ ਨਹੀਂ ਹੈ ਤਾਂ ਇਸ 'ਤੇ ਸਾਡੇ ਨਾਲ ਸੰਪਰਕ ਕਰੋ ਜੀ ", + "openIssueMessage_button": "ਬੱਗ ਟਰੈਕਰ।", + "openIssueMessage_post": "ਹੇਠਾਂ ਦਿੱਤੀ ਜਾਣਕਾਰੀ ਨੂੰ ਕਾਪੀ ਕਰਕੇ ਗਿੱਟਹੱਬ ਮੁੱਦੇ ਵਿੱਚ ਪੇਸਟ ਕਰਕੇ ਸ਼ਾਮਲ ਕਰੋ ਜੀ।", + "sceneContent": "ਦ੍ਰਿਸ਼ ਦੀ ਸਮੱਗਰੀ:" + }, + "roomDialog": { + "desc_intro": "ਤੁਸੀਂ ਲੋਕਾਂ ਨੂੰ ਆਪਣੇ ਨਾਲ ਮੌਜੂਦਾ ਦ੍ਰਿਸ਼ 'ਤੇ ਸਹਿਯੋਗ ਕਰਨ ਲਈ ਸੱਦਾ ਭੇਜ ਸਕਦੇ ਹੋ।", + "desc_privacy": "ਫਿਕਰ ਨਾ ਕਰੋ, ਇਜਲਾਸ ਸਿਰੇ-ਤੋਂ-ਸਿਰੇ ਤੱਕ ਇਨਕਰਿਪਸ਼ਨ ਵਰਤਦਾ ਹੈ, ਸੋ ਜੋ ਕੁਝ ਵੀ ਤੁਸੀਂ ਵਾਹੁੰਦੇ ਹੋ ਉਹ ਨਿੱਜੀ ਹੀ ਰਹਿੰਦਾ ਹੈ। ਇੱਥੋਂ ਤੱਕ ਕਿ ਸਾਡੇ ਸਰਵਰ ਵੀ ਨਹੀਂ ਜਾਣ ਸਕਣਗੇ ਕਿ ਤੁਸੀਂ ਕੀ ਬਣਾਇਆ ਹੈ।", + "button_startSession": "ਇਜਲਾਸ ਸ਼ੁਰੂ ਕਰੋ", + "button_stopSession": "ਇਜਲਾਸ ਰੋਕੋ", + "desc_inProgressIntro": "ਲਾਇਵ ਸਹਿਯੋਗ ਹੁਣ ਚੱਲ ਰਿਹਾ ਹੈ।", + "desc_shareLink": "ਇਸ ਲਿੰਕ ਨੂੰ ਉਹਨਾਂ ਨਾਲ ਸਾਂਝਾ ਕਰੋ ਜਿਹਨਾਂ ਨਾਲ ਤੁਸੀਂ ਸਹਿਯੋਗ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ:", + "desc_exitSession": "ਇਜਲਾਸ ਨੂੰ ਰੋਕਣਾ ਤੁਹਾਡਾ ਕਮਰੇ ਨਾਲੋਂ ਨਾਤਾ ਤੋੜ ਦੇਵੇਗਾ, ਪਰ ਤੁਸੀਂ ਸਥਾਨਕ ਪੱਧਰ 'ਤੇ ਦ੍ਰਿਸ਼ ਨਾਲ ਕੰਮ ਕਰਨਾ ਜਾਰੀ ਰੱਖ ਸਕੋਗੇ। ਇਹ ਧਿਆਨ 'ਚ ਰੱਖੋ ਕਿ ਇਹ ਬਾਕੀ ਲੋਕਾਂ ਨੂੰ ਪ੍ਰਭਾਵਿਤ ਨਹੀਂ ਕਰੇਗਾ , ਅਤੇ ਉਹ ਹਾਲੇ ਵੀ ਆਪਣੇ ਸੰਸਕਰਨ 'ਤੇ ਸਹਿਯੋਗ ਕਰਨ ਦੇ ਕਾਬਲ ਹੋਣਗੇ।" + }, + "errorDialog": { + "title": "ਗਲਤੀ" + }, + "shortcutsDialog": { + "title": "ਕੀਬੋਰਡ ਸ਼ਾਰਟਕੱਟ", + "shapes": "ਆਕ੍ਰਿਤੀਆਂ", + "or": "ਜਾਂ", + "click": "ਕਲਿੱਕ", + "drag": "ਘਸੀਟੋ", + "curvedArrow": "ਵਿੰਗਾ ਤੀਰ", + "curvedLine": "ਵਿੰਗੀ ਲਕੀਰ", + "editor": "ਸੋਧਕ", + "view": "ਦਿੱਖ", + "blog": "ਸਾਡਾ ਬਲੌਗ ਪੜ੍ਹੋ", + "howto": "ਸਾਡੀਆਂ ਗਾਈਡਾਂ ਦੀ ਪਾਲਣਾ ਕਰੋ", + "github": "ਕੋਈ ਸਮੱਸਿਆ ਲੱਭੀ? ਜਮ੍ਹਾਂ ਕਰਵਾਓ", + "textNewLine": "ਨਵੀਂ ਪੰਕਤੀ ਜੋੜੋ (ਪਾਠ)", + "textFinish": "ਸੋਧ ਮੁਕੰਮਲ ਕਰੋ (ਪਾਠ)", + "zoomToFit": "ਸਾਰੇ ਐਲੀਮੈਂਟਾਂ ਨੂੰ ਫਿੱਟ ਕਰਨ ਲਈ ਜ਼ੂਮ ਕਰੋ", + "zoomToSelection": "ਚੋਣ ਤੱਕ ਜ਼ੂਮ ਕਰੋ", + "preventBinding": "ਤੀਰ ਬੱਝਣਾ ਰੋਕੋ" + }, + "encrypted": { + "tooltip": "ਤੁਹਾਡੀ ਡਰਾਇੰਗਾਂ ਸਿਰੇ-ਤੋਂ-ਸਿਰੇ ਤੱਕ ਇਨਕਰਿਪਟ ਕੀਤੀਆਂ ਹੋਈਆਂ ਹਨ, ਇਸ ਲਈ Excalidraw ਦੇ ਸਰਵਰ ਉਹਨਾਂ ਨੂੰ ਕਦੇ ਵੀ ਨਹੀਂ ਦੇਖਣਗੇ।" + }, + "stats": { + "angle": "ਕੋਣ", + "element": "ਐਲੀਮੈਂਟ", + "elements": "ਐਲੀਮੈਂਟ", + "height": "ਉਚਾਈ", + "scene": "ਦ੍ਰਿਸ਼", + "selected": "ਚੁਣੇ", + "storage": "ਸਟੋਰੇਜ", + "title": "ਪੜਾਕੂਆਂ ਲਈ ਅੰਕੜੇ", + "total": "ਕੁੱਲ", + "width": "ਚੌੜਾਈ" + } +} diff --git a/src/locales/percentages.json b/src/locales/percentages.json index 253a489ac..67431c563 100644 --- a/src/locales/percentages.json +++ b/src/locales/percentages.json @@ -1,33 +1,35 @@ { - "ar-SA": 89, - "bg-BG": 61, - "ca-ES": 81, - "de-DE": 99, - "el-GR": 95, + "ar-SA": 100, + "bg-BG": 100, + "ca-ES": 100, + "de-DE": 100, + "el-GR": 100, "en": 100, - "es-ES": 81, - "fa-IR": 89, + "es-ES": 100, + "fa-IR": 100, "fi-FI": 100, "fr-FR": 100, - "he-IL": 69, - "hi-IN": 82, - "hu-HU": 44, - "id-ID": 99, + "he-IL": 100, + "hi-IN": 100, + "hu-HU": 100, + "id-ID": 100, "it-IT": 100, - "ja-JP": 89, - "ko-KR": 68, - "my-MM": 96, + "ja-JP": 85, + "ko-KR": 100, + "my-MM": 93, "nb-NO": 100, - "nl-NL": 80, - "nn-NO": 80, - "pl-PL": 79, - "pt-PT": 83, + "nl-NL": 100, + "nn-NO": 100, + "pa-IN": 100, + "pl-PL": 100, + "pt-BR": 100, + "pt-PT": 100, "ro-RO": 100, - "ru-RU": 81, + "ru-RU": 100, "sk-SK": 100, "sv-SE": 100, - "tr-TR": 81, - "uk-UA": 98, - "zh-CN": 95, - "zh-TW": 99 + "tr-TR": 100, + "uk-UA": 100, + "zh-CN": 100, + "zh-TW": 100 } diff --git a/src/locales/pl-PL.json b/src/locales/pl-PL.json index 272f0f07e..3a57524e9 100644 --- a/src/locales/pl-PL.json +++ b/src/locales/pl-PL.json @@ -1,10 +1,11 @@ { "labels": { "paste": "Wklej", + "pasteCharts": "Wklej wykresy", "selectAll": "Zaznacz wszystko", "multiSelect": "Dodaj element do zaznaczenia", "moveCanvas": "Przesuń obszar roboczy", - "cut": "", + "cut": "Wytnij", "copy": "Kopiuj", "copyAsPng": "Skopiuj do schowka jako plik PNG", "copyAsSvg": "Skopiuj do schowka jako plik SVG", @@ -29,17 +30,17 @@ "edges": "Krawędzie", "sharp": "Ostry", "round": "Zaokrąglij", - "arrowheads": "", - "arrowhead_none": "", - "arrowhead_arrow": "", - "arrowhead_bar": "", - "arrowhead_dot": "", + "arrowheads": "Groty", + "arrowhead_none": "Brak", + "arrowhead_arrow": "Strzałka", + "arrowhead_bar": "Kreska", + "arrowhead_dot": "Kropka", "fontSize": "Rozmiar tekstu", "fontFamily": "Krój pisma", "onlySelected": "Tylko wybrane", - "withBackground": "Z tłem dokumentu", - "exportEmbedScene": "", - "exportEmbedScene_details": "", + "withBackground": "Z tłem", + "exportEmbedScene": "Osadź scenę w eksportowanym pliku", + "exportEmbedScene_details": "Dane sceny zostaną zapisane w eksportowanym pliku PNG/SVG tak, aby scena mogła zostać z niego przywrócona.\nZwiększy to rozmiar eksportowanego pliku.", "addWatermark": "Dodaj \"Zrobione w Excalidraw\"", "handDrawn": "Odręczny", "normal": "Normalny", @@ -60,7 +61,7 @@ "architect": "Dokładny", "artist": "Artystyczny", "cartoonist": "Rysunkowy", - "fileTitle": "", + "fileTitle": "Tytuł pliku", "colorPicker": "Paleta kolorów", "canvasBackground": "Kolor dokumentu", "drawingCanvas": "Obszar roboczy", @@ -69,29 +70,28 @@ "language": "Język", "createRoom": "Udostępnij sesję współpracy na żywo", "duplicateSelection": "Powiel", - "untitled": "", + "untitled": "Bez tytułu", "name": "Nazwa", "yourName": "Twoje imię", "madeWithExcalidraw": "Zrobione w Excalidraw", "group": "Zgrupuj wybrane", "ungroup": "Rozgrupuj wybrane", "collaborators": "Współtwórcy", - "toggleGridMode": "Włącz siatkę", - "toggleStats": "", + "gridMode": "Tryb siatki", "addToLibrary": "Dodaj do biblioteki", "removeFromLibrary": "Usuń z biblioteki", "libraryLoadingMessage": "Wczytywanie biblioteki...", - "libraries": "", + "libraries": "Przeglądaj biblioteki", "loadingScene": "Ładowanie sceny...", - "align": "", - "alignTop": "", - "alignBottom": "", - "alignLeft": "", - "alignRight": "", - "centerVertically": "", - "centerHorizontally": "", - "distributeHorizontally": "", - "distributeVertically": "" + "align": "Wyrównaj", + "alignTop": "Wyrównaj do góry", + "alignBottom": "Wyrównaj do dołu", + "alignLeft": "Wyrównaj do lewej", + "alignRight": "Wyrównaj do prawej", + "centerVertically": "Wyśrodkuj w pionie", + "centerHorizontally": "Wyśrodkuj w poziomie", + "distributeHorizontally": "Rozłóż poziomo", + "distributeVertically": "Rozłóż pionowo" }, "buttons": { "clearReset": "Wyczyść dokument i zresetuj kolor dokumentu", @@ -100,7 +100,7 @@ "exportToSvg": "Zapisz jako SVG", "copyToClipboard": "Skopiuj do schowka", "copyPngToClipboard": "Skopiuj do schowka jako plik PNG", - "scale": "", + "scale": "Skala", "save": "Zapisz", "saveAs": "Zapisz jako", "load": "Otwórz", @@ -118,15 +118,16 @@ "redo": "Przywróć", "roomDialog": "Utwórz nową sesję współpracy na żywo", "createNewRoom": "Utwórz nowy pokój", - "toggleFullScreen": "Włącz/wyłącz tryb pełnoekranowy", - "toggleDarkMode": "Włącz tryb ciemny", - "toggleZenMode": "Włącz tryb Zen", + "fullScreen": "Pełny ekran", + "darkMode": "Ciemny motyw", + "lightMode": "Jasny motyw", + "zenMode": "Tryb Zen", "exitZenMode": "Wyjdź z trybu Zen" }, "alerts": { "clearReset": "To spowoduje usunięcie wszystkiego z dokumentu. Czy chcesz kontynuować?", "couldNotCreateShareableLink": "Wystąpił błąd przy generowaniu linka do udostępniania.", - "couldNotCreateShareableLinkTooBig": "", + "couldNotCreateShareableLinkTooBig": "Nie można utworzyć linku do udostępnienia: scena jest za duża", "couldNotLoadInvalidFile": "Nie udało się otworzyć pliku. Wybrany plik jest nieprawidłowy.", "importBackendFailed": "Wystąpił błąd podczas importowania pliku.", "cannotExportEmptyCanvas": "Najpierw musisz coś narysować, aby zapisać dokument.", @@ -134,10 +135,10 @@ "decryptFailed": "Nie udało się odszyfrować danych.", "uploadedSecurly": "By zapewnić Ci prywatność, udostępnianie projektu jest zabezpieczone szyfrowaniem end-to-end, co oznacza, że poza tobą i osobą z którą podzielisz się linkiem, nikt nie ma dostępu do tego co udostępniasz.", "loadSceneOverridePrompt": "Wczytanie zewnętrznego rysunku zastąpi istniejącą zawartość. Czy chcesz kontynuować?", - "errorLoadingLibrary": "", - "confirmAddLibrary": "", - "imageDoesNotContainScene": "", - "cannotRestoreFromImage": "" + "errorLoadingLibrary": "Wystąpił błąd podczas ładowania biblioteki stron trzecich.", + "confirmAddLibrary": "To doda {{numShapes}} kształtów do twojej biblioteki. Jesteś pewien?", + "imageDoesNotContainScene": "Importowanie zdjęć nie jest obecnie obsługiwane.\n\nCzy chciałeś zaimportować scenę? Ten obraz nie zawiera żadnych danych sceny. Czy włączyłeś to podczas eksportowania?", + "cannotRestoreFromImage": "Scena nie mogła zostać przywrócona z pliku obrazu" }, "toolBar": { "selection": "Zaznaczenie", @@ -161,6 +162,7 @@ "freeDraw": "Naciśnij i przeciągnij by rysować, puść kiedy skończysz", "text": "Wskazówka: możesz również dodać tekst klikając dwukrotnie gdziekolwiek za pomocą narzędzia zaznaczania", "linearElementMulti": "Aby zakończyć krzywą, ponownie kliknij w ostatni punkt, bądź naciśnij Esc albo Enter", + "lockAngle": "Możesz ograniczyć kąt trzymając SHIFT", "resize": "Możesz zachować proporcję trzymająć wcisnięty SHIFT, przytrzymaj ALT by zmienić rozmiar względem środka", "rotate": "Możesz obracać element w równych odstępach trzymając wciśnięty SHIFT", "lineEditor_info": "Kliknij dwukrotnie lub naciśnij Enter, aby edytować punkty", @@ -168,9 +170,9 @@ "lineEditor_nothingSelected": "Naciśnij w punkt by go edytować, przytrzymaj Alt i naciśnij by dodać nowy punkt" }, "canvasError": { - "cannotShowPreview": "", - "canvasTooBig": "", - "canvasTooBigTip": "" + "cannotShowPreview": "Nie można wyświetlić podglądu", + "canvasTooBig": "Obszar roboczy może być za duży.", + "canvasTooBigTip": "Wskazówka: spróbuj nieco zbliżyć najdalej wysunięte elementy." }, "errorSplash": { "headingMain_pre": "Wystąpił błąd. Spróbuj ", @@ -213,22 +215,22 @@ "textNewLine": "Dodaj nową linię (tekst)", "textFinish": "Zakończ edycję (tekst)", "zoomToFit": "Powiększ, aby wyświetlić wszystkie elementy", - "zoomToSelection": "", + "zoomToSelection": "Przybliż zaznaczenie", "preventBinding": "Zablokuj przywiązanie strzałek do obiektu" }, "encrypted": { "tooltip": "Twoje rysunki są zabezpieczone szyfrowaniem end-to-end, tak więc nawet w Excalidraw nie jesteśmy w stanie zobaczyć tego co tworzysz." }, "stats": { - "angle": "", - "element": "", - "elements": "", - "height": "", - "scene": "", - "selected": "", - "storage": "", - "title": "", - "total": "", - "width": "" + "angle": "Kąt", + "element": "Element", + "elements": "Elementy", + "height": "Wysokość", + "scene": "Scena", + "selected": "Zaznaczenie", + "storage": "Pamięć", + "title": "Statystyki dla nerdów", + "total": "Łącznie", + "width": "Szerokość" } } diff --git a/src/locales/pt-BR.json b/src/locales/pt-BR.json new file mode 100644 index 000000000..0f0af4758 --- /dev/null +++ b/src/locales/pt-BR.json @@ -0,0 +1,236 @@ +{ + "labels": { + "paste": "Colar", + "pasteCharts": "Colar gráficos", + "selectAll": "Selecionar tudo", + "multiSelect": "Adicionar elemento à seleção", + "moveCanvas": "Mover tela", + "cut": "Cortar", + "copy": "Copiar", + "copyAsPng": "Copiar para a área de transferência como PNG", + "copyAsSvg": "Copiar para a área de transferência como SVG", + "bringForward": "Trazer para a frente", + "sendToBack": "Enviar para o fundo", + "bringToFront": "Trazer para o primeiro plano", + "sendBackward": "Enviar para trás", + "delete": "Apagar", + "copyStyles": "Copiar os estilos", + "pasteStyles": "Colar os estilos", + "stroke": "Contorno", + "background": "Fundo", + "fill": "Preenchimento", + "strokeWidth": "Espessura do traço", + "strokeStyle": "Estilo de traço", + "strokeStyle_solid": "Sólido", + "strokeStyle_dashed": "Tracejado", + "strokeStyle_dotted": "Pontilhado", + "sloppiness": "Precisão do traço", + "opacity": "Opacidade", + "textAlign": "Alinhamento do texto", + "edges": "Arestas", + "sharp": "Pontudo", + "round": "Arredondado", + "arrowheads": "Pontas", + "arrowhead_none": "Nenhuma", + "arrowhead_arrow": "Flecha", + "arrowhead_bar": "Barra", + "arrowhead_dot": "Ponto", + "fontSize": "Tamanho da fonte", + "fontFamily": "Família da fonte", + "onlySelected": "Somente a seleção", + "withBackground": "Com fundo", + "exportEmbedScene": "Incorporar a cena no arquivo exportado", + "exportEmbedScene_details": "Os dados da cena serão salvos no arquivo PNG/SVG exportado para que a cena possa ser restaurada.\nIrá aumentar o tamanho do arquivo exportado.", + "addWatermark": "Adicionar \"Feito com Excalidraw\"", + "handDrawn": "Manuscrito", + "normal": "Normal", + "code": "Código", + "small": "Pequeno", + "medium": "Médio", + "large": "Grande", + "veryLarge": "Muito grande", + "solid": "Sólido", + "hachure": "Hachura", + "crossHatch": "Hachura cruzada", + "thin": "Fino", + "bold": "Espesso", + "left": "Esquerda", + "center": "Centralizar", + "right": "Direita", + "extraBold": "Muito espesso", + "architect": "Arquiteto", + "artist": "Artista", + "cartoonist": "Cartunista", + "fileTitle": "Título do arquivo", + "colorPicker": "Seletor de cores", + "canvasBackground": "Fundo da tela", + "drawingCanvas": "Tela de desenho", + "layers": "Camadas", + "actions": "Ações", + "language": "Idioma", + "createRoom": "Compartilhar uma sessão de colaboração ao vivo", + "duplicateSelection": "Duplicar", + "untitled": "Sem título", + "name": "Nome", + "yourName": "Seu nome", + "madeWithExcalidraw": "Feito com Excalidraw", + "group": "Agrupar seleção", + "ungroup": "Desagrupar seleção", + "collaborators": "Colaboradores", + "gridMode": "Modo grade", + "addToLibrary": "Adicionar à biblioteca", + "removeFromLibrary": "Remover da biblioteca", + "libraryLoadingMessage": "Carregando biblioteca...", + "libraries": "Procurar bibliotecas", + "loadingScene": "Carregando cena...", + "align": "Alinhamento", + "alignTop": "Alinhar ao topo", + "alignBottom": "Alinhar embaixo", + "alignLeft": "Alinhar à esquerda", + "alignRight": "Alinhar à direita", + "centerVertically": "Centralizar verticalmente", + "centerHorizontally": "Centralizar horizontalmente", + "distributeHorizontally": "Distribuir horizontalmente", + "distributeVertically": "Distribuir verticalmente" + }, + "buttons": { + "clearReset": "Limpar o canvas e redefinir a cor de fundo", + "export": "Exportar", + "exportToPng": "Exportar em PNG", + "exportToSvg": "Exportar em SVG", + "copyToClipboard": "Copiar para o clipboard", + "copyPngToClipboard": "Copiar PNG para área de transferência", + "scale": "Escala", + "save": "Salvar", + "saveAs": "Salvar como", + "load": "Carregar", + "getShareableLink": "Obter um link de compartilhamento", + "close": "Fechar", + "selectLanguage": "Selecionar idioma", + "scrollBackToContent": "Voltar para o conteúdo", + "zoomIn": "Aumentar zoom", + "zoomOut": "Diminuir zoom", + "resetZoom": "Redefinir zoom", + "menu": "Menu", + "done": "Concluído", + "edit": "Editar", + "undo": "Desfazer", + "redo": "Refazer", + "roomDialog": "Iniciar colaboração ao vivo", + "createNewRoom": "Criar nova sala", + "fullScreen": "Tela cheia", + "darkMode": "Modo escuro", + "lightMode": "Modo claro", + "zenMode": "Modo Zen", + "exitZenMode": "Sair do modo zen" + }, + "alerts": { + "clearReset": "Isto irá limpar toda a tela. Você tem certeza?", + "couldNotCreateShareableLink": "Não foi possível criar um link de compartilhamento.", + "couldNotCreateShareableLinkTooBig": "Não foi possível criar um link compartilhável: a cena é muito grande", + "couldNotLoadInvalidFile": "Não foi possível carregar o arquivo inválido", + "importBackendFailed": "A importação do servidor falhou.", + "cannotExportEmptyCanvas": "Não é possível exportar um canvas vazio.", + "couldNotCopyToClipboard": "Não foi possível copiar para a área de transferência. Experimente usando o navegador Chrome.", + "decryptFailed": "Não foi possível descriptografar os dados.", + "uploadedSecurly": "O upload foi protegido com criptografia de ponta a ponta, o que significa que o servidor do Excalidraw e terceiros não podem ler o conteúdo.", + "loadSceneOverridePrompt": "Carregar um desenho externo substituirá o seu conteúdo existente. Deseja continuar?", + "errorLoadingLibrary": "Houve um erro ao carregar a biblioteca de terceiros.", + "confirmAddLibrary": "Isso adicionará {{numShapes}} forma(s) à sua biblioteca. Tem certeza?", + "imageDoesNotContainScene": "A importação de imagens não é suportada no momento.\n\nVocê deseja importar uma cena? Esta imagem parece não conter dados de cena. Você ativou isto durante a exportação?", + "cannotRestoreFromImage": "Não foi possível restaurar a cena deste arquivo de imagem" + }, + "toolBar": { + "selection": "Seleção", + "draw": "Desenho livre", + "rectangle": "Retângulo", + "diamond": "Losango", + "ellipse": "Elipse", + "arrow": "Flecha", + "line": "Linha", + "text": "Texto", + "library": "Biblioteca", + "lock": "Manter ativa a ferramenta selecionada após desenhar" + }, + "headings": { + "canvasActions": "Ações da tela", + "selectedShapeActions": "Ações das formas selecionadas", + "shapes": "Formas" + }, + "hints": { + "linearElement": "Clique para iniciar vários pontos, arraste para uma única linha", + "freeDraw": "Toque e arraste, solte quando terminar", + "text": "Dica: você também pode adicionar texto clicando duas vezes em qualquer lugar com a ferramenta de seleção", + "linearElementMulti": "Clique no último ponto ou pressione Escape ou Enter para terminar", + "lockAngle": "Você pode restringir o ângulo segurando o SHIFT", + "resize": "Você pode restringir proporções segurando SHIFT enquanto redimensiona,\nsegure ALT para redimensionar do centro", + "rotate": "Você pode restringir os ângulos segurando SHIFT enquanto gira", + "lineEditor_info": "Clique duas vezes ou pressione Enter para editar os pontos", + "lineEditor_pointSelected": "Pressione Deletar para remover o ponto, CtrlOuCmd+D para duplicar ou arraste para mover", + "lineEditor_nothingSelected": "Selecione um ponto para mover ou remover, ou segure Alt e clique para adicionar novos pontos" + }, + "canvasError": { + "cannotShowPreview": "Não é possível mostrar pré-visualização", + "canvasTooBig": "A tela pode ser muito grande.", + "canvasTooBigTip": "Dica: tente aproximar um pouco os elementos mais distantes." + }, + "errorSplash": { + "headingMain_pre": "Foi encontrado um erro. Tente ", + "headingMain_button": "recarregar a página.", + "clearCanvasMessage": "Se recarregar a página não funcionar, tente ", + "clearCanvasMessage_button": "limpando a tela.", + "clearCanvasCaveat": " Isso resultará em perda de trabalho ", + "trackedToSentry_pre": "O erro com o identificador ", + "trackedToSentry_post": " foi rastreado no nosso sistema.", + "openIssueMessage_pre": "Fomos muito cautelosos para não incluir suas informações de cena no erro. Se sua cena não for privada, por favor, considere seguir nosso ", + "openIssueMessage_button": "rastreador de bugs.", + "openIssueMessage_post": " Por favor, inclua informações abaixo, copiando e colando para a issue do GitHub.", + "sceneContent": "Conteúdo da cena:" + }, + "roomDialog": { + "desc_intro": "Você pode convidar pessoas para sua cena atual para colaborar com você.", + "desc_privacy": "Não se preocupe, a sessão usa criptografia de ponta a ponta; portanto, o que você desenhar permanecerá privado. Nem mesmo nosso servidor poderá ver o que você cria.", + "button_startSession": "Iniciar sessão", + "button_stopSession": "Parar sessão", + "desc_inProgressIntro": "A sessão de colaboração ao vivo está agora em andamento.", + "desc_shareLink": "Compartilhe este link com qualquer pessoa com quem você queira colaborar:", + "desc_exitSession": "Interrompendo a sessão você irá se desconectar da sala, mas você poderá continuar trabalhando com a cena localmente. Observe que isso não afetará outras pessoas, e elas ainda poderão colaborar em suas versões." + }, + "errorDialog": { + "title": "Erro" + }, + "shortcutsDialog": { + "title": "Atalhos de teclado", + "shapes": "Formas", + "or": "ou", + "click": "clicar", + "drag": "arrastar", + "curvedArrow": "Seta curva", + "curvedLine": "Linha curva", + "editor": "Editor", + "view": "Visualizar", + "blog": "Leia o nosso blog", + "howto": "Siga os nossos guias", + "github": "Encontrou algum problema? Nos informe", + "textNewLine": "Adicionar nova linha (texto)", + "textFinish": "Finalizar edição (texto)", + "zoomToFit": "Ajustar para caber todos os elementos", + "zoomToSelection": "Ampliar a seleção", + "preventBinding": "Prevenir fixação de seta" + }, + "encrypted": { + "tooltip": "Seus desenhos são criptografados de ponta a ponta, então os servidores do Excalidraw nunca os verão." + }, + "stats": { + "angle": "Ângulo", + "element": "Elemento", + "elements": "Elementos", + "height": "Altura", + "scene": "Cena", + "selected": "Selecionado", + "storage": "Armazenamento", + "title": "Estatísticas para nerds", + "total": "Total", + "width": "Largura" + } +} diff --git a/src/locales/pt-PT.json b/src/locales/pt-PT.json index a76e04c39..d217b41cd 100644 --- a/src/locales/pt-PT.json +++ b/src/locales/pt-PT.json @@ -1,10 +1,11 @@ { "labels": { "paste": "Colar", + "pasteCharts": "Colar gráficos", "selectAll": "Selecionar tudo", "multiSelect": "Adicionar elemento à seleção", "moveCanvas": "Mover tela", - "cut": "", + "cut": "Cortar", "copy": "Copiar", "copyAsPng": "Copiar para a área de transferência como PNG", "copyAsSvg": "Copiar para a área de transferência como SVG", @@ -29,11 +30,11 @@ "edges": "Arestas", "sharp": "Aguçado", "round": "Redondo", - "arrowheads": "", - "arrowhead_none": "", - "arrowhead_arrow": "", - "arrowhead_bar": "", - "arrowhead_dot": "", + "arrowheads": "Pontas", + "arrowhead_none": "Nenhuma", + "arrowhead_arrow": "Seta", + "arrowhead_bar": "Barra", + "arrowhead_dot": "Ponto", "fontSize": "Tamanho da fonte", "fontFamily": "Família da fontes", "onlySelected": "Somente a seleção", @@ -60,7 +61,7 @@ "architect": "Arquitecto", "artist": "Artista", "cartoonist": "Caricaturista", - "fileTitle": "", + "fileTitle": "Título do ficheiro", "colorPicker": "Seletor de cores", "canvasBackground": "Fundo da tela", "drawingCanvas": "Tela de desenho", @@ -69,29 +70,28 @@ "language": "Idioma", "createRoom": "Compartilhar uma sessão de colaboração ao vivo", "duplicateSelection": "Duplicar", - "untitled": "", + "untitled": "Sem título", "name": "Nome", "yourName": "Seu nome", "madeWithExcalidraw": "Feito com Excalidraw", "group": "Agrupar seleção", "ungroup": "Desagrupar seleção", "collaborators": "Colaboradores", - "toggleGridMode": "Alternar modo de grade", - "toggleStats": "", + "gridMode": "Modo grade", "addToLibrary": "Adicionar à biblioteca", "removeFromLibrary": "Remover da biblioteca", "libraryLoadingMessage": "Carregando biblioteca...", - "libraries": "", + "libraries": "Procurar bibliotecas", "loadingScene": "Carregando cena...", - "align": "", - "alignTop": "", - "alignBottom": "", - "alignLeft": "", - "alignRight": "", - "centerVertically": "", - "centerHorizontally": "", - "distributeHorizontally": "", - "distributeVertically": "" + "align": "Alinhamento", + "alignTop": "Alinhar ao topo", + "alignBottom": "Alinhar ao fundo", + "alignLeft": "Alinhar à esquerda", + "alignRight": "Alinhar à direita", + "centerVertically": "Centralizar verticalmente", + "centerHorizontally": "Centralizar horizontalmente", + "distributeHorizontally": "Distribuir horizontalmente", + "distributeVertically": "Distribuir verticalmente" }, "buttons": { "clearReset": "Limpar o canvas e redefinir a cor de fundo", @@ -118,9 +118,10 @@ "redo": "Refazer", "roomDialog": "Iniciar colaboração ao vivo", "createNewRoom": "Criar nova sala", - "toggleFullScreen": "Alternar tela cheia", - "toggleDarkMode": "Alternar modo escuro", - "toggleZenMode": "Alternar modo zen", + "fullScreen": "Tela cheia", + "darkMode": "Modo escuro", + "lightMode": "Modo claro", + "zenMode": "Modo Zen", "exitZenMode": "Sair do modo zen" }, "alerts": { @@ -136,7 +137,7 @@ "loadSceneOverridePrompt": "Carregar um desenho externo substituirá o seu conteúdo existente. Deseja continuar?", "errorLoadingLibrary": "Houve um erro ao carregar a biblioteca de terceiros.", "confirmAddLibrary": "Isso adicionará {{numShapes}} forma(s) à sua biblioteca. Tem certeza?", - "imageDoesNotContainScene": "O arquivo de imagem não contém dados de cena. Você ativou durante a exportação?", + "imageDoesNotContainScene": "A importação de imagens não é suportada no momento.\n\nVocê deseja importar uma cena? Esta imagem parece não conter dados de cena. Você ativou isto durante a exportação?", "cannotRestoreFromImage": "Não foi possível restaurar a cena deste arquivo de imagem" }, "toolBar": { @@ -161,6 +162,7 @@ "freeDraw": "Toque e arraste, solte quando terminar", "text": "Dica: você também pode adicionar texto clicando duas vezes em qualquer lugar com a ferramenta de seleção", "linearElementMulti": "Clique no último ponto ou pressione Escape ou Enter para terminar", + "lockAngle": "Você pode restringir o ângulo segurando SHIFT", "resize": "Você pode restringir proporções segurando SHIFT enquanto redimensiona,\nsegure ALT para redimensionar do centro", "rotate": "Você pode restringir os ângulos segurando SHIFT enquanto gira", "lineEditor_info": "Clique duas vezes ou pressione Enter para editar os pontos", @@ -168,9 +170,9 @@ "lineEditor_nothingSelected": "Selecione um ponto para mover ou remover, ou segure Alt e clique para adicionar novos pontos" }, "canvasError": { - "cannotShowPreview": "", - "canvasTooBig": "", - "canvasTooBigTip": "" + "cannotShowPreview": "Não é possível mostrar pré-visualização", + "canvasTooBig": "A tela pode ser muito grande.", + "canvasTooBigTip": "Dica: tente aproximar um pouco os elementos mais distantes." }, "errorSplash": { "headingMain_pre": "Foi encontrado um erro. Tente ", @@ -213,22 +215,22 @@ "textNewLine": "Adicionar nova linha (texto)", "textFinish": "Finalizar edição (texto)", "zoomToFit": "Ajustar para caber todos os elementos", - "zoomToSelection": "", + "zoomToSelection": "Ampliar a seleção", "preventBinding": "Prevenir fixação de seta" }, "encrypted": { "tooltip": "Seus desenhos são criptografados de ponta a ponta, então os servidores do Excalidraw nunca os verão." }, "stats": { - "angle": "", - "element": "", - "elements": "", - "height": "", - "scene": "", - "selected": "", - "storage": "", - "title": "", - "total": "", - "width": "" + "angle": "Ângulo", + "element": "Elemento", + "elements": "Elementos", + "height": "Altura", + "scene": "Cena", + "selected": "Selecionado", + "storage": "Armazenamento", + "title": "Estatísticas para nerds", + "total": "Total", + "width": "Largura" } } diff --git a/src/locales/ro-RO.json b/src/locales/ro-RO.json index becf2ac8c..8b283af6a 100644 --- a/src/locales/ro-RO.json +++ b/src/locales/ro-RO.json @@ -1,6 +1,7 @@ { "labels": { "paste": "Lipire", + "pasteCharts": "Lipire diagrame", "selectAll": "Selectare totală", "multiSelect": "Adaugă element la selecție", "moveCanvas": "Mutare pânză", @@ -76,8 +77,7 @@ "group": "Grupare selecție", "ungroup": "Degrupare selecție", "collaborators": "Colaboratori", - "toggleGridMode": "Comută modul grilă", - "toggleStats": "Comută statisticile pentru pasionați", + "gridMode": "Mod grilă", "addToLibrary": "Adăugare la bibliotecă", "removeFromLibrary": "Eliminare din bibliotecă", "libraryLoadingMessage": "Se încarcă biblioteca...", @@ -118,9 +118,10 @@ "redo": "Refacere", "roomDialog": "Colaborare în direct", "createNewRoom": "Creare cameră nouă", - "toggleFullScreen": "Comută modul ecran complet", - "toggleDarkMode": "Comută modul întunecat", - "toggleZenMode": "Comută modul zen", + "fullScreen": "Ecran complet", + "darkMode": "Mod întunecat", + "lightMode": "Mod luminos", + "zenMode": "Mod zen", "exitZenMode": "Ieșire din modul zen" }, "alerts": { @@ -136,7 +137,7 @@ "loadSceneOverridePrompt": "Încărcarea desenului extern va înlocui conținutul existent. Dorești să continui?", "errorLoadingLibrary": "A apărut o eroare la încărcarea bibliotecii terțe.", "confirmAddLibrary": "Această acțiune va adăuga {{numShapes}} formă(e) la biblioteca ta. Confirmi?", - "imageDoesNotContainScene": "Fișierul de imagine nu conține date de scenă. Ai activat această opțiune pe durata exportării?", + "imageDoesNotContainScene": "Importarea imaginilor nu este acceptată în acest moment.\n\nVoiai să imporți o scenă? Această imagine nu pare să conțină date de scenă. Ai activat această opțiune pe durata exportării?", "cannotRestoreFromImage": "Scena nu a putut fi restaurată din acest fișier de imagine" }, "toolBar": { @@ -161,6 +162,7 @@ "freeDraw": "Dă clic pe pânză și glisează cursorul, apoi eliberează-l când ai terminat", "text": "Sfat: poți adăuga text și dând dublu clic oriunde cu instrumentul de selecție", "linearElementMulti": "Dă clic pe ultimul punct sau apasă tasta Escape sau tasta Enter pentru a termina", + "lockAngle": "Poți constrânge unghiul prin ținerea apăsată a tastei SHIFT", "resize": "Poți constrânge proporțiile, ținând apăsată tasta SHIFT în timp ce redimensionezi,\nține apăsată tasta ALT pentru a redimensiona de la centru", "rotate": "Poți constrânge unghiurile, ținând apăsată tasta SHIFT în timp ce rotești", "lineEditor_info": "Dă dublu clic sau apasă tasta Enter pentru a edita punctele", diff --git a/src/locales/ru-RU.json b/src/locales/ru-RU.json index d51b074b8..9e95888f2 100644 --- a/src/locales/ru-RU.json +++ b/src/locales/ru-RU.json @@ -1,10 +1,11 @@ { "labels": { "paste": "Вставить", + "pasteCharts": "Вставить диаграммы", "selectAll": "Выбрать все", - "multiSelect": "Добавить элемент к выбору", + "multiSelect": "Добавить элемент в выделенный фрагмент", "moveCanvas": "Переместить холст", - "cut": "", + "cut": "Вырезать", "copy": "Копировать", "copyAsPng": "Скопировать в буфер обмена как PNG", "copyAsSvg": "Скопировать в буфер обмена как SVG", @@ -29,17 +30,17 @@ "edges": "Края", "sharp": "Острые", "round": "Скругленные", - "arrowheads": "", - "arrowhead_none": "", + "arrowheads": "Стрелка", + "arrowhead_none": "Без стрелки", "arrowhead_arrow": "Cтрелка", - "arrowhead_bar": "", + "arrowhead_bar": "Столбец", "arrowhead_dot": "Точка", "fontSize": "Размер шрифта", "fontFamily": "Семейство шрифтов", "onlySelected": "Только выбранные", "withBackground": "С фоном", - "exportEmbedScene": "", - "exportEmbedScene_details": "", + "exportEmbedScene": "Встроить информацию о сцене в экспортируемый файл", + "exportEmbedScene_details": "Сцена будет сохранена в PNG/SVG файл так, чтобы всю сцену можно будет восстановить из этого файла. Это увеличит размер файла.", "addWatermark": "Добавить \"Сделано с Excalidraw\"", "handDrawn": "Нарисованный от руки", "normal": "Обычный", @@ -75,23 +76,22 @@ "madeWithExcalidraw": "Сделано в Excalidraw", "group": "Сгруппировать выделение", "ungroup": "Разделить выделение", - "collaborators": "Сотрудники", - "toggleGridMode": "Переключить режим сетки", - "toggleStats": "", + "collaborators": "Участники", + "gridMode": "Сетка", "addToLibrary": "Добавить в библиотеку", "removeFromLibrary": "Удалить из библиотеки", "libraryLoadingMessage": "Загрузка библиотеки...", - "libraries": "", + "libraries": "Просмотреть библиотеки", "loadingScene": "Загрузка сцены...", - "align": "", - "alignTop": "", - "alignBottom": "", - "alignLeft": "", - "alignRight": "", - "centerVertically": "", - "centerHorizontally": "", - "distributeHorizontally": "", - "distributeVertically": "" + "align": "Выровнять", + "alignTop": "Выровнять по верхнему краю", + "alignBottom": "Выровнять по нижнему краю", + "alignLeft": "Выровнять по левому краю", + "alignRight": "Выровнять по правому краю", + "centerVertically": "Центрировать по вертикали", + "centerHorizontally": "Центрировать по горизонтали", + "distributeHorizontally": "Распределить по горизонтали", + "distributeVertically": "Распределить по вертикали" }, "buttons": { "clearReset": "Очистить холст и сбросить цвет фона", @@ -100,7 +100,7 @@ "exportToSvg": "Экспорт в SVG", "copyToClipboard": "Скопировать в буфер обмена", "copyPngToClipboard": "Скопировать PNG в буфер обмена", - "scale": "Шкала", + "scale": "Масштаб", "save": "Сохранить", "saveAs": "Сохранить как", "load": "Загрузить", @@ -118,26 +118,27 @@ "redo": "Шаг вперед", "roomDialog": "Начать совместную работу", "createNewRoom": "Создать новую комнату", - "toggleFullScreen": "Переключить полноэкранный режим", - "toggleDarkMode": "Переключить тёмную тему", - "toggleZenMode": "Переключить режим концентрации внимания", + "fullScreen": "Полный экран", + "darkMode": "Темная тема", + "lightMode": "Светлая тема", + "zenMode": "Режим Дзен", "exitZenMode": "Выключить режим концентрации внимания" }, "alerts": { "clearReset": "Это очистит весь холст. Вы уверены?", "couldNotCreateShareableLink": "Не удалось создать общедоступную ссылку.", - "couldNotCreateShareableLinkTooBig": "", + "couldNotCreateShareableLinkTooBig": "Нельзя создать ссылку, чтобы поделиться. Сцена слишком большая", "couldNotLoadInvalidFile": "Не удалось загрузить недопустимый файл", "importBackendFailed": "Не удалось импортировать из бэкэнда.", "cannotExportEmptyCanvas": "Не может экспортировать пустой холст.", "couldNotCopyToClipboard": "Не удалось скопировать в буфер обмена. Попробуйте использовать веб-браузер Chrome.", - "decryptFailed": "Не удалось декодировать данные.", + "decryptFailed": "Не удалось расшифровать данные.", "uploadedSecurly": "Загружаемые данные защищена сквозным шифрованием, что означает, что сервер Excalidraw и третьи стороны не могут прочитать содержимое.", - "loadSceneOverridePrompt": "", - "errorLoadingLibrary": "", - "confirmAddLibrary": "", - "imageDoesNotContainScene": "", - "cannotRestoreFromImage": "" + "loadSceneOverridePrompt": "Загрузка рисунка приведёт к замене имеющегося содержимого. Вы хотите продолжить?", + "errorLoadingLibrary": "Произошла ошибка при загрузке сторонней библиотеки.", + "confirmAddLibrary": "Будет добавлено {{numShapes}} фигур в вашу библиотеку. Продолжить?", + "imageDoesNotContainScene": "Импорт изображений не поддерживается в данный момент.\n\nХотите импортировать сцену? Данное изображение не содержит данных о сцене. Было ли включено это во время экспорта?", + "cannotRestoreFromImage": "Сцена не может быть восстановлена из этого изображения" }, "toolBar": { "selection": "Выделение области", @@ -159,18 +160,19 @@ "hints": { "linearElement": "Нажмите, чтобы начать несколько точек, перетащите для одной линии", "freeDraw": "Нажмите и перетаскивайте, отпустите по завершении", - "text": "", + "text": "Совет: при выбранном инструменте выделения дважды щёлкните в любом месте, чтобы добавить текст", "linearElementMulti": "Кликните на последней точке или нажмите Escape или Enter чтобы закончить", + "lockAngle": "Вы можете ограничить угол удерживая SHIFT", "resize": "Вы можете ограничить пропорции, удерживая SHIFT во время изменения размеров,\nудерживайте ALT чтобы изменить размер из центра", "rotate": "Вы можете ограничить углы, удерживая SHIFT во время вращения", "lineEditor_info": "Дважды кликните или нажмите Enter, чтобы редактировать точки", - "lineEditor_pointSelected": "", - "lineEditor_nothingSelected": "" + "lineEditor_pointSelected": "Нажмите Delete для удаления точки, Ctrl или Cmd + D для дублирования, перетащите для перемещения", + "lineEditor_nothingSelected": "Выберите точку для перемещения или удаления. Alt + клик чтобы добавить новые точки" }, "canvasError": { - "cannotShowPreview": "", - "canvasTooBig": "", - "canvasTooBigTip": "" + "cannotShowPreview": "Не удается отобразить предпросмотр", + "canvasTooBig": "Сцена слишком большая.", + "canvasTooBigTip": "Совет: попробуйте сблизить элементы рисунка." }, "errorSplash": { "headingMain_pre": "Возникла ошибка. Попробуйте ", @@ -188,11 +190,11 @@ "roomDialog": { "desc_intro": "Вы можете пригласить людей в текущую сцену для совместной работы.", "desc_privacy": "Не беспокойтесь, сессия использует сквозное шифрование, поэтому всё что вы нарисуете останется приватным. Ваша информация не будет доступна даже на наших серверах.", - "button_startSession": "Начать сессию", - "button_stopSession": "Закончить сессию", + "button_startSession": "Начать сеанс", + "button_stopSession": "Завершить сеанс", "desc_inProgressIntro": "Совместная сессия теперь активна.", "desc_shareLink": "Поделитесь этой ссылкой со всеми участниками:", - "desc_exitSession": "" + "desc_exitSession": "Завершив сеанс, вы выйдете из комнаты, но сможете продолжить работать с документом локально. Это не повлияет на работу других пользователей — они смогут продолжить совместную работу с их версией документа." }, "errorDialog": { "title": "Ошибка" @@ -212,23 +214,23 @@ "github": "Нашли проблему? Отправьте", "textNewLine": "Добавить новую строку (текст)", "textFinish": "Закончить редактирование (текст)", - "zoomToFit": "", - "zoomToSelection": "", + "zoomToFit": "Отмастштабировать, чтобы поместились все элементы", + "zoomToSelection": "Перейти к выделенному", "preventBinding": "Предотвратить привязку стрелок" }, "encrypted": { - "tooltip": "" + "tooltip": "Ваши данные защищены сквозным (End-to-end) шифрованием. Серверы Excalidraw никогда не получат доступ к ним." }, "stats": { "angle": "Угол", "element": "Элемент", "elements": "Элементы", "height": "Высота", - "scene": "", - "selected": "", - "storage": "", - "title": "", - "total": "", + "scene": "Сцены", + "selected": "Выбран", + "storage": "Хранилище", + "title": "Статистика для ботаников", + "total": "Всего", "width": "Ширина" } } diff --git a/src/locales/sk-SK.json b/src/locales/sk-SK.json index 2cedc8b30..3b7193208 100644 --- a/src/locales/sk-SK.json +++ b/src/locales/sk-SK.json @@ -1,6 +1,7 @@ { "labels": { "paste": "Vložiť", + "pasteCharts": "Vložiť grafy", "selectAll": "Vybrať všetko", "multiSelect": "Pridať prvok do výberu", "moveCanvas": "Pohyb plátna", @@ -14,7 +15,7 @@ "sendBackward": "Presunúť o úroveň dozadu", "delete": "Vymazať", "copyStyles": "Kopírovať štýly", - "pasteStyles": "Prilepiť štýly", + "pasteStyles": "Vložiť štýly", "stroke": "Obrys", "background": "Pozadie", "fill": "Výplň", @@ -76,8 +77,7 @@ "group": "Zoskupiť", "ungroup": "Zrušiť zoskupenie", "collaborators": "Spolupracovníci", - "toggleGridMode": "Prepnúť mriežku", - "toggleStats": "Prepnúť štatistiky", + "gridMode": "Režim mriežky", "addToLibrary": "Pridať do knižnice", "removeFromLibrary": "Odstrániť z knižnice", "libraryLoadingMessage": "Načítavanie knižnice...", @@ -118,9 +118,10 @@ "redo": "Znova", "roomDialog": "Začať živú spoluprácu", "createNewRoom": "Vytvoriť novú miestnosť", - "toggleFullScreen": "Prepnúť režim celej obrazovky", - "toggleDarkMode": "Prepnúť tmavý režim", - "toggleZenMode": "Prepnúť režim zen", + "fullScreen": "Celá obrazovka", + "darkMode": "Tmavý režim", + "lightMode": "Svetlý režim", + "zenMode": "Režim zen", "exitZenMode": "Zrušiť režim zen" }, "alerts": { @@ -136,7 +137,7 @@ "loadSceneOverridePrompt": "Nahratie externej kresby nahradí existujúci obsah. Prajete si pokračovať?", "errorLoadingLibrary": "Nepodarilo sa načítať externú knižnicu.", "confirmAddLibrary": "Týmto sa pridá {{numShapes}} tvar(ov) do vašej knižnice. Ste si istí?", - "imageDoesNotContainScene": "Obrázkový súbor neobsahuje údaje scény. Povolili ste ich pri exportovaní?", + "imageDoesNotContainScene": "Importovanie obrázku v tomto momente nie je možné.\n\nChceli ste importovať scénu? Tento obrázok neobsahuje žiadne údaje scény. Povolili ste túto možnosť počas exportovania?", "cannotRestoreFromImage": "Nepodarilo sa obnoviť scénu z tohto obrázkového súboru" }, "toolBar": { @@ -161,6 +162,7 @@ "freeDraw": "Kliknite a ťahajte, pustite na ukončenie", "text": "Tip: text môžete pridať aj dvojklikom kdekoľvek, ak je zvolený nástroj výber", "linearElementMulti": "Kliknite na počiatočný bod alebo stlačte Escape alebo Enter na ukončenie", + "lockAngle": "Počas rotácie obmedzíte uhol podržaním SHIFT", "resize": "Počas zmeny veľkosti zachováte proporcie podržaním SHIFT,\\npodržaním ALT meníte veľkosť so zachovaním stredu", "rotate": "Počas rotácie obmedzíte uhol podržaním SHIFT", "lineEditor_info": "Použite dvojklik alebo stlačte Enter na editáciu bodov", diff --git a/src/locales/sv-SE.json b/src/locales/sv-SE.json index d5db1198a..e749a977e 100644 --- a/src/locales/sv-SE.json +++ b/src/locales/sv-SE.json @@ -1,6 +1,7 @@ { "labels": { "paste": "Klistra in", + "pasteCharts": "Klistra in diagram", "selectAll": "Markera alla", "multiSelect": "Lägg till element till markering", "moveCanvas": "Flytta canvas", @@ -76,8 +77,7 @@ "group": "Gruppera markering", "ungroup": "Avgruppera markering", "collaborators": "Medarbetare", - "toggleGridMode": "Växla rutnätsläge", - "toggleStats": "Visa/dölj statistik för nördar", + "gridMode": "Rutnätsläge", "addToLibrary": "Lägg till i biblioteket", "removeFromLibrary": "Ta bort från bibliotek", "libraryLoadingMessage": "Laddar bibliotek...", @@ -118,9 +118,10 @@ "redo": "Gör om", "roomDialog": "Starta live-samarbete", "createNewRoom": "Skapa ett nytt rum", - "toggleFullScreen": "Växla fullskärmsläge", - "toggleDarkMode": "Växla mörkt läge", - "toggleZenMode": "Växla zen-läge", + "fullScreen": "Helskärm", + "darkMode": "Mörkt läge", + "lightMode": "Ljust läge", + "zenMode": "Zen-läge", "exitZenMode": "Gå ur zen-läge" }, "alerts": { @@ -136,7 +137,7 @@ "loadSceneOverridePrompt": "Laddning av extern skiss kommer att ersätta ditt befintliga innehåll. Vill du fortsätta?", "errorLoadingLibrary": "Fel vid inläsning av tredjeparts bibliotek.", "confirmAddLibrary": "Detta kommer att lägga till {{numShapes}} form(er) till ditt bibliotek. Är du säker?", - "imageDoesNotContainScene": "Bildfilen innehåller inte skissdata. Har du aktiverat detta under export?", + "imageDoesNotContainScene": "Importering av bilder stöds inte just nu.\n\nVill du importera en skiss? Den här bilden verkar inte innehålla någon skissdata. Har du aktiverat detta under export?", "cannotRestoreFromImage": "Skiss kunde inte återställas från denna bildfil" }, "toolBar": { @@ -161,6 +162,7 @@ "freeDraw": "Klicka och dra, släpp när du är klar", "text": "Tips: du kan också lägga till text genom att dubbelklicka var som helst med markeringsverktyget", "linearElementMulti": "Klicka på sista punkten eller tryck Escape eller Enter för att avsluta", + "lockAngle": "Du kan begränsa vinkeln genom att hålla SKIFT", "resize": "Du kan behålla proportioner genom att hålla SHIFT medan du ändrar storlek,\nhåller du ALT ändras storlek relativt mitten", "rotate": "Du kan begränsa vinklar genom att hålla SHIFT medan du roterar", "lineEditor_info": "Dubbelklicka eller tryck på Enter för att redigera punkter", diff --git a/src/locales/tr-TR.json b/src/locales/tr-TR.json index 3babf71b1..6382029a4 100644 --- a/src/locales/tr-TR.json +++ b/src/locales/tr-TR.json @@ -1,10 +1,11 @@ { "labels": { "paste": "Yapıştır", + "pasteCharts": "Dairesel grafik", "selectAll": "Tümünü seç", "multiSelect": "Seçime öge ekle", "moveCanvas": "Tuvali taşı", - "cut": "", + "cut": "Kes", "copy": "Kopyala", "copyAsPng": "Panoya PNG olarak kopyala", "copyAsSvg": "Panoya SVG olarak kopyala", @@ -29,17 +30,17 @@ "edges": "Kenarlar", "sharp": "Keskin", "round": "Yuvarlak", - "arrowheads": "", - "arrowhead_none": "", - "arrowhead_arrow": "", - "arrowhead_bar": "", - "arrowhead_dot": "", + "arrowheads": "Ok başları", + "arrowhead_none": "Yok", + "arrowhead_arrow": "Ok", + "arrowhead_bar": "Çizgi", + "arrowhead_dot": "Nokta", "fontSize": "Yazı tipi boyutu", "fontFamily": "Yazı tipi ailesi", "onlySelected": "Sadece seçilen", - "withBackground": "Arka Plan İle Beraber", - "exportEmbedScene": "", - "exportEmbedScene_details": "", + "withBackground": "Arka planla beraber", + "exportEmbedScene": "Sahneyi çıktı dosyasına dahil et", + "exportEmbedScene_details": "Sahne datası, daha sonra geri kullanılabilmesi için çıktı alınan PNG/SVG dosyasına dahil edicelek. Bu işlem dosya boyutunu arttıracaktır.", "addWatermark": "\"Excalidraw ile yapıldı\" yazısını ekle", "handDrawn": "El-yazısı", "normal": "Normal", @@ -60,7 +61,7 @@ "architect": "Mimar", "artist": "Sanatçı", "cartoonist": "Karikatürist", - "fileTitle": "", + "fileTitle": "Dosya adı", "colorPicker": "Renk seçici", "canvasBackground": "Tuval arka planı", "drawingCanvas": "Çizim tuvali", @@ -69,29 +70,28 @@ "language": "Dil", "createRoom": "Ortak çalışma ortamını paylaş", "duplicateSelection": "Çoğalt", - "untitled": "", + "untitled": "Adsız", "name": "İsim", "yourName": "İsminiz", "madeWithExcalidraw": "Excalidraw ile yapıldı", "group": "Seçimi grup yap", "ungroup": "Seçilen grubu dağıt", "collaborators": "Ortaklar", - "toggleGridMode": "Izgara modunu aç", - "toggleStats": "", + "gridMode": "Izgara modu", "addToLibrary": "Kütüphaneye ekle", "removeFromLibrary": "Kütüphaneden kaldır", "libraryLoadingMessage": "Kütüphane yükleniyor...", - "libraries": "", + "libraries": "Kütüphanelere gözat", "loadingScene": "Çalışma alanı yükleniyor...", - "align": "", - "alignTop": "", - "alignBottom": "", - "alignLeft": "", - "alignRight": "", - "centerVertically": "", - "centerHorizontally": "", - "distributeHorizontally": "", - "distributeVertically": "" + "align": "Hizala", + "alignTop": "Yukarı hizala", + "alignBottom": "Aşağı hizala", + "alignLeft": "Sola yasla", + "alignRight": "Sağa yasla", + "centerVertically": "Dikeyde ortala", + "centerHorizontally": "Yatayda ortala", + "distributeHorizontally": "Yatay dağıt", + "distributeVertically": "Dikey dağıt" }, "buttons": { "clearReset": "Tuvali sıfırla", @@ -118,15 +118,16 @@ "redo": "Yeniden yap", "roomDialog": "Ortak çalışma ortamı yarat", "createNewRoom": "Yeni oda oluştur", - "toggleFullScreen": "Tam ekranı aç/kapa", - "toggleDarkMode": "Karanlık modu aç/kapa", - "toggleZenMode": "Zen modunu aç/kapa", + "fullScreen": "Tam ekran", + "darkMode": "Koyu tema", + "lightMode": "Açık tema", + "zenMode": "Zen modu", "exitZenMode": "Zen modundan çık" }, "alerts": { "clearReset": "Tuvalin tamamı temizlenecek. Emin misiniz?", "couldNotCreateShareableLink": "Paylaşılabilir bağlantı oluşturulamadı.", - "couldNotCreateShareableLinkTooBig": "", + "couldNotCreateShareableLinkTooBig": "Paylaşılabilir bağlantı oluşturulamadı: sahne çok büyük", "couldNotLoadInvalidFile": "Bilinmeyen dosya yüklenemiyor", "importBackendFailed": "Sunucudan içe aktarma başarısız.", "cannotExportEmptyCanvas": "Boş tuval dışarıya aktarılamaz.", @@ -136,8 +137,8 @@ "loadSceneOverridePrompt": "Harici çizimler yüklemek mevcut olan içeriği değiştirecektir. Devam etmek istiyor musunuz?", "errorLoadingLibrary": "Üçüncü taraf kitaplığı yüklerken bir hata oluştu.", "confirmAddLibrary": "Bu, kitaplığınıza {{numShapes}} tane şekil ekleyecek. Emin misiniz?", - "imageDoesNotContainScene": "Görsel dosyası herhangi bir sahne verisi bulundurmuyor. Dışa aktarırken bunu etkinleştirdiniz mi?", - "cannotRestoreFromImage": "Bu görsel dosyasından sahne onarılamıyor" + "imageDoesNotContainScene": "Resim ekleme şuan için desteklenmiyor.\nBir sahneyi içeri aktarmak mı istediniz? Bu dosya herhangi bir sahne içeriyor gibi durmuyor. Çıktı alırken sahneyi dahil ettiniz mi?", + "cannotRestoreFromImage": "Sahne bu dosyadan oluşturulamıyor" }, "toolBar": { "selection": "Seçme", @@ -161,6 +162,7 @@ "freeDraw": "Tıkla ve sürükle, bitirdiğinde serbest bırak", "text": "İpucu: seçme aracıyla herhangi bir yere çift tıklayarak da yazı ekleyebilirsin", "linearElementMulti": "Tamamlamak için son noktayı seçin veya Escape ve Enter'dan birine basın", + "lockAngle": "SHIFT tuşuna basılı tutarak açıyı koruyabilirsiniz", "resize": "Yeniden boyutlandırırken SHIFT'e basılı tutarak oranları kısıtlayabilirsiniz, merkezden yeniden boyutlandırmak için ALT'a basılı tutun", "rotate": "Döndürürken SHIFT tuşuna basılı tutarak açıları koruyabilirsiniz", "lineEditor_info": "Noktaları düzenlemek için çift-tıklayın veya Enter'a basın", @@ -168,9 +170,9 @@ "lineEditor_nothingSelected": "Kaldırmak veya oynatmak için bir nokta seç, veya yeni noktalar eklemek için Alt'a basılı tut" }, "canvasError": { - "cannotShowPreview": "", - "canvasTooBig": "", - "canvasTooBigTip": "" + "cannotShowPreview": "Önizleme gösterilemiyor", + "canvasTooBig": "Kanvas çok büyük olabilir.", + "canvasTooBigTip": "İpucu: En uzaktaki elemanları birbirine yakınlaştırmayı deneyin." }, "errorSplash": { "headingMain_pre": "Hata oluştu. Lütfen ", @@ -180,8 +182,8 @@ "clearCanvasCaveat": " Bu, yaptığınız değişiklikleri sıfırlayacak ", "trackedToSentry_pre": "Tanımlayıcı ile ilgili hata ", "trackedToSentry_post": " sistemimize yakalandı.", - "openIssueMessage_pre": "", - "openIssueMessage_button": "hata takibinde bir yardım bileti oluşturun.", + "openIssueMessage_pre": "Sahne bilginizi hata mesajına yansıtmamak için oldukça dikkatli davrandık. Eğer sahneniz gizli değilse hatayı lütfen şuradan takip edin ", + "openIssueMessage_button": "hata takibi.", "openIssueMessage_post": " Lütfen aşağıya GitHub sorununa kopyalayarak ve yapıştırarak bilgi ekleyin.", "sceneContent": "Sahne içeriği:" }, @@ -213,22 +215,22 @@ "textNewLine": "Yeni satır ekle (yazı)", "textFinish": "(Yazıyı) düzenlemeyi bitir", "zoomToFit": "Tüm öğeleri sığdırmak için yakınlaştır", - "zoomToSelection": "", + "zoomToSelection": "Seçime yaklaş", "preventBinding": "Ok bağlamayı önleyin" }, "encrypted": { "tooltip": "Çizimleriniz uçtan-uca şifrelenmiştir, Excalidraw'ın sunucuları bile onları göremez." }, "stats": { - "angle": "", - "element": "", - "elements": "", - "height": "", - "scene": "", - "selected": "", - "storage": "", - "title": "", - "total": "", - "width": "" + "angle": "Açı", + "element": "Bileşen", + "elements": "Bileşenler", + "height": "Yükseklik", + "scene": "Sahne", + "selected": "Seçili", + "storage": "Depolama", + "title": "İnekler için istatistikler", + "total": "Toplam", + "width": "Genişlik" } } diff --git a/src/locales/uk-UA.json b/src/locales/uk-UA.json index 8237fb0f1..a9b9a7fd4 100644 --- a/src/locales/uk-UA.json +++ b/src/locales/uk-UA.json @@ -1,6 +1,7 @@ { "labels": { "paste": "Вставити", + "pasteCharts": "Вставити діаграми", "selectAll": "Вибрати все", "multiSelect": "Додати елемент до вибраного", "moveCanvas": "Перемістити полотно", @@ -29,7 +30,7 @@ "edges": "Краї", "sharp": "Гострі", "round": "Круглі", - "arrowheads": "", + "arrowheads": "Закінчення стрілки", "arrowhead_none": "Жоден", "arrowhead_arrow": "Стрілка", "arrowhead_bar": "Колона", @@ -37,7 +38,7 @@ "fontSize": "Розмір шрифту", "fontFamily": "Шрифт", "onlySelected": "Тільки вибране", - "withBackground": "З тлом", + "withBackground": "З фоном", "exportEmbedScene": "Вставити сцену в експортований файл", "exportEmbedScene_details": "Дані сцени будуть збережені в експортований файл PNG/SVG. Ця сцена може бути відновленна з нього, однак це збільшить розмір експортованого файлу.", "addWatermark": "Додати «Накреслене в Excalidraw»", @@ -76,8 +77,7 @@ "group": "Групувати виділене", "ungroup": "Розгрупувати виділене", "collaborators": "Співавтори", - "toggleGridMode": "Режим сітки", - "toggleStats": "", + "gridMode": "Режим сітки", "addToLibrary": "Додати до бібліотеки", "removeFromLibrary": "Видалити з бібліотеки", "libraryLoadingMessage": "Завантажити бібліотеку...", @@ -118,9 +118,10 @@ "redo": "Повторити", "roomDialog": "Відкрити сесію спільної роботи", "createNewRoom": "Створити нову кімнату", - "toggleFullScreen": "Повноекранний режим", - "toggleDarkMode": "Переключити темний режим", - "toggleZenMode": "Дзен-режим", + "fullScreen": "Повноекранний режим", + "darkMode": "Темний режим", + "lightMode": "Світлий режим", + "zenMode": "Режим Дзен", "exitZenMode": "Вийти з дзен-режиму" }, "alerts": { @@ -136,7 +137,7 @@ "loadSceneOverridePrompt": "Завантаження зовнішнього креслення замінить ваш наявний контент. Продовжити?", "errorLoadingLibrary": "Помилка при завантаженні сторонньої бібліотеки.", "confirmAddLibrary": "Це призведе до додавання {{numShapes}} фігур до вашої бібліотеки. Ви впевнені?", - "imageDoesNotContainScene": "Файл зображення не містить даних сцени. Ви увімкнули це під час експорту?", + "imageDoesNotContainScene": "Імпортування зображень на даний момент не підтримується.\n\nЧи хочете ви імпортувати сцену? Це зображення не містить ніяких даних сцен. Ви увімкнули це під час експорту?", "cannotRestoreFromImage": "Сцена не може бути відновлена з цього файлу зображення" }, "toolBar": { @@ -161,6 +162,7 @@ "freeDraw": "Натисніть і потягніть, відпустіть коли завершите", "text": "Порада: можна також додати текст, двічі клацнувши по будь-якому місці інструментом вибору", "linearElementMulti": "Натисніть на останню точку, клацніть Esc або Enter щоб завершити", + "lockAngle": "Ви можете обмежити кут, утримуюючи SHIFT", "resize": "Ви можете зберегти пропорції, утримуючи SHIFT під час зміни розміру,\nутримуйте ALT для змінення розміру від центру", "rotate": "Ви можете обмежити кути, утримуючи SHIFT під час обертання", "lineEditor_info": "Двічі клацніть або натисніть Enter щоб редагувати точки", @@ -227,7 +229,7 @@ "scene": "Сцена", "selected": "Вибраний", "storage": "Сховище", - "title": "", + "title": "Статистика", "total": "Всього", "width": "Ширина" } diff --git a/src/locales/zh-CN.json b/src/locales/zh-CN.json index bf38e4a25..71631fafe 100644 --- a/src/locales/zh-CN.json +++ b/src/locales/zh-CN.json @@ -1,10 +1,11 @@ { "labels": { "paste": "粘贴", + "pasteCharts": "粘贴图表", "selectAll": "全部选中", "multiSelect": "添加元素到选区", "moveCanvas": "移动画布", - "cut": "", + "cut": "剪切", "copy": "复制", "copyAsPng": "复制为 PNG 到剪贴板", "copyAsSvg": "复制为 SVG 到剪贴板", @@ -29,15 +30,15 @@ "edges": "边角", "sharp": "尖锐", "round": "圆润", - "arrowheads": "", - "arrowhead_none": "", - "arrowhead_arrow": "", - "arrowhead_bar": "", - "arrowhead_dot": "", + "arrowheads": "箭头", + "arrowhead_none": "无", + "arrowhead_arrow": "箭头", + "arrowhead_bar": "条", + "arrowhead_dot": "圆点", "fontSize": "字体大小", "fontFamily": "字体", "onlySelected": "仅被选中", - "withBackground": "添加背景", + "withBackground": "使用背景", "exportEmbedScene": "将场景嵌入到导出的文件", "exportEmbedScene_details": "场景数据将被保存到导出的 PNG/SVG 文件,以便恢复。\n将会增加导出的文件大小。", "addWatermark": "添加 “使用 Excalidraw 创建” 水印", @@ -76,12 +77,11 @@ "group": "组选", "ungroup": "取消组选", "collaborators": "协作者", - "toggleGridMode": "切换网格模式", - "toggleStats": "", + "gridMode": "网格模式", "addToLibrary": "添加到库中", "removeFromLibrary": "从库中移除", "libraryLoadingMessage": "正在加载库...", - "libraries": "", + "libraries": "浏览库", "loadingScene": "正在加载绘图...", "align": "对齐", "alignTop": "顶部对齐", @@ -118,9 +118,10 @@ "redo": "重做", "roomDialog": "开始实时协作", "createNewRoom": "新建会议室", - "toggleFullScreen": "切换全屏显示", - "toggleDarkMode": "切换暗黑模式", - "toggleZenMode": "切换禅模式", + "fullScreen": "全屏", + "darkMode": "暗色主题", + "lightMode": "浅色模式", + "zenMode": "禅意模式", "exitZenMode": "退出禅模式" }, "alerts": { @@ -136,7 +137,7 @@ "loadSceneOverridePrompt": "加载外部绘图将取代您现有的内容。您想要继续吗?", "errorLoadingLibrary": "加载第三方库时出错。", "confirmAddLibrary": "这将添加 {{numShapes}} 个形状到您的库。您确定吗?", - "imageDoesNotContainScene": "图像文件不包含场景数据。您是否在导出过程中启用了此选项?", + "imageDoesNotContainScene": "当前不支持导入图片。\n\n您想要导入场景吗?此图像似乎不包含任何场景数据。您是否在导出过程中启用了这个数据?", "cannotRestoreFromImage": "无法从此图像文件恢复场景" }, "toolBar": { @@ -161,6 +162,7 @@ "freeDraw": "点击并拖动,完成后发布", "text": "提示:您也可以使用选择工具双击任意位置来添加文字", "linearElementMulti": "点击最后一个点或按下 Esc/Enter 来完成", + "lockAngle": "可以按住 Shift 来约束角度", "resize": "您可以按住SHIFT来限制比例大小,\n按住ALT来调整中心大小", "rotate": "旋转时可以按住 Shift 来约束角度", "lineEditor_info": "双击或按回车键编辑", @@ -200,7 +202,7 @@ "shortcutsDialog": { "title": "快捷键列表", "shapes": "形状", - "or": "或者", + "or": "或", "click": "点击", "drag": "拖动", "curvedArrow": "曲线(带有箭头)", @@ -209,7 +211,7 @@ "view": "视图", "blog": "浏览我们的博客", "howto": "跟随我们的指南", - "github": "发现问题?提交", + "github": "发现问题?请提出来", "textNewLine": "文本换行", "textFinish": "完成编辑文本", "zoomToFit": "缩放以适应所有元素", @@ -217,7 +219,7 @@ "preventBinding": "防止箭头吸附" }, "encrypted": { - "tooltip": "您的绘图采用的端到端加密,因此Excalidraw服务器永远不会收集。" + "tooltip": "您的绘图采用的端到端加密,其内容对于Excalidraw服务器是不可见的。" }, "stats": { "angle": "角度", @@ -227,7 +229,7 @@ "scene": "场景", "selected": "选中", "storage": "存储", - "title": "", + "title": "详细统计信息", "total": "总计", "width": "宽度" } diff --git a/src/locales/zh-TW.json b/src/locales/zh-TW.json index a567cc199..eed021e2d 100644 --- a/src/locales/zh-TW.json +++ b/src/locales/zh-TW.json @@ -1,6 +1,7 @@ { "labels": { "paste": "貼上", + "pasteCharts": "貼上圖表", "selectAll": "全選", "multiSelect": "將物件加入選取範圍", "moveCanvas": "移動畫布", @@ -76,12 +77,11 @@ "group": "建立群組", "ungroup": "取消群組", "collaborators": "協作者", - "toggleGridMode": "切換格線模式", - "toggleStats": "切換詳細統計", + "gridMode": "網格模式", "addToLibrary": "加入資料庫", "removeFromLibrary": "從資料庫中移除", "libraryLoadingMessage": "資料庫讀取中…", - "libraries": "", + "libraries": "瀏覽資料庫", "loadingScene": "場景讀取中…", "align": "對齊", "alignTop": "對齊頂部", @@ -118,9 +118,10 @@ "redo": "重做", "roomDialog": "開始即時協作", "createNewRoom": "建立新協作會議室", - "toggleFullScreen": "切換全螢幕", - "toggleDarkMode": "切換深色模式", - "toggleZenMode": "切換專注模式", + "fullScreen": "全螢幕", + "darkMode": "深色模式", + "lightMode": "淺色模式", + "zenMode": "專注模式", "exitZenMode": "離開專注模式" }, "alerts": { @@ -136,7 +137,7 @@ "loadSceneOverridePrompt": "讀取外部圖樣將取代目前的內容。是否要繼續?", "errorLoadingLibrary": "載入第三方套件時出現錯誤。", "confirmAddLibrary": "這將會將 {{numShapes}} 個圖形加入你的資料庫,你確定嗎?", - "imageDoesNotContainScene": "圖檔中未包含場景資料。輸出檔案時是否有包含此資料?", + "imageDoesNotContainScene": "目前尚不支援載入圖片。\n您是否要載入場景?此圖片中並無任何場景資料,輸出時是否有選擇包含?", "cannotRestoreFromImage": "無法由此檔案回復場景。" }, "toolBar": { @@ -161,6 +162,7 @@ "freeDraw": "點擊並拖曳來繪圖,放開即結束", "text": "提示:亦可使用選取工具在任何地方雙擊來加入文字", "linearElementMulti": "按下 Escape 或 Enter 以結束繪製", + "lockAngle": "按住 SHIFT 可限制旋轉角度", "resize": "縮放時按住 Shift 可保持原比例縮放;\\n按住 Alt 可由中心點進行縮放", "rotate": "旋轉時按住 Shift 可限制旋轉角度", "lineEditor_info": "雙擊滑鼠左鍵或按 Enter 來編輯控制點", diff --git a/src/packages/excalidraw/CHANGELOG.md b/src/packages/excalidraw/CHANGELOG.md index ab26fdf34..865a64470 100644 --- a/src/packages/excalidraw/CHANGELOG.md +++ b/src/packages/excalidraw/CHANGELOG.md @@ -16,6 +16,10 @@ Please add the latest change on the top under the correct section. ### Features +- Add `cmd+o` shortcut to load scene [#2732](https://github.com/excalidraw/excalidraw/pull/2732) +- Remove language picker, and add `langCode`, `renderFooter` [#2644](https://github.com/excalidraw/excalidraw/pull/2644): + - BREAKING: removed the language picker from UI. It is now the host app's responsibility to implement a language picker if desirable, using the newly added [`renderFooter`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#renderFooter) prop. The reasoning is that the i18n should be controlled by the app itself, not by the nested Excalidraw component. + - Added [`langCode`](https://github.com/excalidraw/excalidraw/blob/master/src/packages/excalidraw/README.md#langCode) prop to control the UI language. - Add support for `exportToBackend` prop to allow host apps to implement shareable links [#2612](https://github.com/excalidraw/excalidraw/pull/2612/files) - Add zoom to selection [#2522](https://github.com/excalidraw/excalidraw/pull/2522) - Insert Library items in the middle of the screen [#2527](https://github.com/excalidraw/excalidraw/pull/2527) @@ -27,6 +31,7 @@ Please add the latest change on the top under the correct section. ### Fixes +- Fix initialization when browser tab not focused [#2677](https://github.com/excalidraw/excalidraw/pull/2677) - Consistent case for export locale strings [#2622](https://github.com/excalidraw/excalidraw/pull/2622) - Remove unnecessary console.error as it was polluting Sentry [#2637](https://github.com/excalidraw/excalidraw/pull/2637) - Fix scroll-to-center on init for non-zero canvas offsets [#2445](https://github.com/excalidraw/excalidraw/pull/2445) @@ -39,6 +44,8 @@ Please add the latest change on the top under the correct section. ### Improvements +- Added Zen Mode to the context menu [#2734](https://github.com/excalidraw/excalidraw/pull/2734) +- Do not reset to selection when using the draw tool [#2721](https://github.com/excalidraw/excalidraw/pull/2721) - Display proper tooltip for 2-point lines during resize, and normalize modifier key labels in hints [#2655](https://github.com/excalidraw/excalidraw/pull/2655) - Improve error message around importing images [#2619](https://github.com/excalidraw/excalidraw/pull/2619) - Add tooltip with icon for embedding scenes [#2532](https://github.com/excalidraw/excalidraw/pull/2532) @@ -51,6 +58,10 @@ Please add the latest change on the top under the correct section. - Bump ini from 1.3.5 to 1.3.7 in /src/packages/excalidraw [#2500](https://github.com/excalidraw/excalidraw/pull/2500) +### Docs + +- Document some of the more exotic element props [#2673](https://github.com/excalidraw/excalidraw/pull/2673) + ## 0.1.1 #### Fix diff --git a/src/packages/excalidraw/README.md b/src/packages/excalidraw/README.md index 276bafd4a..36c76f668 100644 --- a/src/packages/excalidraw/README.md +++ b/src/packages/excalidraw/README.md @@ -125,20 +125,22 @@ export default function App() { ### Props -| Name | Type | Default | Description | -| --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [`width`](#width) | Number | `window.innerWidth` | The width of Excalidraw component | -| [`height`](#height) | Number | `window.innerHeight` | The height of Excalidraw component | -| [`offsetLeft`](#offsetLeft) | Number | `0` | left position relative to which Excalidraw should be rendered | -| [`offsetTop`](#offsetTop) | Number | `0` | top position relative to which Excalidraw should render | -| [`onChange`](#onChange) | Function | | This callback is triggered whenever the component updates due to any change. This callback will receive the excalidraw elements and the current app state. | -| [`initialData`](#initialData) | [`ExcalidrawElement[]`](https://github.com/excalidraw/excalidraw/blob/4c90ea5667d29effe8ec4a115e49efc7c340cdb3/src/types.ts#L151) | [] | The initial data with which app loads. | -| [`user`](#user) | `{ name?: string }` | | User details. The name refers to the name of the user to be shown | -| [`excalidrawRef`](#excalidrawRef) | [`createRef`](https://reactjs.org/docs/refs-and-the-dom.html#creating-refs) or [`callbackRef`](https://reactjs.org/docs/refs-and-the-dom.html#callback-refs) or
{ current: { readyPromise: resolvablePromise } }
| | Ref to be passed to Excalidraw | -| [`onCollabButtonClick`](#onCollabButtonClick) | Function | | Callback to be triggered when the collab button is clicked | -| [`isCollaborating`](#isCollaborating) | `boolean` | | This implies if the app is in collaboration mode | -| [`onPointerUpdate`](#onPointerUpdate) | Function | | Callback triggered when mouse pointer is updated. | -| [`onExportToBackend`](#onExportToBackend) | Function | | Callback triggered when link button is clicked on export dialog | +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| [`width`](#width) | Number | `window.innerWidth` | The width of Excalidraw component | +| [`height`](#height) | Number | `window.innerHeight` | The height of Excalidraw component | +| [`offsetLeft`](#offsetLeft) | Number | `0` | left position relative to which Excalidraw should be rendered | +| [`offsetTop`](#offsetTop) | Number | `0` | top position relative to which Excalidraw should render | +| [`onChange`](#onChange) | Function | | This callback is triggered whenever the component updates due to any change. This callback will receive the excalidraw elements and the current app state. | +| [`initialData`](#initialData) |
{elements?: ExcalidrawElement[], appState?: AppState } 
| null | The initial data with which app loads. | +| [`user`](#user) | `{ name?: string }` | | User details. The name refers to the name of the user to be shown | +| [`excalidrawRef`](#excalidrawRef) | [`createRef`](https://reactjs.org/docs/refs-and-the-dom.html#creating-refs) or [`callbackRef`](https://reactjs.org/docs/refs-and-the-dom.html#callback-refs) or
{ current: { readyPromise: resolvablePromise } }
| | Ref to be passed to Excalidraw | +| [`onCollabButtonClick`](#onCollabButtonClick) | Function | | Callback to be triggered when the collab button is clicked | +| [`isCollaborating`](#isCollaborating) | `boolean` | | This implies if the app is in collaboration mode | +| [`onPointerUpdate`](#onPointerUpdate) | Function | | Callback triggered when mouse pointer is updated. | +| [`onExportToBackend`](#onExportToBackend) | Function | | Callback triggered when link button is clicked on export dialog | +| [`langCode`](#langCode) | string | `en` | Language code string | +| [`renderFooter `](#renderFooter) | Function | | Function that renders custom UI footer | #### `width` @@ -164,21 +166,20 @@ Every time component updates, this callback if passed will get triggered and has (excalidrawElements, appState) => void; ``` -1.`excalidrawElements`: Array of [excalidrawElements](https://github.com/excalidraw/excalidraw/blob/4c90ea5667d29effe8ec4a115e49efc7c340cdb3/src/element/types.ts#L59) in the scene. +1.`excalidrawElements`: Array of [excalidrawElements](https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78) in the scene. -2.`appState`: [AppState](https://github.com/excalidraw/excalidraw/blob/4c90ea5667d29effe8ec4a115e49efc7c340cdb3/src/types.ts#L33) of the scene +2.`appState`: [AppState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L37) of the scene Here you can try saving the data to your backend or local storage for example. #### `initialData` -This helps to load Excalidraw with `initialData`. -It must be an object or a [promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise) which resolves to an object containing the below optional fields. +This helps to load Excalidraw with `initialData`. It must be an object or a [promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/Promise) which resolves to an object containing the below optional fields. -| name | type | -| -------- | --------------------------------------------------------------------------------------------------------------------------------------- | -| elements | [ExcalidrawElement []](https://github.com/excalidraw/excalidraw/blob/4c90ea5667d29effe8ec4a115e49efc7c340cdb3/src/element/types.ts#L59) | -| appState | [AppState](https://github.com/excalidraw/excalidraw/blob/4c90ea5667d29effe8ec4a115e49efc7c340cdb3/src/types.ts#L33) | +| name | type | +| --- | --- | +| elements | [ExcalidrawElement []](https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L78) | +| appState | [AppState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L37) | ```json { @@ -217,24 +218,23 @@ This is the user name which shows during collaboration. Defaults to `{name: ''}` #### `excalidrawRef` -You can pass a `ref` when you want to access some excalidraw APIs. -We expose the below APIs: +You can pass a `ref` when you want to access some excalidraw APIs. We expose the below APIs: -| API | signature | Usage | -| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| ready | `boolean` | This is set to true once Excalidraw is rendered | -| readyPromise | [resolvablePromise](https://github.com/excalidraw/excalidraw/blob/4c90ea5667d29effe8ec4a115e49efc7c340cdb3/src/utils.ts#L312) | This promise will be resolved with the api once excalidraw has rendered. This will be helpful when you want do some action on the host app once this promise resolves. For this to work you will have to pass ref as shown [here](#readyPromise) | -| updateScene |
(sceneData)) => void 
| updates the scene with the sceneData | -| resetScene | `({ resetLoadingState: boolean }) => void` | Resets the scene. If `resetLoadingState` is passed as true then it will also force set the loading state to false. | -| getSceneElementsIncludingDeleted |
 () => ExcalidrawElement []
| Returns all the elements including the deleted in the scene | -| getSceneElements |
 () => ExcalidrawElement []
| Returns all the elements excluding the deleted in the scene | -| history | `{ clear: () => void }` | This is the history API. `history.clear()` will clear the history | -| setScrollToCenter |
 (ExcalidrawElement[]) => void 
| sets the elements to center | +| API | signature | Usage | +| --- | --- | --- | +| ready | `boolean` | This is set to true once Excalidraw is rendered | +| readyPromise | [resolvablePromise](https://github.com/excalidraw/excalidraw/blob/master/src/utils.ts#L317) | This promise will be resolved with the api once excalidraw has rendered. This will be helpful when you want do some action on the host app once this promise resolves. For this to work you will have to pass ref as shown [here](#readyPromise) | +| updateScene |
(sceneData)) => void 
| updates the scene with the sceneData | +| resetScene | `({ resetLoadingState: boolean }) => void` | Resets the scene. If `resetLoadingState` is passed as true then it will also force set the loading state to false. | +| getSceneElementsIncludingDeleted |
 () => ExcalidrawElement []
| Returns all the elements including the deleted in the scene | +| getSceneElements |
 () => ExcalidrawElement []
| Returns all the elements excluding the deleted in the scene | +| history | `{ clear: () => void }` | This is the history API. `history.clear()` will clear the history | +| setScrollToCenter |
 (ExcalidrawElement[]) => void 
| sets the elements to center | #### `readyPromise`
-const excalidrawRef = { current: { readyPromise: resolvablePromise}}
+const excalidrawRef = { current: { readyPromise: resolvablePromise}}
 
#### `onCollabButtonClick` @@ -257,7 +257,7 @@ This callback is triggered when mouse pointer is updated. 2.`button`: The position of the button. This will be one of `["down", "up"]` -3.`pointersMap`: [`pointers map`](https://github.com/excalidraw/excalidraw/blob/182a3e39e1362d73d2a565c870eb2fb72071fdcc/src/types.ts#L122) of the scene +3.`pointersMap`: [`pointers map`](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L131) of the scene #### `onExportToBackend` @@ -267,6 +267,23 @@ This callback is triggered when the shareable-link button is clicked in the expo (exportedElements, appState, canvas) => void ``` -1. `exportedElements`: An array of [non deleted elements](https://github.com/excalidraw/excalidraw/blob/6e45cb95dbd7a8be1859c7055b06957298e3097c/src/element/types.ts#L76) which needs to be exported. -2. `appState`: [AppState](https://github.com/excalidraw/excalidraw/blob/4c90ea5667d29effe8ec4a115e49efc7c340cdb3/src/types.ts#L33) of the scene. +1. `exportedElements`: An array of [non deleted elements](https://github.com/excalidraw/excalidraw/blob/master/src/element/types.ts#L87) which needs to be exported. +2. `appState`: [AppState](https://github.com/excalidraw/excalidraw/blob/master/src/types.ts#L37) of the scene. 3. `canvas`: The `HTMLCanvasElement` of the scene. + +#### `langCode` + +Determines the language of the UI. It should be one of the [available language codes](https://github.com/excalidraw/excalidraw/blob/master/src/i18n.ts#L14). Defaults to `en` (English). We also export default language and supported languages which you can import as shown below. + +```js +import { defaultLang, languages } from "@excalidraw/excalidraw"; +``` + +| name | type | +| --- | --- | +| defaultLang | string | +| languages | [Language []](https://github.com/excalidraw/excalidraw/blob/master/src/i18n.ts#L8) | + +#### `renderFooter` + +A function that renders (returns JSX) custom UI footer. For example, you can use this to render a language picker that was previously being rendered by Excalidraw itself (for now, you'll need to implement your own language picker). diff --git a/src/packages/excalidraw/index.tsx b/src/packages/excalidraw/index.tsx index 577250971..c298fc94e 100644 --- a/src/packages/excalidraw/index.tsx +++ b/src/packages/excalidraw/index.tsx @@ -8,6 +8,7 @@ import "../../css/styles.scss"; import { ExcalidrawAPIRefValue, ExcalidrawProps } from "../../types"; import { IsMobileProvider } from "../../is-mobile"; +import { defaultLang } from "../../i18n"; const Excalidraw = (props: ExcalidrawProps) => { const { @@ -23,6 +24,8 @@ const Excalidraw = (props: ExcalidrawProps) => { isCollaborating, onPointerUpdate, onExportToBackend, + renderFooter, + langCode = defaultLang.code, } = props; useEffect(() => { @@ -44,7 +47,7 @@ const Excalidraw = (props: ExcalidrawProps) => { }, []); return ( - + { isCollaborating={isCollaborating} onPointerUpdate={onPointerUpdate} onExportToBackend={onExportToBackend} + renderFooter={renderFooter} + langCode={langCode} /> @@ -94,3 +99,4 @@ export { getSyncableElements, getElementMap, } from "../../element"; +export { defaultLang, languages } from "../../i18n"; diff --git a/src/packages/excalidraw/package-lock.json b/src/packages/excalidraw/package-lock.json index 23db6e1e8..cb79f61bc 100644 --- a/src/packages/excalidraw/package-lock.json +++ b/src/packages/excalidraw/package-lock.json @@ -1149,6 +1149,12 @@ "to-fast-properties": "^2.0.0" } }, + "@discoveryjs/json-ext": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz", + "integrity": "sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg==", + "dev": true + }, "@polka/url": { "version": "1.0.0-next.11", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.11.tgz", @@ -1369,18 +1375,18 @@ } }, "@webpack-cli/info": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.1.0.tgz", - "integrity": "sha512-uNWSdaYHc+f3LdIZNwhdhkjjLDDl3jP2+XBqAq9H8DjrJUvlOKdP8TNruy1yEaDfgpAIgbSAN7pye4FEHg9tYQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.2.1.tgz", + "integrity": "sha512-fLnDML5HZ5AEKzHul8xLAksoKN2cibu6MgonkUj8R9V7bbeVRkd1XbGEGWrAUNYHbX1jcqCsDEpBviE5StPMzQ==", "dev": true, "requires": { "envinfo": "^7.7.3" } }, "@webpack-cli/serve": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.1.0.tgz", - "integrity": "sha512-7RfnMXCpJ/NThrhq4gYQYILB18xWyoQcBey81oIyVbmgbc6m5ZHHyFK+DyH7pLHJf0p14MxL4mTsoPAgBSTpIg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.2.1.tgz", + "integrity": "sha512-Zj1z6AyS+vqV6Hfi7ngCjFGdHV5EwZNIHo6QfFTNe9PyW+zBU1zJ9BiOW1pmUEq950RC4+Dym6flyA/61/vhyw==", "dev": true }, "@xtuc/ieee754": { @@ -1446,12 +1452,6 @@ "color-convert": "^1.9.0" } }, - "array-back": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz", - "integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==", - "dev": true - }, "babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", @@ -1761,18 +1761,6 @@ "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==", "dev": true }, - "command-line-usage": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.1.tgz", - "integrity": "sha512-F59pEuAR9o1SF/bD0dQBDluhpT4jJQNWUHEuVBqpDmCUo6gPjCi+m9fCWnWZVR/oG6cMTUms4h+3NPl74wGXvA==", - "dev": true, - "requires": { - "array-back": "^4.0.1", - "chalk": "^2.4.2", - "table-layout": "^1.0.1", - "typical": "^5.2.0" - } - }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -1912,12 +1900,6 @@ "ms": "2.1.2" } }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -1945,15 +1927,6 @@ "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, "enhanced-resolve": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz", @@ -1981,9 +1954,9 @@ "dev": true }, "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, "requires": { "prr": "~1.0.1" @@ -2047,19 +2020,19 @@ "dev": true }, "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", + "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", "dev": true, "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, @@ -2075,6 +2048,12 @@ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, + "fastest-levenshtein": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", + "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", + "dev": true + }, "file-loader": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", @@ -2163,13 +2142,10 @@ } }, "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz", + "integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==", + "dev": true }, "glob-to-regexp": { "version": "0.4.1", @@ -2229,9 +2205,9 @@ "dev": true }, "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, "icss-utils": { @@ -2248,51 +2224,6 @@ "requires": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - } } }, "indexes-of": { @@ -2322,6 +2253,15 @@ "loose-envify": "^1.0.0" } }, + "is-core-module": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -2413,12 +2353,6 @@ "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==", "dev": true }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, "loader-runner": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.1.0.tgz", @@ -2530,18 +2464,18 @@ "dev": true }, "mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "version": "1.45.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz", + "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==", "dev": true }, "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "version": "2.1.28", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz", + "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==", "dev": true, "requires": { - "mime-db": "1.44.0" + "mime-db": "1.45.0" } }, "mimic-fn": { @@ -2642,15 +2576,6 @@ "object-keys": "^1.1.1" } }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, "onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -2807,16 +2732,6 @@ "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", "dev": true }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -2856,12 +2771,6 @@ "resolve": "^1.9.0" } }, - "reduce-flatten": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", - "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", - "dev": true - }, "regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -2930,11 +2839,12 @@ } }, "resolve": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", - "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", "dev": true, "requires": { + "is-core-module": "^2.1.0", "path-parse": "^1.0.6" } }, @@ -3126,18 +3036,6 @@ "has-flag": "^3.0.0" } }, - "table-layout": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.1.tgz", - "integrity": "sha512-dEquqYNJiGwY7iPfZ3wbXDI944iqanTSchrACLL2nOB+1r+h1Nzu2eH+DuPPvWvm5Ry7iAPeFlgEtP5bIp5U7Q==", - "dev": true, - "requires": { - "array-back": "^4.0.1", - "deep-extend": "~0.6.0", - "typical": "^5.2.0", - "wordwrapjs": "^4.0.0" - } - }, "tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", @@ -3227,9 +3125,9 @@ "dev": true }, "ts-loader": { - "version": "8.0.12", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.0.12.tgz", - "integrity": "sha512-UIivVfGVJDdwwjgSrbtcL9Nf10c1BWnL1mxAQUVcnhNIn/P9W3nP5v60Z0aBMtc7ZrE11lMmU6+5jSgAXmGaYw==", + "version": "8.0.13", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.0.13.tgz", + "integrity": "sha512-1o1nO6aqouA23d2nlcMSEyPMAWRhnYUU0EQUJSc60E0TUyBNX792RHFYUN1ZM29vhMUNayrsbj2UVdZwKhXCDA==", "dev": true, "requires": { "chalk": "^2.3.0", @@ -3253,12 +3151,6 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, - "typical": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", - "dev": true - }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", @@ -3325,9 +3217,9 @@ } }, "webpack": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.11.0.tgz", - "integrity": "sha512-ubWv7iP54RqAC/VjixgpnLLogCFbAfSOREcSWnnOlZEU8GICC5eKmJSu6YEnph2N2amKqY9rvxSwgyHxVqpaRw==", + "version": "5.11.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.11.1.tgz", + "integrity": "sha512-tNUIdAmYJv+nupRs/U/gqmADm6fgrf5xE+rSlSsf2PgsGO7j2WG7ccU6AWNlOJlHFl+HnmXlBmHIkiLf+XA9mQ==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.0", @@ -3357,13 +3249,13 @@ }, "dependencies": { "enhanced-resolve": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.4.0.tgz", - "integrity": "sha512-ZmqfWURB2lConOBM1JdCVfPyMRv5RdKWktLXO6123p97ovVm2CLBgw9t5MBj3jJWA6eHyOeIws9iJQoGFR4euQ==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.4.1.tgz", + "integrity": "sha512-4GbyIMzYktTFoRSmkbgZ1LU+RXwf4AQ8Z+rSuuh1dC8plp0PPeaWvx6+G4hh4KnUJ48VoxKbNyA1QQQIUpXjYA==", "dev": true, "requires": { "graceful-fs": "^4.2.4", - "tapable": "^2.0.0" + "tapable": "^2.2.0" } }, "find-up": { @@ -3522,21 +3414,21 @@ } }, "webpack-cli": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.2.0.tgz", - "integrity": "sha512-EIl3k88vaF4fSxWSgtAQR+VwicfLMTZ9amQtqS4o+TDPW9HGaEpbFBbAZ4A3ZOT5SOnMxNOzROsSTPiE8tBJPA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.3.1.tgz", + "integrity": "sha512-/F4+9QNZM/qKzzL9/06Am8NXIkGV+/NqQ62Dx7DSqudxxpAgBqYn6V7+zp+0Y7JuWksKUbczRY3wMTd+7Uj6OA==", "dev": true, "requires": { - "@webpack-cli/info": "^1.1.0", - "@webpack-cli/serve": "^1.1.0", + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/info": "^1.2.1", + "@webpack-cli/serve": "^1.2.1", "colorette": "^1.2.1", - "command-line-usage": "^6.1.0", "commander": "^6.2.0", "enquirer": "^2.3.6", - "execa": "^4.1.0", + "execa": "^5.0.0", + "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", "interpret": "^2.2.0", - "leven": "^3.1.0", "rechoir": "^0.7.0", "v8-compile-cache": "^2.2.0", "webpack-merge": "^4.2.2" @@ -3586,22 +3478,6 @@ "isexe": "^2.0.0" } }, - "wordwrapjs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.0.tgz", - "integrity": "sha512-Svqw723a3R34KvsMgpjFBYCgNOSdcW3mQFK4wIfhGQhtaFVOJmdYoXgi63ne3dTlWgatVcUc7t4HtQ/+bUVIzQ==", - "dev": true, - "requires": { - "reduce-flatten": "^2.0.0", - "typical": "^5.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, "ws": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz", diff --git a/src/packages/excalidraw/package.json b/src/packages/excalidraw/package.json index 80c9b4d79..cce5d6163 100644 --- a/src/packages/excalidraw/package.json +++ b/src/packages/excalidraw/package.json @@ -57,10 +57,10 @@ "mini-css-extract-plugin": "1.3.3", "sass-loader": "10.1.0", "terser-webpack-plugin": "5.0.3", - "ts-loader": "8.0.12", - "webpack": "5.11.0", + "ts-loader": "8.0.13", + "webpack": "5.11.1", "webpack-bundle-analyzer": "4.3.0", - "webpack-cli": "4.2.0" + "webpack-cli": "4.3.1" }, "bugs": "https://github.com/excalidraw/excalidraw/issues", "repository": "https://github.com/excalidraw/excalidraw", diff --git a/src/packages/utils/CHANGELOG.md b/src/packages/utils/CHANGELOG.md index f706bf973..395b77e7e 100644 --- a/src/packages/utils/CHANGELOG.md +++ b/src/packages/utils/CHANGELOG.md @@ -4,6 +4,4 @@ First release of `@excalidraw/utils` to provide utilities functions. -- Added `exportToBlob` and `exportToSvg` to export an Excalidraw diagram definition, respectively, - to a [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) and - to a [SVGElement](https://developer.mozilla.org/en-US/docs/Web/API/SVGElement) ([#2246](https://github.com/excalidraw/excalidraw/pull/2246)) +- Added `exportToBlob` and `exportToSvg` to export an Excalidraw diagram definition, respectively, to a [Blob](https://developer.mozilla.org/en-US/docs/Web/API/Blob) and to a [SVGElement](https://developer.mozilla.org/en-US/docs/Web/API/SVGElement) ([#2246](https://github.com/excalidraw/excalidraw/pull/2246)) diff --git a/src/packages/utils/README.md b/src/packages/utils/README.md index 2615078b5..7d53e497f 100644 --- a/src/packages/utils/README.md +++ b/src/packages/utils/README.md @@ -24,8 +24,7 @@ Export an Excalidraw diagram to a [SVGElement](https://developer.mozilla.org/en- ## Usage -Excalidraw utils is published as a UMD (Universal Module Definition). -If you are using a Web bundler (for instance, Webpack), you can import it as an ES6 module: +Excalidraw utils is published as a UMD (Universal Module Definition). If you are using a Web bundler (for instance, Webpack), you can import it as an ES6 module: ```js import { exportToSvg, exportToBlob } from "@excalidraw/utils"; diff --git a/src/packages/utils/package-lock.json b/src/packages/utils/package-lock.json index 3e3f27ad2..9d2f334ac 100644 --- a/src/packages/utils/package-lock.json +++ b/src/packages/utils/package-lock.json @@ -1064,6 +1064,12 @@ "to-fast-properties": "^2.0.0" } }, + "@discoveryjs/json-ext": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz", + "integrity": "sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg==", + "dev": true + }, "@polka/url": { "version": "1.0.0-next.11", "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.11.tgz", @@ -1103,9 +1109,9 @@ "dev": true }, "@types/node": { - "version": "14.14.14", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.14.tgz", - "integrity": "sha512-UHnOPWVWV1z+VV8k6L1HhG7UbGBgIdghqF3l9Ny9ApPghbjICXkUJSd/b9gOgQfjM1r+37cipdw/HJ3F6ICEnQ==", + "version": "14.14.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.19.tgz", + "integrity": "sha512-4nhBPStMK04rruRVtVc6cDqhu7S9GZai0fpXgPXrFpcPX6Xul8xnrjSdGB4KPBVYG/R5+fXWdCM8qBoiULWGPQ==", "dev": true }, "@webassemblyjs/ast": { @@ -1284,18 +1290,18 @@ } }, "@webpack-cli/info": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.1.0.tgz", - "integrity": "sha512-uNWSdaYHc+f3LdIZNwhdhkjjLDDl3jP2+XBqAq9H8DjrJUvlOKdP8TNruy1yEaDfgpAIgbSAN7pye4FEHg9tYQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.2.1.tgz", + "integrity": "sha512-fLnDML5HZ5AEKzHul8xLAksoKN2cibu6MgonkUj8R9V7bbeVRkd1XbGEGWrAUNYHbX1jcqCsDEpBviE5StPMzQ==", "dev": true, "requires": { "envinfo": "^7.7.3" } }, "@webpack-cli/serve": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.1.0.tgz", - "integrity": "sha512-7RfnMXCpJ/NThrhq4gYQYILB18xWyoQcBey81oIyVbmgbc6m5ZHHyFK+DyH7pLHJf0p14MxL4mTsoPAgBSTpIg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.2.1.tgz", + "integrity": "sha512-Zj1z6AyS+vqV6Hfi7ngCjFGdHV5EwZNIHo6QfFTNe9PyW+zBU1zJ9BiOW1pmUEq950RC4+Dym6flyA/61/vhyw==", "dev": true }, "@xtuc/ieee754": { @@ -1361,12 +1367,6 @@ "color-convert": "^1.9.0" } }, - "array-back": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-4.0.1.tgz", - "integrity": "sha512-Z/JnaVEXv+A9xabHzN43FiiiWEE7gPCRXMrVmRm00tWbjZRul1iHm7ECzlyNq1p4a4ATXz+G9FJ3GqGOkOV3fg==", - "dev": true - }, "babel-code-frame": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", @@ -1670,18 +1670,6 @@ "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==", "dev": true }, - "command-line-usage": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-6.1.1.tgz", - "integrity": "sha512-F59pEuAR9o1SF/bD0dQBDluhpT4jJQNWUHEuVBqpDmCUo6gPjCi+m9fCWnWZVR/oG6cMTUms4h+3NPl74wGXvA==", - "dev": true, - "requires": { - "array-back": "^4.0.1", - "chalk": "^2.4.2", - "table-layout": "^1.0.1", - "typical": "^5.2.0" - } - }, "commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", @@ -1762,12 +1750,6 @@ "ms": "2.1.2" } }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true - }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -1795,15 +1777,6 @@ "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, "enhanced-resolve": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.3.0.tgz", @@ -1831,9 +1804,9 @@ "dev": true }, "errno": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", "dev": true, "requires": { "prr": "~1.0.1" @@ -1897,19 +1870,19 @@ "dev": true }, "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.0.0.tgz", + "integrity": "sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==", "dev": true, "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, @@ -1925,6 +1898,12 @@ "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, + "fastest-levenshtein": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", + "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", + "dev": true + }, "file-loader": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz", @@ -2013,13 +1992,10 @@ } }, "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz", + "integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==", + "dev": true }, "glob-to-regexp": { "version": "0.4.1", @@ -2079,9 +2055,9 @@ "dev": true }, "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, "import-local": { @@ -2209,12 +2185,6 @@ "minimist": "^1.2.5" } }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, "loader-runner": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.1.0.tgz", @@ -2317,18 +2287,18 @@ "dev": true }, "mime-db": { - "version": "1.44.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", - "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "version": "1.45.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.45.0.tgz", + "integrity": "sha512-CkqLUxUk15hofLoLyljJSrukZi8mAtgd+yE5uO4tqRZsdsAJKv0O+rFMhVDRJgozy+yG6md5KwuXhD4ocIoP+w==", "dev": true }, "mime-types": { - "version": "2.1.27", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", - "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "version": "2.1.28", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.28.tgz", + "integrity": "sha512-0TO2yJ5YHYr7M2zzT7gDU1tbwHxEUWBCLt0lscSNpcdAfFyJOVEpRYNS7EXVcTLNj/25QO8gulHC5JtTzSE2UQ==", "dev": true, "requires": { - "mime-db": "1.44.0" + "mime-db": "1.45.0" } }, "mimic-fn": { @@ -2388,15 +2358,6 @@ "object-keys": "^1.1.1" } }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, "onetime": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", @@ -2481,16 +2442,6 @@ "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", "dev": true }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", @@ -2530,12 +2481,6 @@ "resolve": "^1.9.0" } }, - "reduce-flatten": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", - "integrity": "sha512-EJ4UNY/U1t2P/2k6oqotuX2Cc3T6nxJwsM0N0asT7dhrtH1ltUxDn4NalSYmPE2rCkVpcf/X6R0wDwcFpzhd4w==", - "dev": true - }, "regenerate": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", @@ -2755,18 +2700,6 @@ "has-flag": "^3.0.0" } }, - "table-layout": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-1.0.1.tgz", - "integrity": "sha512-dEquqYNJiGwY7iPfZ3wbXDI944iqanTSchrACLL2nOB+1r+h1Nzu2eH+DuPPvWvm5Ry7iAPeFlgEtP5bIp5U7Q==", - "dev": true, - "requires": { - "array-back": "^4.0.1", - "deep-extend": "~0.6.0", - "typical": "^5.2.0", - "wordwrapjs": "^4.0.0" - } - }, "tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", @@ -2856,9 +2789,9 @@ "dev": true }, "ts-loader": { - "version": "8.0.12", - "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.0.12.tgz", - "integrity": "sha512-UIivVfGVJDdwwjgSrbtcL9Nf10c1BWnL1mxAQUVcnhNIn/P9W3nP5v60Z0aBMtc7ZrE11lMmU6+5jSgAXmGaYw==", + "version": "8.0.13", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-8.0.13.tgz", + "integrity": "sha512-1o1nO6aqouA23d2nlcMSEyPMAWRhnYUU0EQUJSc60E0TUyBNX792RHFYUN1ZM29vhMUNayrsbj2UVdZwKhXCDA==", "dev": true, "requires": { "chalk": "^2.3.0", @@ -2882,12 +2815,6 @@ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "dev": true }, - "typical": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-5.2.0.tgz", - "integrity": "sha512-dvdQgNDNJo+8B2uBQoqdb11eUCE1JQXhvjC/CZtgvZseVd5TYMXnq0+vuUemXbd/Se29cTaUuPX3YIc2xgbvIg==", - "dev": true - }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", @@ -2948,9 +2875,9 @@ } }, "webpack": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.11.0.tgz", - "integrity": "sha512-ubWv7iP54RqAC/VjixgpnLLogCFbAfSOREcSWnnOlZEU8GICC5eKmJSu6YEnph2N2amKqY9rvxSwgyHxVqpaRw==", + "version": "5.11.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.11.1.tgz", + "integrity": "sha512-tNUIdAmYJv+nupRs/U/gqmADm6fgrf5xE+rSlSsf2PgsGO7j2WG7ccU6AWNlOJlHFl+HnmXlBmHIkiLf+XA9mQ==", "dev": true, "requires": { "@types/eslint-scope": "^3.7.0", @@ -2980,13 +2907,13 @@ }, "dependencies": { "enhanced-resolve": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.4.0.tgz", - "integrity": "sha512-ZmqfWURB2lConOBM1JdCVfPyMRv5RdKWktLXO6123p97ovVm2CLBgw9t5MBj3jJWA6eHyOeIws9iJQoGFR4euQ==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.4.1.tgz", + "integrity": "sha512-4GbyIMzYktTFoRSmkbgZ1LU+RXwf4AQ8Z+rSuuh1dC8plp0PPeaWvx6+G4hh4KnUJ48VoxKbNyA1QQQIUpXjYA==", "dev": true, "requires": { "graceful-fs": "^4.2.4", - "tapable": "^2.0.0" + "tapable": "^2.2.0" } }, "find-up": { @@ -3129,21 +3056,21 @@ } }, "webpack-cli": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.2.0.tgz", - "integrity": "sha512-EIl3k88vaF4fSxWSgtAQR+VwicfLMTZ9amQtqS4o+TDPW9HGaEpbFBbAZ4A3ZOT5SOnMxNOzROsSTPiE8tBJPA==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.3.1.tgz", + "integrity": "sha512-/F4+9QNZM/qKzzL9/06Am8NXIkGV+/NqQ62Dx7DSqudxxpAgBqYn6V7+zp+0Y7JuWksKUbczRY3wMTd+7Uj6OA==", "dev": true, "requires": { - "@webpack-cli/info": "^1.1.0", - "@webpack-cli/serve": "^1.1.0", + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/info": "^1.2.1", + "@webpack-cli/serve": "^1.2.1", "colorette": "^1.2.1", - "command-line-usage": "^6.1.0", "commander": "^6.2.0", "enquirer": "^2.3.6", - "execa": "^4.1.0", + "execa": "^5.0.0", + "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", "interpret": "^2.2.0", - "leven": "^3.1.0", "rechoir": "^0.7.0", "v8-compile-cache": "^2.2.0", "webpack-merge": "^4.2.2" @@ -3193,22 +3120,6 @@ "isexe": "^2.0.0" } }, - "wordwrapjs": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.0.tgz", - "integrity": "sha512-Svqw723a3R34KvsMgpjFBYCgNOSdcW3mQFK4wIfhGQhtaFVOJmdYoXgi63ne3dTlWgatVcUc7t4HtQ/+bUVIzQ==", - "dev": true, - "requires": { - "reduce-flatten": "^2.0.0", - "typical": "^5.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, "ws": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.1.tgz", diff --git a/src/packages/utils/package.json b/src/packages/utils/package.json index 1f39f390b..776a30ad5 100644 --- a/src/packages/utils/package.json +++ b/src/packages/utils/package.json @@ -45,10 +45,10 @@ "babel-plugin-transform-class-properties": "6.24.1", "cross-env": "7.0.3", "file-loader": "6.2.0", - "ts-loader": "8.0.12", - "webpack": "5.11.0", + "ts-loader": "8.0.13", + "webpack": "5.11.1", "webpack-bundle-analyzer": "4.3.0", - "webpack-cli": "4.2.0" + "webpack-cli": "4.3.1" }, "bugs": "https://github.com/excalidraw/excalidraw/issues", "repository": "https://github.com/excalidraw/excalidraw", diff --git a/src/tests/__snapshots__/regressionTests.test.tsx.snap b/src/tests/__snapshots__/regressionTests.test.tsx.snap index c82bce844..dc78141e1 100644 --- a/src/tests/__snapshots__/regressionTests.test.tsx.snap +++ b/src/tests/__snapshots__/regressionTests.test.tsx.snap @@ -4,6 +4,7 @@ exports[`given element A and group of elements B and given both are selected whe Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -19,8 +20,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -44,6 +43,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id1": true, @@ -454,12 +457,13 @@ Object { exports[`given element A and group of elements B and given both are selected when user clicks on B, on pointer up only elements from B should be selected: [end of test] number of elements 1`] = `3`; -exports[`given element A and group of elements B and given both are selected when user clicks on B, on pointer up only elements from B should be selected: [end of test] number of renders 1`] = `24`; +exports[`given element A and group of elements B and given both are selected when user clicks on B, on pointer up only elements from B should be selected: [end of test] number of renders 1`] = `25`; exports[`given element A and group of elements B and given both are selected when user shift-clicks on B, on pointer up only element A should be selected: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -475,8 +479,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -500,6 +502,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id1": true, @@ -916,12 +922,13 @@ Object { exports[`given element A and group of elements B and given both are selected when user shift-clicks on B, on pointer up only element A should be selected: [end of test] number of elements 1`] = `3`; -exports[`given element A and group of elements B and given both are selected when user shift-clicks on B, on pointer up only element A should be selected: [end of test] number of renders 1`] = `20`; +exports[`given element A and group of elements B and given both are selected when user shift-clicks on B, on pointer up only element A should be selected: [end of test] number of renders 1`] = `21`; exports[`regression tests Cmd/Ctrl-click exclusively select element under pointer: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -937,8 +944,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": "id10", @@ -962,6 +967,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -1687,12 +1696,13 @@ Object { exports[`regression tests Cmd/Ctrl-click exclusively select element under pointer: [end of test] number of elements 1`] = `3`; -exports[`regression tests Cmd/Ctrl-click exclusively select element under pointer: [end of test] number of renders 1`] = `39`; +exports[`regression tests Cmd/Ctrl-click exclusively select element under pointer: [end of test] number of renders 1`] = `40`; exports[`regression tests Drags selected element when hitting only bounding box and keeps element selected: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -1708,8 +1718,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -1733,6 +1741,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, }, @@ -1886,12 +1898,13 @@ Object { exports[`regression tests Drags selected element when hitting only bounding box and keeps element selected: [end of test] number of elements 1`] = `1`; -exports[`regression tests Drags selected element when hitting only bounding box and keeps element selected: [end of test] number of renders 1`] = `8`; +exports[`regression tests Drags selected element when hitting only bounding box and keeps element selected: [end of test] number of renders 1`] = `9`; exports[`regression tests adjusts z order when grouping: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -1907,8 +1920,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -1932,6 +1943,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id3": true, @@ -2339,12 +2354,13 @@ Object { exports[`regression tests adjusts z order when grouping: [end of test] number of elements 1`] = `3`; -exports[`regression tests adjusts z order when grouping: [end of test] number of renders 1`] = `18`; +exports[`regression tests adjusts z order when grouping: [end of test] number of renders 1`] = `19`; exports[`regression tests alt-drag duplicates an element: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -2360,8 +2376,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -2385,6 +2399,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, }, @@ -2587,12 +2605,13 @@ Object { exports[`regression tests alt-drag duplicates an element: [end of test] number of elements 1`] = `2`; -exports[`regression tests alt-drag duplicates an element: [end of test] number of renders 1`] = `8`; +exports[`regression tests alt-drag duplicates an element: [end of test] number of renders 1`] = `9`; exports[`regression tests arrow keys: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -2608,8 +2627,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -2633,6 +2650,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -2746,12 +2767,13 @@ Object { exports[`regression tests arrow keys: [end of test] number of elements 1`] = `1`; -exports[`regression tests arrow keys: [end of test] number of renders 1`] = `17`; +exports[`regression tests arrow keys: [end of test] number of renders 1`] = `18`; exports[`regression tests can drag element that covers another element, while another elem is selected: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -2767,8 +2789,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -2792,6 +2812,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id2": true, }, @@ -3218,12 +3242,13 @@ Object { exports[`regression tests can drag element that covers another element, while another elem is selected: [end of test] number of elements 1`] = `3`; -exports[`regression tests can drag element that covers another element, while another elem is selected: [end of test] number of renders 1`] = `16`; +exports[`regression tests can drag element that covers another element, while another elem is selected: [end of test] number of renders 1`] = `17`; exports[`regression tests change the properties of a shape: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "#fa5252", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -3239,8 +3264,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -3264,6 +3287,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -3521,12 +3548,13 @@ Object { exports[`regression tests change the properties of a shape: [end of test] number of elements 1`] = `1`; -exports[`regression tests change the properties of a shape: [end of test] number of renders 1`] = `9`; +exports[`regression tests change the properties of a shape: [end of test] number of renders 1`] = `10`; exports[`regression tests click on an element and drag it: [dragged] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -3542,8 +3570,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -3567,6 +3593,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, }, @@ -3720,12 +3750,13 @@ Object { exports[`regression tests click on an element and drag it: [dragged] number of elements 1`] = `1`; -exports[`regression tests click on an element and drag it: [dragged] number of renders 1`] = `8`; +exports[`regression tests click on an element and drag it: [dragged] number of renders 1`] = `9`; exports[`regression tests click on an element and drag it: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -3741,8 +3772,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -3766,6 +3795,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id1": true, @@ -3959,12 +3992,13 @@ Object { exports[`regression tests click on an element and drag it: [end of test] number of elements 1`] = `1`; -exports[`regression tests click on an element and drag it: [end of test] number of renders 1`] = `11`; +exports[`regression tests click on an element and drag it: [end of test] number of renders 1`] = `12`; exports[`regression tests click to select a shape: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -3980,8 +4014,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -4005,6 +4037,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id1": true, }, @@ -4206,12 +4242,13 @@ Object { exports[`regression tests click to select a shape: [end of test] number of elements 1`] = `2`; -exports[`regression tests click to select a shape: [end of test] number of renders 1`] = `11`; +exports[`regression tests click to select a shape: [end of test] number of renders 1`] = `12`; exports[`regression tests click-drag to select a group: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -4227,8 +4264,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -4252,6 +4287,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id2": true, }, @@ -4562,12 +4601,13 @@ Object { exports[`regression tests click-drag to select a group: [end of test] number of elements 1`] = `3`; -exports[`regression tests click-drag to select a group: [end of test] number of renders 1`] = `17`; +exports[`regression tests click-drag to select a group: [end of test] number of renders 1`] = `18`; exports[`regression tests deselects group of selected elements on pointer down when pointer doesn't hit any element: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -4583,8 +4623,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "down", - "cursorX": 0, - "cursorY": 0, "draggingElement": Object { "angle": 0, "backgroundColor": "transparent", @@ -4630,6 +4668,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id1": true, @@ -4852,12 +4894,13 @@ Object { exports[`regression tests deselects group of selected elements on pointer down when pointer doesn't hit any element: [end of test] number of elements 1`] = `2`; -exports[`regression tests deselects group of selected elements on pointer down when pointer doesn't hit any element: [end of test] number of renders 1`] = `12`; +exports[`regression tests deselects group of selected elements on pointer down when pointer doesn't hit any element: [end of test] number of renders 1`] = `13`; exports[`regression tests deselects group of selected elements on pointer up when pointer hits common bounding box without hitting any element: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -4873,8 +4916,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": Object { "angle": 0, "backgroundColor": "transparent", @@ -4920,6 +4961,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id1": true, @@ -5154,12 +5199,13 @@ Object { exports[`regression tests deselects group of selected elements on pointer up when pointer hits common bounding box without hitting any element: [end of test] number of elements 1`] = `2`; -exports[`regression tests deselects group of selected elements on pointer up when pointer hits common bounding box without hitting any element: [end of test] number of renders 1`] = `13`; +exports[`regression tests deselects group of selected elements on pointer up when pointer hits common bounding box without hitting any element: [end of test] number of renders 1`] = `14`; exports[`regression tests deselects selected element on pointer down when pointer doesn't hit any element: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -5175,8 +5221,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "down", - "cursorX": 0, - "cursorY": 0, "draggingElement": Object { "angle": 0, "backgroundColor": "transparent", @@ -5222,6 +5266,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, }, @@ -5357,12 +5405,13 @@ Object { exports[`regression tests deselects selected element on pointer down when pointer doesn't hit any element: [end of test] number of elements 1`] = `1`; -exports[`regression tests deselects selected element on pointer down when pointer doesn't hit any element: [end of test] number of renders 1`] = `6`; +exports[`regression tests deselects selected element on pointer down when pointer doesn't hit any element: [end of test] number of renders 1`] = `7`; exports[`regression tests deselects selected element, on pointer up, when click hits element bounding box but doesn't hit the element: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -5378,8 +5427,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": Object { "angle": 0, "backgroundColor": "transparent", @@ -5425,6 +5472,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, }, @@ -5538,12 +5589,13 @@ Object { exports[`regression tests deselects selected element, on pointer up, when click hits element bounding box but doesn't hit the element: [end of test] number of elements 1`] = `1`; -exports[`regression tests deselects selected element, on pointer up, when click hits element bounding box but doesn't hit the element: [end of test] number of renders 1`] = `7`; +exports[`regression tests deselects selected element, on pointer up, when click hits element bounding box but doesn't hit the element: [end of test] number of renders 1`] = `8`; exports[`regression tests double click to edit a group: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -5559,8 +5611,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": "id3", @@ -5584,6 +5634,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -5986,12 +6040,13 @@ Object { exports[`regression tests double click to edit a group: [end of test] number of elements 1`] = `3`; -exports[`regression tests double click to edit a group: [end of test] number of renders 1`] = `16`; +exports[`regression tests double click to edit a group: [end of test] number of renders 1`] = `17`; exports[`regression tests drags selected elements from point inside common bounding box that doesn't hit any element and keeps elements selected after dragging: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -6007,8 +6062,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -6032,6 +6085,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id1": true, @@ -6299,12 +6356,13 @@ Object { exports[`regression tests drags selected elements from point inside common bounding box that doesn't hit any element and keeps elements selected after dragging: [end of test] number of elements 1`] = `2`; -exports[`regression tests drags selected elements from point inside common bounding box that doesn't hit any element and keeps elements selected after dragging: [end of test] number of renders 1`] = `14`; +exports[`regression tests drags selected elements from point inside common bounding box that doesn't hit any element and keeps elements selected after dragging: [end of test] number of renders 1`] = `15`; exports[`regression tests draw every type of shape: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -6320,14 +6378,12 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "down", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, "editingLinearElement": null, "elementLocked": false, - "elementType": "selection", + "elementType": "draw", "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, @@ -6345,13 +6401,17 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, "scrollY": 0, "scrolledOutside": false, "selectedElementIds": Object { - "id7": true, + "id7": false, }, "selectedGroupIds": Object {}, "selectionElement": null, @@ -8042,7 +8102,7 @@ Object { "editingLinearElement": null, "name": "Untitled-201933152653", "selectedElementIds": Object { - "id7": true, + "id7": false, }, "viewBackgroundColor": "#ffffff", }, @@ -8328,12 +8388,13 @@ Object { exports[`regression tests draw every type of shape: [end of test] number of elements 1`] = `8`; -exports[`regression tests draw every type of shape: [end of test] number of renders 1`] = `49`; +exports[`regression tests draw every type of shape: [end of test] number of renders 1`] = `50`; exports[`regression tests given a group of selected elements with an element that is not selected inside the group common bounding box when element that is not selected is clicked should switch selection to not selected element on pointer up: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -8349,8 +8410,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -8374,6 +8433,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id2": true, @@ -8685,12 +8748,13 @@ Object { exports[`regression tests given a group of selected elements with an element that is not selected inside the group common bounding box when element that is not selected is clicked should switch selection to not selected element on pointer up: [end of test] number of elements 1`] = `3`; -exports[`regression tests given a group of selected elements with an element that is not selected inside the group common bounding box when element that is not selected is clicked should switch selection to not selected element on pointer up: [end of test] number of renders 1`] = `17`; +exports[`regression tests given a group of selected elements with an element that is not selected inside the group common bounding box when element that is not selected is clicked should switch selection to not selected element on pointer up: [end of test] number of renders 1`] = `18`; exports[`regression tests given a selected element A and a not selected element B with higher z-index than A and given B partialy overlaps A when there's a shift-click on the overlapped section B is added to the selection: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "#fa5252", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -8706,8 +8770,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -8731,6 +8793,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id2": true, @@ -8935,12 +9001,13 @@ Object { exports[`regression tests given a selected element A and a not selected element B with higher z-index than A and given B partialy overlaps A when there's a shift-click on the overlapped section B is added to the selection: [end of test] number of elements 1`] = `2`; -exports[`regression tests given a selected element A and a not selected element B with higher z-index than A and given B partialy overlaps A when there's a shift-click on the overlapped section B is added to the selection: [end of test] number of renders 1`] = `15`; +exports[`regression tests given a selected element A and a not selected element B with higher z-index than A and given B partialy overlaps A when there's a shift-click on the overlapped section B is added to the selection: [end of test] number of renders 1`] = `16`; exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when clicking intersection between A and B B should be selected on pointer up: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "#fa5252", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -8956,8 +9023,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -8981,6 +9046,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id2": true, @@ -9183,12 +9252,13 @@ Object { exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when clicking intersection between A and B B should be selected on pointer up: [end of test] number of elements 1`] = `2`; -exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when clicking intersection between A and B B should be selected on pointer up: [end of test] number of renders 1`] = `15`; +exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when clicking intersection between A and B B should be selected on pointer up: [end of test] number of renders 1`] = `16`; exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when dragging on intersection between A and B A should be dragged and keep being selected: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "#fa5252", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -9204,8 +9274,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -9229,6 +9297,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id2": true, @@ -9493,12 +9565,13 @@ Object { exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when dragging on intersection between A and B A should be dragged and keep being selected: [end of test] number of elements 1`] = `2`; -exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when dragging on intersection between A and B A should be dragged and keep being selected: [end of test] number of renders 1`] = `16`; +exports[`regression tests given selected element A with lower z-index than unselected element B and given B is partially over A when dragging on intersection between A and B A should be dragged and keep being selected: [end of test] number of renders 1`] = `17`; exports[`regression tests key 2 selects rectangle tool: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -9514,8 +9587,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -9539,6 +9610,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -9652,12 +9727,13 @@ Object { exports[`regression tests key 2 selects rectangle tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key 2 selects rectangle tool: [end of test] number of renders 1`] = `5`; +exports[`regression tests key 2 selects rectangle tool: [end of test] number of renders 1`] = `6`; exports[`regression tests key 3 selects diamond tool: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -9673,8 +9749,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -9698,6 +9772,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -9811,12 +9889,13 @@ Object { exports[`regression tests key 3 selects diamond tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key 3 selects diamond tool: [end of test] number of renders 1`] = `5`; +exports[`regression tests key 3 selects diamond tool: [end of test] number of renders 1`] = `6`; exports[`regression tests key 4 selects ellipse tool: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -9832,8 +9911,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -9857,6 +9934,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -9970,12 +10051,13 @@ Object { exports[`regression tests key 4 selects ellipse tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key 4 selects ellipse tool: [end of test] number of renders 1`] = `5`; +exports[`regression tests key 4 selects ellipse tool: [end of test] number of renders 1`] = `6`; exports[`regression tests key 5 selects arrow tool: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -9991,8 +10073,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -10016,6 +10096,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -10159,12 +10243,13 @@ Object { exports[`regression tests key 5 selects arrow tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key 5 selects arrow tool: [end of test] number of renders 1`] = `6`; +exports[`regression tests key 5 selects arrow tool: [end of test] number of renders 1`] = `7`; exports[`regression tests key 6 selects line tool: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -10180,8 +10265,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -10205,6 +10288,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -10348,12 +10435,13 @@ Object { exports[`regression tests key 6 selects line tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key 6 selects line tool: [end of test] number of renders 1`] = `5`; +exports[`regression tests key 6 selects line tool: [end of test] number of renders 1`] = `6`; exports[`regression tests key 7 selects draw tool: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -10369,14 +10457,12 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "down", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, "editingLinearElement": null, "elementLocked": false, - "elementType": "selection", + "elementType": "draw", "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, @@ -10394,13 +10480,17 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, "scrollY": 0, "scrolledOutside": false, "selectedElementIds": Object { - "id0": true, + "id0": false, }, "selectedGroupIds": Object {}, "selectionElement": null, @@ -10486,7 +10576,7 @@ Object { "editingLinearElement": null, "name": "Untitled-201933152653", "selectedElementIds": Object { - "id0": true, + "id0": false, }, "viewBackgroundColor": "#ffffff", }, @@ -10537,12 +10627,13 @@ Object { exports[`regression tests key 7 selects draw tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key 7 selects draw tool: [end of test] number of renders 1`] = `5`; +exports[`regression tests key 7 selects draw tool: [end of test] number of renders 1`] = `6`; exports[`regression tests key a selects arrow tool: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -10558,8 +10649,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -10583,6 +10672,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -10726,12 +10819,13 @@ Object { exports[`regression tests key a selects arrow tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key a selects arrow tool: [end of test] number of renders 1`] = `6`; +exports[`regression tests key a selects arrow tool: [end of test] number of renders 1`] = `7`; exports[`regression tests key d selects diamond tool: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -10747,8 +10841,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -10772,6 +10864,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -10885,12 +10981,13 @@ Object { exports[`regression tests key d selects diamond tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key d selects diamond tool: [end of test] number of renders 1`] = `5`; +exports[`regression tests key d selects diamond tool: [end of test] number of renders 1`] = `6`; exports[`regression tests key e selects ellipse tool: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -10906,8 +11003,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -10931,6 +11026,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -11044,12 +11143,13 @@ Object { exports[`regression tests key e selects ellipse tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key e selects ellipse tool: [end of test] number of renders 1`] = `5`; +exports[`regression tests key e selects ellipse tool: [end of test] number of renders 1`] = `6`; exports[`regression tests key l selects line tool: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -11065,8 +11165,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -11090,6 +11188,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -11233,12 +11335,13 @@ Object { exports[`regression tests key l selects line tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key l selects line tool: [end of test] number of renders 1`] = `5`; +exports[`regression tests key l selects line tool: [end of test] number of renders 1`] = `6`; exports[`regression tests key r selects rectangle tool: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -11254,8 +11357,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -11279,6 +11380,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -11392,12 +11497,13 @@ Object { exports[`regression tests key r selects rectangle tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key r selects rectangle tool: [end of test] number of renders 1`] = `5`; +exports[`regression tests key r selects rectangle tool: [end of test] number of renders 1`] = `6`; exports[`regression tests key x selects draw tool: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -11413,14 +11519,12 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "down", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, "editingLinearElement": null, "elementLocked": false, - "elementType": "selection", + "elementType": "draw", "errorMessage": null, "exportBackground": true, "exportEmbedScene": false, @@ -11438,13 +11542,17 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, "scrollY": 0, "scrolledOutside": false, "selectedElementIds": Object { - "id0": true, + "id0": false, }, "selectedGroupIds": Object {}, "selectionElement": null, @@ -11530,7 +11638,7 @@ Object { "editingLinearElement": null, "name": "Untitled-201933152653", "selectedElementIds": Object { - "id0": true, + "id0": false, }, "viewBackgroundColor": "#ffffff", }, @@ -11581,12 +11689,13 @@ Object { exports[`regression tests key x selects draw tool: [end of test] number of elements 1`] = `1`; -exports[`regression tests key x selects draw tool: [end of test] number of renders 1`] = `5`; +exports[`regression tests key x selects draw tool: [end of test] number of renders 1`] = `6`; exports[`regression tests make a group and duplicate it: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -11602,8 +11711,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -11627,6 +11734,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id1": true, @@ -12292,12 +12403,13 @@ Object { exports[`regression tests make a group and duplicate it: [end of test] number of elements 1`] = `6`; -exports[`regression tests make a group and duplicate it: [end of test] number of renders 1`] = `20`; +exports[`regression tests make a group and duplicate it: [end of test] number of renders 1`] = `21`; exports[`regression tests noop interaction after undo shouldn't create history entry: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -12313,8 +12425,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -12338,6 +12448,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id3": true, @@ -12540,12 +12654,13 @@ Object { exports[`regression tests noop interaction after undo shouldn't create history entry: [end of test] number of elements 1`] = `2`; -exports[`regression tests noop interaction after undo shouldn't create history entry: [end of test] number of renders 1`] = `17`; +exports[`regression tests noop interaction after undo shouldn't create history entry: [end of test] number of renders 1`] = `18`; exports[`regression tests pinch-to-zoom works: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -12561,8 +12676,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "down", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -12586,6 +12699,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": -6, @@ -12637,12 +12754,13 @@ Object { exports[`regression tests pinch-to-zoom works: [end of test] number of elements 1`] = `0`; -exports[`regression tests pinch-to-zoom works: [end of test] number of renders 1`] = `7`; +exports[`regression tests pinch-to-zoom works: [end of test] number of renders 1`] = `8`; exports[`regression tests rerenders UI on language change: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -12658,8 +12776,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -12683,6 +12799,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -12732,12 +12852,13 @@ Object { exports[`regression tests rerenders UI on language change: [end of test] number of elements 1`] = `0`; -exports[`regression tests rerenders UI on language change: [end of test] number of renders 1`] = `4`; +exports[`regression tests rerenders UI on language change: [end of test] number of renders 1`] = `7`; exports[`regression tests selecting 'Add to library' in context menu adds element to library: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -12753,8 +12874,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -12778,6 +12897,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -12891,12 +13014,13 @@ Object { exports[`regression tests selecting 'Add to library' in context menu adds element to library: [end of test] number of elements 1`] = `1`; -exports[`regression tests selecting 'Add to library' in context menu adds element to library: [end of test] number of renders 1`] = `5`; +exports[`regression tests selecting 'Add to library' in context menu adds element to library: [end of test] number of renders 1`] = `6`; exports[`regression tests selecting 'Bring forward' in context menu brings element forward: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -12912,8 +13036,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -12937,6 +13059,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -13194,12 +13320,13 @@ Object { exports[`regression tests selecting 'Bring forward' in context menu brings element forward: [end of test] number of elements 1`] = `2`; -exports[`regression tests selecting 'Bring forward' in context menu brings element forward: [end of test] number of renders 1`] = `11`; +exports[`regression tests selecting 'Bring forward' in context menu brings element forward: [end of test] number of renders 1`] = `12`; exports[`regression tests selecting 'Bring to front' in context menu brings element to front: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -13215,8 +13342,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -13240,6 +13365,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -13497,12 +13626,13 @@ Object { exports[`regression tests selecting 'Bring to front' in context menu brings element to front: [end of test] number of elements 1`] = `2`; -exports[`regression tests selecting 'Bring to front' in context menu brings element to front: [end of test] number of renders 1`] = `11`; +exports[`regression tests selecting 'Bring to front' in context menu brings element to front: [end of test] number of renders 1`] = `12`; exports[`regression tests selecting 'Copy styles' in context menu copies styles: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -13518,8 +13648,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -13543,6 +13671,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -13656,12 +13788,13 @@ Object { exports[`regression tests selecting 'Copy styles' in context menu copies styles: [end of test] number of elements 1`] = `1`; -exports[`regression tests selecting 'Copy styles' in context menu copies styles: [end of test] number of renders 1`] = `5`; +exports[`regression tests selecting 'Copy styles' in context menu copies styles: [end of test] number of renders 1`] = `6`; exports[`regression tests selecting 'Delete' in context menu deletes element: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -13677,8 +13810,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -13702,6 +13833,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -13847,12 +13982,13 @@ Object { exports[`regression tests selecting 'Delete' in context menu deletes element: [end of test] number of elements 1`] = `1`; -exports[`regression tests selecting 'Delete' in context menu deletes element: [end of test] number of renders 1`] = `6`; +exports[`regression tests selecting 'Delete' in context menu deletes element: [end of test] number of renders 1`] = `7`; exports[`regression tests selecting 'Duplicate' in context menu duplicates element: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -13868,8 +14004,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -13893,6 +14027,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -14091,12 +14229,13 @@ Object { exports[`regression tests selecting 'Duplicate' in context menu duplicates element: [end of test] number of elements 1`] = `2`; -exports[`regression tests selecting 'Duplicate' in context menu duplicates element: [end of test] number of renders 1`] = `6`; +exports[`regression tests selecting 'Duplicate' in context menu duplicates element: [end of test] number of renders 1`] = `7`; exports[`regression tests selecting 'Group selection' in context menu groups selected elements: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -14112,8 +14251,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -14137,6 +14274,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id1": true, }, @@ -14410,12 +14551,13 @@ Object { exports[`regression tests selecting 'Group selection' in context menu groups selected elements: [end of test] number of elements 1`] = `2`; -exports[`regression tests selecting 'Group selection' in context menu groups selected elements: [end of test] number of renders 1`] = `12`; +exports[`regression tests selecting 'Group selection' in context menu groups selected elements: [end of test] number of renders 1`] = `13`; exports[`regression tests selecting 'Paste styles' in context menu pastes styles: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "#e64980", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "cross-hatch", @@ -14431,8 +14573,6 @@ Object { "currentItemStrokeWidth": 2, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -14456,6 +14596,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -15244,12 +15388,13 @@ Object { exports[`regression tests selecting 'Paste styles' in context menu pastes styles: [end of test] number of elements 1`] = `2`; -exports[`regression tests selecting 'Paste styles' in context menu pastes styles: [end of test] number of renders 1`] = `20`; +exports[`regression tests selecting 'Paste styles' in context menu pastes styles: [end of test] number of renders 1`] = `21`; exports[`regression tests selecting 'Send backward' in context menu sends element backward: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -15265,8 +15410,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -15290,6 +15433,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -15547,12 +15694,13 @@ Object { exports[`regression tests selecting 'Send backward' in context menu sends element backward: [end of test] number of elements 1`] = `2`; -exports[`regression tests selecting 'Send backward' in context menu sends element backward: [end of test] number of renders 1`] = `10`; +exports[`regression tests selecting 'Send backward' in context menu sends element backward: [end of test] number of renders 1`] = `11`; exports[`regression tests selecting 'Send to back' in context menu sends element to back: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -15568,8 +15716,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -15593,6 +15739,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -15850,12 +16000,13 @@ Object { exports[`regression tests selecting 'Send to back' in context menu sends element to back: [end of test] number of elements 1`] = `2`; -exports[`regression tests selecting 'Send to back' in context menu sends element to back: [end of test] number of renders 1`] = `10`; +exports[`regression tests selecting 'Send to back' in context menu sends element to back: [end of test] number of renders 1`] = `11`; exports[`regression tests selecting 'Ungroup selection' in context menu ungroups selected group: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -15871,8 +16022,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -15896,6 +16045,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id1": true, }, @@ -16224,12 +16377,13 @@ Object { exports[`regression tests selecting 'Ungroup selection' in context menu ungroups selected group: [end of test] number of elements 1`] = `2`; -exports[`regression tests selecting 'Ungroup selection' in context menu ungroups selected group: [end of test] number of renders 1`] = `13`; +exports[`regression tests selecting 'Ungroup selection' in context menu ungroups selected group: [end of test] number of renders 1`] = `14`; exports[`regression tests shift click on selected element should deselect it on pointer up: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -16245,8 +16399,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -16270,6 +16422,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, }, @@ -16386,12 +16542,13 @@ Object { exports[`regression tests shift click on selected element should deselect it on pointer up: [end of test] number of elements 1`] = `1`; -exports[`regression tests shift click on selected element should deselect it on pointer up: [end of test] number of renders 1`] = `7`; +exports[`regression tests shift click on selected element should deselect it on pointer up: [end of test] number of renders 1`] = `8`; exports[`regression tests shift-click to multiselect, then drag: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -16407,8 +16564,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -16432,6 +16587,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id1": true, @@ -16702,12 +16861,13 @@ Object { exports[`regression tests shift-click to multiselect, then drag: [end of test] number of elements 1`] = `2`; -exports[`regression tests shift-click to multiselect, then drag: [end of test] number of renders 1`] = `16`; +exports[`regression tests shift-click to multiselect, then drag: [end of test] number of renders 1`] = `17`; exports[`regression tests should show fill icons when element has non transparent background: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "#fa5252", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -16723,8 +16883,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -16748,6 +16906,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, }, @@ -16936,12 +17098,13 @@ Object { exports[`regression tests should show fill icons when element has non transparent background: [end of test] number of elements 1`] = `1`; -exports[`regression tests should show fill icons when element has non transparent background: [end of test] number of renders 1`] = `9`; +exports[`regression tests should show fill icons when element has non transparent background: [end of test] number of renders 1`] = `10`; exports[`regression tests shows 'Group selection' in context menu for multiple selected elements: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -16957,8 +17120,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -16982,6 +17143,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id2": true, @@ -17186,12 +17351,13 @@ Object { exports[`regression tests shows 'Group selection' in context menu for multiple selected elements: [end of test] number of elements 1`] = `2`; -exports[`regression tests shows 'Group selection' in context menu for multiple selected elements: [end of test] number of renders 1`] = `13`; +exports[`regression tests shows 'Group selection' in context menu for multiple selected elements: [end of test] number of renders 1`] = `14`; exports[`regression tests shows 'Ungroup selection' in context menu for group inside selected elements: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -17207,8 +17373,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -17232,6 +17396,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id2": true, @@ -17508,12 +17676,13 @@ Object { exports[`regression tests shows 'Ungroup selection' in context menu for group inside selected elements: [end of test] number of elements 1`] = `2`; -exports[`regression tests shows 'Ungroup selection' in context menu for group inside selected elements: [end of test] number of renders 1`] = `14`; +exports[`regression tests shows 'Ungroup selection' in context menu for group inside selected elements: [end of test] number of renders 1`] = `15`; exports[`regression tests shows context menu for canvas: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -17529,8 +17698,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -17554,6 +17721,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -17603,12 +17774,13 @@ Object { exports[`regression tests shows context menu for canvas: [end of test] number of elements 1`] = `0`; -exports[`regression tests shows context menu for canvas: [end of test] number of renders 1`] = `1`; +exports[`regression tests shows context menu for canvas: [end of test] number of renders 1`] = `2`; exports[`regression tests shows context menu for element: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -17624,8 +17796,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -17649,6 +17819,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -17762,12 +17936,13 @@ Object { exports[`regression tests shows context menu for element: [end of test] number of elements 1`] = `1`; -exports[`regression tests shows context menu for element: [end of test] number of renders 1`] = `5`; +exports[`regression tests shows context menu for element: [end of test] number of renders 1`] = `6`; exports[`regression tests single-clicking on a subgroup of a selected group should not alter selection: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -17783,8 +17958,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -17808,6 +17981,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id0": true, "id1": true, @@ -18578,12 +18755,13 @@ Object { exports[`regression tests single-clicking on a subgroup of a selected group should not alter selection: [end of test] number of elements 1`] = `4`; -exports[`regression tests single-clicking on a subgroup of a selected group should not alter selection: [end of test] number of renders 1`] = `35`; +exports[`regression tests single-clicking on a subgroup of a selected group should not alter selection: [end of test] number of renders 1`] = `36`; exports[`regression tests spacebar + drag scrolls the canvas: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -18599,8 +18777,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -18624,6 +18800,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 60, @@ -18673,12 +18853,13 @@ Object { exports[`regression tests spacebar + drag scrolls the canvas: [end of test] number of elements 1`] = `0`; -exports[`regression tests spacebar + drag scrolls the canvas: [end of test] number of renders 1`] = `4`; +exports[`regression tests spacebar + drag scrolls the canvas: [end of test] number of renders 1`] = `5`; exports[`regression tests supports nested groups: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -18694,8 +18875,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": "id3", @@ -18719,7 +18898,13 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, - "previousSelectedElementIds": Object {}, + "pasteDialog": Object { + "data": null, + "shown": false, + }, + "previousSelectedElementIds": Object { + "id0": true, + }, "resizingElement": null, "scrollX": 0, "scrollY": 0, @@ -18758,7 +18943,7 @@ Object { "groupIds": Array [ "id3", ], - "height": 10, + "height": 50, "id": "id1", "isDeleted": false, "opacity": 100, @@ -18771,9 +18956,9 @@ Object { "type": "rectangle", "version": 3, "versionNonce": 1116226695, - "width": 10, - "x": 30, - "y": 10, + "width": 50, + "x": 100, + "y": 100, } `; @@ -18787,7 +18972,7 @@ Object { "id5", "id3", ], - "height": 10, + "height": 50, "id": "id0", "isDeleted": false, "opacity": 100, @@ -18800,9 +18985,9 @@ Object { "type": "rectangle", "version": 4, "versionNonce": 400692809, - "width": 10, - "x": 10, - "y": 10, + "width": 50, + "x": 0, + "y": 0, } `; @@ -18816,7 +19001,7 @@ Object { "id5", "id3", ], - "height": 10, + "height": 50, "id": "id2", "isDeleted": false, "opacity": 100, @@ -18829,9 +19014,9 @@ Object { "type": "rectangle", "version": 4, "versionNonce": 1604849351, - "width": 10, - "x": 50, - "y": 10, + "width": 50, + "x": 200, + "y": 200, } `; @@ -18867,7 +19052,7 @@ Object { "boundElementIds": null, "fillStyle": "hachure", "groupIds": Array [], - "height": 10, + "height": 50, "id": "id0", "isDeleted": false, "opacity": 100, @@ -18880,9 +19065,9 @@ Object { "type": "rectangle", "version": 2, "versionNonce": 1278240551, - "width": 10, - "x": 10, - "y": 10, + "width": 50, + "x": 0, + "y": 0, }, ], }, @@ -18903,7 +19088,7 @@ Object { "boundElementIds": null, "fillStyle": "hachure", "groupIds": Array [], - "height": 10, + "height": 50, "id": "id0", "isDeleted": false, "opacity": 100, @@ -18916,9 +19101,9 @@ Object { "type": "rectangle", "version": 2, "versionNonce": 1278240551, - "width": 10, - "x": 10, - "y": 10, + "width": 50, + "x": 0, + "y": 0, }, Object { "angle": 0, @@ -18926,7 +19111,7 @@ Object { "boundElementIds": null, "fillStyle": "hachure", "groupIds": Array [], - "height": 10, + "height": 50, "id": "id1", "isDeleted": false, "opacity": 100, @@ -18939,9 +19124,9 @@ Object { "type": "rectangle", "version": 2, "versionNonce": 453191, - "width": 10, - "x": 30, - "y": 10, + "width": 50, + "x": 100, + "y": 100, }, ], }, @@ -18962,7 +19147,7 @@ Object { "boundElementIds": null, "fillStyle": "hachure", "groupIds": Array [], - "height": 10, + "height": 50, "id": "id0", "isDeleted": false, "opacity": 100, @@ -18975,9 +19160,9 @@ Object { "type": "rectangle", "version": 2, "versionNonce": 1278240551, - "width": 10, - "x": 10, - "y": 10, + "width": 50, + "x": 0, + "y": 0, }, Object { "angle": 0, @@ -18985,7 +19170,7 @@ Object { "boundElementIds": null, "fillStyle": "hachure", "groupIds": Array [], - "height": 10, + "height": 50, "id": "id1", "isDeleted": false, "opacity": 100, @@ -18998,9 +19183,9 @@ Object { "type": "rectangle", "version": 2, "versionNonce": 453191, - "width": 10, - "x": 30, - "y": 10, + "width": 50, + "x": 100, + "y": 100, }, Object { "angle": 0, @@ -19008,7 +19193,7 @@ Object { "boundElementIds": null, "fillStyle": "hachure", "groupIds": Array [], - "height": 10, + "height": 50, "id": "id2", "isDeleted": false, "opacity": 100, @@ -19021,9 +19206,9 @@ Object { "type": "rectangle", "version": 2, "versionNonce": 2019559783, - "width": 10, - "x": 50, - "y": 10, + "width": 50, + "x": 200, + "y": 200, }, ], }, @@ -19048,7 +19233,7 @@ Object { "groupIds": Array [ "id3", ], - "height": 10, + "height": 50, "id": "id0", "isDeleted": false, "opacity": 100, @@ -19061,9 +19246,9 @@ Object { "type": "rectangle", "version": 3, "versionNonce": 1150084233, - "width": 10, - "x": 10, - "y": 10, + "width": 50, + "x": 0, + "y": 0, }, Object { "angle": 0, @@ -19073,7 +19258,7 @@ Object { "groupIds": Array [ "id3", ], - "height": 10, + "height": 50, "id": "id1", "isDeleted": false, "opacity": 100, @@ -19086,9 +19271,9 @@ Object { "type": "rectangle", "version": 3, "versionNonce": 1116226695, - "width": 10, - "x": 30, - "y": 10, + "width": 50, + "x": 100, + "y": 100, }, Object { "angle": 0, @@ -19098,7 +19283,7 @@ Object { "groupIds": Array [ "id3", ], - "height": 10, + "height": 50, "id": "id2", "isDeleted": false, "opacity": 100, @@ -19111,9 +19296,9 @@ Object { "type": "rectangle", "version": 3, "versionNonce": 1014066025, - "width": 10, - "x": 50, - "y": 10, + "width": 50, + "x": 200, + "y": 200, }, ], }, @@ -19138,7 +19323,7 @@ Object { "groupIds": Array [ "id3", ], - "height": 10, + "height": 50, "id": "id0", "isDeleted": false, "opacity": 100, @@ -19151,9 +19336,9 @@ Object { "type": "rectangle", "version": 3, "versionNonce": 1150084233, - "width": 10, - "x": 10, - "y": 10, + "width": 50, + "x": 0, + "y": 0, }, Object { "angle": 0, @@ -19163,7 +19348,7 @@ Object { "groupIds": Array [ "id3", ], - "height": 10, + "height": 50, "id": "id1", "isDeleted": false, "opacity": 100, @@ -19176,9 +19361,9 @@ Object { "type": "rectangle", "version": 3, "versionNonce": 1116226695, - "width": 10, - "x": 30, - "y": 10, + "width": 50, + "x": 100, + "y": 100, }, Object { "angle": 0, @@ -19188,7 +19373,7 @@ Object { "groupIds": Array [ "id3", ], - "height": 10, + "height": 50, "id": "id2", "isDeleted": false, "opacity": 100, @@ -19201,9 +19386,9 @@ Object { "type": "rectangle", "version": 3, "versionNonce": 1014066025, - "width": 10, - "x": 50, - "y": 10, + "width": 50, + "x": 200, + "y": 200, }, ], }, @@ -19228,7 +19413,7 @@ Object { "groupIds": Array [ "id3", ], - "height": 10, + "height": 50, "id": "id1", "isDeleted": false, "opacity": 100, @@ -19241,9 +19426,9 @@ Object { "type": "rectangle", "version": 3, "versionNonce": 1116226695, - "width": 10, - "x": 30, - "y": 10, + "width": 50, + "x": 100, + "y": 100, }, Object { "angle": 0, @@ -19254,7 +19439,7 @@ Object { "id5", "id3", ], - "height": 10, + "height": 50, "id": "id0", "isDeleted": false, "opacity": 100, @@ -19267,9 +19452,9 @@ Object { "type": "rectangle", "version": 4, "versionNonce": 400692809, - "width": 10, - "x": 10, - "y": 10, + "width": 50, + "x": 0, + "y": 0, }, Object { "angle": 0, @@ -19280,7 +19465,7 @@ Object { "id5", "id3", ], - "height": 10, + "height": 50, "id": "id2", "isDeleted": false, "opacity": 100, @@ -19293,9 +19478,9 @@ Object { "type": "rectangle", "version": 4, "versionNonce": 1604849351, - "width": 10, - "x": 50, - "y": 10, + "width": 50, + "x": 200, + "y": 200, }, ], }, @@ -19321,7 +19506,7 @@ Object { "groupIds": Array [ "id3", ], - "height": 10, + "height": 50, "id": "id1", "isDeleted": false, "opacity": 100, @@ -19334,9 +19519,9 @@ Object { "type": "rectangle", "version": 3, "versionNonce": 1116226695, - "width": 10, - "x": 30, - "y": 10, + "width": 50, + "x": 100, + "y": 100, }, Object { "angle": 0, @@ -19347,7 +19532,7 @@ Object { "id5", "id3", ], - "height": 10, + "height": 50, "id": "id0", "isDeleted": false, "opacity": 100, @@ -19360,9 +19545,9 @@ Object { "type": "rectangle", "version": 4, "versionNonce": 400692809, - "width": 10, - "x": 10, - "y": 10, + "width": 50, + "x": 0, + "y": 0, }, Object { "angle": 0, @@ -19373,7 +19558,7 @@ Object { "id5", "id3", ], - "height": 10, + "height": 50, "id": "id2", "isDeleted": false, "opacity": 100, @@ -19386,9 +19571,9 @@ Object { "type": "rectangle", "version": 4, "versionNonce": 1604849351, - "width": 10, - "x": 50, - "y": 10, + "width": 50, + "x": 200, + "y": 200, }, ], }, @@ -19404,6 +19589,7 @@ exports[`regression tests switches from group of selected elements to another el Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -19419,8 +19605,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "down", - "cursorX": 0, - "cursorY": 0, "draggingElement": Object { "angle": 0, "backgroundColor": "transparent", @@ -19466,6 +19650,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id1": true, "id2": true, @@ -19798,12 +19986,13 @@ Object { exports[`regression tests switches from group of selected elements to another element on pointer down: [end of test] number of elements 1`] = `3`; -exports[`regression tests switches from group of selected elements to another element on pointer down: [end of test] number of renders 1`] = `16`; +exports[`regression tests switches from group of selected elements to another element on pointer down: [end of test] number of renders 1`] = `17`; exports[`regression tests switches selected element on pointer down: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -19819,8 +20008,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "down", - "cursorX": 0, - "cursorY": 0, "draggingElement": Object { "angle": 0, "backgroundColor": "transparent", @@ -19866,6 +20053,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object { "id1": true, }, @@ -20088,12 +20279,13 @@ Object { exports[`regression tests switches selected element on pointer down: [end of test] number of elements 1`] = `2`; -exports[`regression tests switches selected element on pointer down: [end of test] number of renders 1`] = `10`; +exports[`regression tests switches selected element on pointer down: [end of test] number of renders 1`] = `11`; exports[`regression tests two-finger scroll works: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -20109,8 +20301,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "down", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -20134,6 +20324,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 11, @@ -20185,12 +20379,13 @@ Object { exports[`regression tests two-finger scroll works: [end of test] number of elements 1`] = `0`; -exports[`regression tests two-finger scroll works: [end of test] number of renders 1`] = `9`; +exports[`regression tests two-finger scroll works: [end of test] number of renders 1`] = `10`; exports[`regression tests undo/redo drawing an element: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -20206,8 +20401,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -20231,6 +20424,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -20678,12 +20875,13 @@ Object { exports[`regression tests undo/redo drawing an element: [end of test] number of elements 1`] = `3`; -exports[`regression tests undo/redo drawing an element: [end of test] number of renders 1`] = `26`; +exports[`regression tests undo/redo drawing an element: [end of test] number of renders 1`] = `27`; exports[`regression tests updates fontSize & fontFamily appState: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -20699,8 +20897,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -20724,6 +20920,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -20773,12 +20973,13 @@ Object { exports[`regression tests updates fontSize & fontFamily appState: [end of test] number of elements 1`] = `0`; -exports[`regression tests updates fontSize & fontFamily appState: [end of test] number of renders 1`] = `3`; +exports[`regression tests updates fontSize & fontFamily appState: [end of test] number of renders 1`] = `4`; exports[`regression tests zoom hotkeys: [end of test] appState 1`] = ` Object { "appearance": "light", "collaborators": Map {}, + "currentChartType": "bar", "currentItemBackgroundColor": "transparent", "currentItemEndArrowhead": "arrow", "currentItemFillStyle": "hachure", @@ -20794,8 +20995,6 @@ Object { "currentItemStrokeWidth": 1, "currentItemTextAlign": "left", "cursorButton": "up", - "cursorX": 0, - "cursorY": 0, "draggingElement": null, "editingElement": null, "editingGroupId": null, @@ -20819,6 +21018,10 @@ Object { "offsetLeft": 0, "offsetTop": 0, "openMenu": null, + "pasteDialog": Object { + "data": null, + "shown": false, + }, "previousSelectedElementIds": Object {}, "resizingElement": null, "scrollX": 0, @@ -20868,4 +21071,4 @@ Object { exports[`regression tests zoom hotkeys: [end of test] number of elements 1`] = `0`; -exports[`regression tests zoom hotkeys: [end of test] number of renders 1`] = `3`; +exports[`regression tests zoom hotkeys: [end of test] number of renders 1`] = `4`; diff --git a/src/tests/align.test.tsx b/src/tests/align.test.tsx index 27ab4cd84..a16ac3027 100644 --- a/src/tests/align.test.tsx +++ b/src/tests/align.test.tsx @@ -2,7 +2,7 @@ import React from "react"; import ReactDOM from "react-dom"; import { render } from "./test-utils"; import ExcalidrawApp from "../excalidraw-app"; -import { setLanguage } from "../i18n"; +import { defaultLang, setLanguage } from "../i18n"; import { UI, Pointer, Keyboard } from "./helpers/ui"; import { API } from "./helpers/api"; import { KEYS } from "../keys"; @@ -60,7 +60,7 @@ describe("aligning", () => { ReactDOM.unmountComponentAtNode(document.getElementById("root")!); mouse.reset(); - await setLanguage("en.json"); + await setLanguage(defaultLang); await render(); }); diff --git a/src/tests/fixtures/smiley.png b/src/tests/fixtures/smiley.png index e59d1b26e..7a4054320 100644 Binary files a/src/tests/fixtures/smiley.png and b/src/tests/fixtures/smiley.png differ diff --git a/src/tests/fixtures/smiley_embedded_v2.png b/src/tests/fixtures/smiley_embedded_v2.png index 767249208..b74075bd3 100644 Binary files a/src/tests/fixtures/smiley_embedded_v2.png and b/src/tests/fixtures/smiley_embedded_v2.png differ diff --git a/src/tests/fixtures/test_embedded_v1.png b/src/tests/fixtures/test_embedded_v1.png index d5447223d..96c97cf1b 100644 Binary files a/src/tests/fixtures/test_embedded_v1.png and b/src/tests/fixtures/test_embedded_v1.png differ diff --git a/src/tests/helpers/ui.ts b/src/tests/helpers/ui.ts index 1ae572044..5f8f23c76 100644 --- a/src/tests/helpers/ui.ts +++ b/src/tests/helpers/ui.ts @@ -169,6 +169,12 @@ export class Pointer { this.click(element.x, element.y); this.reset(); } + + doubleClickOn(element: ExcalidrawElement) { + this.reset(); + this.doubleClick(element.x, element.y); + this.reset(); + } } const mouse = new Pointer("mouse"); @@ -178,32 +184,72 @@ export class UI { fireEvent.click(GlobalTestState.renderResult.getByToolName(toolName)); }; + /** + * Creates an Excalidraw element, and returns a proxy that wraps it so that + * accessing props will return the latest ones from the object existing in + * the app's elements array. This is because across the app lifecycle we tend + * to recreate element objects and the returned reference will become stale. + * + * If you need to get the actual element, not the proxy, call `get()` method + * on the proxy object. + */ static createElement( type: T, { - x = 0, - y = 0, + position = 0, + x = position, + y = position, size = 10, width = size, height = width, }: { + position?: number; x?: number; y?: number; size?: number; width?: number; height?: number; } = {}, - ): T extends "arrow" | "line" | "draw" + ): (T extends "arrow" | "line" | "draw" ? ExcalidrawLinearElement : T extends "text" ? ExcalidrawTextElement - : ExcalidrawElement { + : ExcalidrawElement) & { + /** Returns the actual, current element from the elements array, instead + of the proxy */ + get(): T extends "arrow" | "line" | "draw" + ? ExcalidrawLinearElement + : T extends "text" + ? ExcalidrawTextElement + : ExcalidrawElement; + } { UI.clickTool(type); mouse.reset(); mouse.down(x, y); mouse.reset(); mouse.up(x + (width ?? height ?? size), y + (height ?? size)); - return h.elements[h.elements.length - 1] as any; + + const origElement = h.elements[h.elements.length - 1] as any; + + return new Proxy( + {}, + { + get(target, prop) { + const currentElement = h.elements.find( + (element) => element.id === origElement.id, + ) as any; + if (prop === "get") { + if (currentElement.hasOwnProperty("get")) { + throw new Error( + "trying to get `get` test property, but ExcalidrawElement seems to define its own", + ); + } + return () => currentElement; + } + return currentElement[prop]; + }, + }, + ) as any; } static group(elements: ExcalidrawElement[]) { diff --git a/src/tests/move.test.tsx b/src/tests/move.test.tsx index 9d58b0873..e97ace31f 100644 --- a/src/tests/move.test.tsx +++ b/src/tests/move.test.tsx @@ -69,9 +69,9 @@ describe("move element", () => { // bind line to two rectangles bindOrUnbindLinearElement( - line as NonDeleted, - rectA as ExcalidrawRectangleElement, - rectB as ExcalidrawRectangleElement, + line.get() as NonDeleted, + rectA.get() as ExcalidrawRectangleElement, + rectB.get() as ExcalidrawRectangleElement, ); // select the second rectangles diff --git a/src/tests/regressionTests.test.tsx b/src/tests/regressionTests.test.tsx index 1a2aaa6a8..95fb5662e 100644 --- a/src/tests/regressionTests.test.tsx +++ b/src/tests/regressionTests.test.tsx @@ -4,9 +4,8 @@ import ReactDOM from "react-dom"; import { copiedStyles } from "../actions/actionStyles"; import { ShortcutName } from "../actions/shortcuts"; import { ExcalidrawElement } from "../element/types"; -import { setLanguage } from "../i18n"; import { CODES, KEYS } from "../keys"; -import Excalidraw from "../packages/excalidraw/index"; +import ExcalidrawApp from "../excalidraw-app"; import { reseed } from "../random"; import * as Renderer from "../renderer/renderScene"; import { setDateTimeForTests } from "../utils"; @@ -19,6 +18,7 @@ import { screen, waitFor, } from "./test-utils"; +import { defaultLang } from "../i18n"; const { h } = window; @@ -75,8 +75,7 @@ beforeEach(async () => { finger1.reset(); finger2.reset(); - await setLanguage("en.json"); - await render(); + await render(); }); afterEach(() => { @@ -151,22 +150,26 @@ describe("regression tests", () => { expect(API.getSelectedElement().id).not.toEqual(prevSelectedId); }); - for (const [keys, shape] of [ - [`2${KEYS.R}`, "rectangle"], - [`3${KEYS.D}`, "diamond"], - [`4${KEYS.E}`, "ellipse"], - [`5${KEYS.A}`, "arrow"], - [`6${KEYS.L}`, "line"], - [`7${KEYS.X}`, "draw"], - ] as [string, ExcalidrawElement["type"]][]) { + for (const [keys, shape, shouldSelect] of [ + [`2${KEYS.R}`, "rectangle", true], + [`3${KEYS.D}`, "diamond", true], + [`4${KEYS.E}`, "ellipse", true], + [`5${KEYS.A}`, "arrow", true], + [`6${KEYS.L}`, "line", true], + [`7${KEYS.X}`, "draw", false], + ] as [string, ExcalidrawElement["type"], boolean][]) { for (const key of keys) { it(`key ${key} selects ${shape} tool`, () => { Keyboard.keyPress(key); + expect(h.state.elementType).toBe(shape); + mouse.down(10, 10); mouse.up(10, 10); - expect(API.getSelectedElement().type).toBe(shape); + if (shouldSelect) { + expect(API.getSelectedElement().type).toBe(shape); + } }); } } @@ -439,7 +442,7 @@ describe("regression tests", () => { await waitFor(() => expect(screen.queryByTitle(/thin/i)).toBeNull()); // reset language fireEvent.change(document.querySelector(".dropdown-select__language")!, { - target: { value: "en" }, + target: { value: defaultLang.code }, }); // switching back to English await waitFor(() => expect(screen.queryByTitle(/thin/i)).not.toBeNull()); @@ -558,64 +561,46 @@ describe("regression tests", () => { }); it("supports nested groups", () => { - const positions: number[][] = []; - - UI.clickTool("rectangle"); - mouse.down(10, 10); - mouse.up(10, 10); - positions.push(mouse.getPosition()); - - UI.clickTool("rectangle"); - mouse.down(10, -10); - mouse.up(10, 10); - positions.push(mouse.getPosition()); - - UI.clickTool("rectangle"); - mouse.down(10, -10); - mouse.up(10, 10); - positions.push(mouse.getPosition()); + const rectA = UI.createElement("rectangle", { position: 0, size: 50 }); + const rectB = UI.createElement("rectangle", { position: 100, size: 50 }); + const rectC = UI.createElement("rectangle", { position: 200, size: 50 }); Keyboard.withModifierKeys({ ctrl: true }, () => { Keyboard.keyPress(KEYS.A); Keyboard.codePress(CODES.G); }); - mouse.doubleClick(); + mouse.doubleClickOn(rectC); Keyboard.withModifierKeys({ shift: true }, () => { - mouse.restorePosition(...positions[0]); - mouse.click(); + mouse.clickOn(rectA); }); Keyboard.withModifierKeys({ ctrl: true }, () => { Keyboard.codePress(CODES.G); }); - const groupIds = h.elements[2].groupIds; - expect(groupIds.length).toBe(2); - expect(h.elements[1].groupIds).toEqual(groupIds); - expect(h.elements[0].groupIds).toEqual(groupIds.slice(1)); + expect(rectC.groupIds.length).toBe(2); + expect(rectA.groupIds).toEqual(rectC.groupIds); + expect(rectB.groupIds).toEqual(rectA.groupIds.slice(1)); - mouse.click(50, 50); + mouse.click(0, 100); expect(API.getSelectedElements().length).toBe(0); - mouse.restorePosition(...positions[0]); - mouse.click(); + + mouse.clickOn(rectA); expect(API.getSelectedElements().length).toBe(3); expect(h.state.editingGroupId).toBe(null); - mouse.doubleClick(); + mouse.doubleClickOn(rectA); expect(API.getSelectedElements().length).toBe(2); - expect(h.state.editingGroupId).toBe(groupIds[1]); + expect(h.state.editingGroupId).toBe(rectA.groupIds[1]); - mouse.doubleClick(); + mouse.doubleClickOn(rectA); expect(API.getSelectedElements().length).toBe(1); - expect(h.state.editingGroupId).toBe(groupIds[0]); + expect(h.state.editingGroupId).toBe(rectA.groupIds[0]); - // click out of the group - mouse.restorePosition(...positions[1]); - mouse.click(); - expect(API.getSelectedElements().length).toBe(0); - mouse.click(); + // click outside current (sub)group + mouse.clickOn(rectB); expect(API.getSelectedElements().length).toBe(3); - mouse.doubleClick(); + mouse.doubleClickOn(rectB); expect(API.getSelectedElements().length).toBe(1); }); @@ -636,6 +621,7 @@ describe("regression tests", () => { const expectedShortcutNames: ShortcutName[] = [ "selectAll", "gridMode", + "zenMode", "stats", ]; diff --git a/src/types.ts b/src/types.ts index 3f73ff97d..0310941ed 100644 --- a/src/types.ts +++ b/src/types.ts @@ -9,6 +9,7 @@ import { GroupId, ExcalidrawBindableElement, Arrowhead, + ChartType, } from "./element/types"; import { SHAPES } from "./shapes"; import { Point as RoughPoint } from "roughjs/bin/geometry"; @@ -17,6 +18,8 @@ import { SuggestedBinding } from "./element/binding"; import { ImportedDataState } from "./data/types"; import { ExcalidrawImperativeAPI } from "./components/App"; import type { ResolvablePromise } from "./utils"; +import { Spreadsheet } from "./charts"; +import { Language } from "./i18n"; export type FlooredNumber = number & { _brand: "FlooredNumber" }; export type Point = Readonly; @@ -67,8 +70,6 @@ export type AppState = { viewBackgroundColor: string; scrollX: FlooredNumber; scrollY: FlooredNumber; - cursorX: number; - cursorY: number; cursorButton: "up" | "down"; scrolledOutside: boolean; name: string; @@ -100,6 +101,16 @@ export type AppState = { fileHandle: import("browser-nativefs").FileSystemHandle | null; collaborators: Map; showStats: boolean; + currentChartType: ChartType; + pasteDialog: + | { + shown: false; + data: null; + } + | { + shown: true; + data: Spreadsheet; + }; }; export type NormalizedZoomValue = number & { _brand: "normalizedZoom" }; @@ -172,6 +183,8 @@ export interface ExcalidrawProps { appState: AppState, canvas: HTMLCanvasElement | null, ) => void; + renderFooter?: (isMobile: boolean) => JSX.Element; + langCode?: Language["code"]; } export type SceneData = { diff --git a/src/utils.ts b/src/utils.ts index e1c276d45..933765c2f 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,6 +1,7 @@ import colors from "./colors"; import { CURSOR_TYPE, + DEFAULT_VERSION, FONT_FAMILY, WINDOWS_EMOJI_FALLBACK_FONT, } from "./constants"; @@ -361,3 +362,8 @@ export const nFormatter = (num: number, digits: number): string => { (num / si[index].value).toFixed(digits).replace(rx, "$1") + si[index].symbol ); }; + +export const getVersion = () => { + const version = document.querySelector('meta[name="version"]'); + return version ? (version as any).content : DEFAULT_VERSION; +}; diff --git a/src/zindex.ts b/src/zindex.ts index 38ab9c8ca..055714101 100644 --- a/src/zindex.ts +++ b/src/zindex.ts @@ -1,8 +1,7 @@ -import { AppState } from "./types"; import { ExcalidrawElement } from "./element/types"; import { getElementsInGroup } from "./groups"; -import { findLastIndex, findIndex } from "./utils"; -import { trackEvent, EVENT_LAYER } from "./analytics"; +import { AppState } from "./types"; +import { findIndex, findLastIndex } from "./utils"; /** * Returns indices of elements to move based on selected elements. @@ -176,7 +175,6 @@ const shiftElements = ( ]; }); - trackEvent(EVENT_LAYER, "move", direction === "left" ? "down" : "up"); return elements; }; @@ -234,7 +232,6 @@ const shiftElementsToEnd = ( const leadingElements = elements.slice(0, leadingIndex); const trailingElements = elements.slice(trailingIndex + 1); - trackEvent(EVENT_LAYER, "move", direction === "left" ? "back" : "front"); return direction === "left" ? [ ...leadingElements,