├── src ├── Globals.d.ts ├── index.module.css ├── types │ └── index.ts └── index.ts ├── .gitignore ├── server ├── requirements.txt ├── Dockerfile └── main.py ├── assets └── demo.gif ├── .npmignore ├── .github ├── dependabot.yml └── workflows │ ├── npm-publish.yml │ └── bump-version.yml ├── package.json ├── vite.config.js ├── LICENSE ├── index.html ├── README.md ├── tsconfig.json └── yarn.lock /src/Globals.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.module.css"; -------------------------------------------------------------------------------- /src/index.module.css: -------------------------------------------------------------------------------- 1 | .hidden { 2 | display: none; 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | server/venv 2 | .idea 3 | .DS_Store 4 | node_modules 5 | *.log 6 | dist -------------------------------------------------------------------------------- /server/requirements.txt: -------------------------------------------------------------------------------- 1 | flask==2.2.2 2 | flask-cors==3.0.10 3 | googletrans==3.1.0a0 -------------------------------------------------------------------------------- /assets/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/editor-js/translate-inline/master/assets/demo.gif -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .github/ 2 | .idea/ 3 | src/ 4 | index.html 5 | tsconfig.json 6 | vite.config.js 7 | yarn.lock -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | directory: "/template" 5 | schedule: 6 | interval: "daily" -------------------------------------------------------------------------------- /server/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim 2 | 3 | WORKDIR /app 4 | 5 | COPY ./requirements.txt . 6 | RUN pip install -r requirements.txt 7 | 8 | COPY ./main.py . 9 | 10 | CMD ["python", "main.py"] -------------------------------------------------------------------------------- /src/types/index.ts: -------------------------------------------------------------------------------- 1 | import { ToolConfig } from '@editorjs/editorjs'; 2 | 3 | /** 4 | * Translate Tool's configuration object that passed through the initial Editor config 5 | */ 6 | export interface TranslateConfig extends ToolConfig { 7 | /** 8 | * API endpoint to send requests to 9 | * @example http://localhost:5000/translate?text= 10 | */ 11 | endpoint: string; 12 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@editorjs/translate-inline", 3 | "description": "Translate Inline Tool for Editor.js", 4 | "version": "1.0.0-rc.1", 5 | "main": "dist/Translate.umd.js", 6 | "module": "dist/Translate.mjs", 7 | "license": "MIT", 8 | "scripts": { 9 | "dev": "vite", 10 | "build": "vite build" 11 | }, 12 | "devDependencies": { 13 | "@codexteam/icons": "^0.2.0", 14 | "@editorjs/editorjs": "^2.26.4", 15 | "@types/node": "^16.3.3", 16 | "vite": "^3.1.0", 17 | "vite-plugin-css-injected-by-js": "^2.1.1" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'; 2 | import path from 'path'; 3 | 4 | /** 5 | * Trick to use Vite server.open option on macOS 6 | * @see https://github.com/facebook/create-react-app/pull/1690#issuecomment-283518768 7 | */ 8 | process.env.BROWSER = 'open'; 9 | 10 | export default { 11 | build: { 12 | lib: { 13 | entry: path.resolve(__dirname, 'src', 'index.ts'), 14 | name: 'Translate', 15 | formats: ['umd', 'es'], 16 | fileName: 'Translate' 17 | }, 18 | }, 19 | 20 | server: { 21 | port: 3300, 22 | open: true, 23 | }, 24 | 25 | plugins: [ 26 | cssInjectedByJsPlugin(), 27 | ] 28 | } -------------------------------------------------------------------------------- /server/main.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, request, jsonify 2 | from flask_cors import CORS 3 | 4 | from googletrans import Translator 5 | 6 | app = Flask(__name__) 7 | CORS(app) 8 | translator = Translator() 9 | 10 | @app.route('/translate', methods=['GET']) 11 | def hello(): 12 | try: 13 | text = request.args.get('text', default = None) 14 | landSrc = request.args.get('src', default = None) 15 | langDest = request.args.get('dest', default = 'en') 16 | 17 | response = translator.translate(text, dest=langDest).text 18 | 19 | return jsonify({ 20 | "status": "success", 21 | "message": response 22 | }) 23 | 24 | except Exception as err: 25 | print(err) 26 | return jsonify({ 27 | "status": "error", 28 | "message": str(err) 29 | }) 30 | 31 | if __name__ == '__main__': 32 | app.run(host="0.0.0.0", port=5000, debug=True) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 CodeX 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish package to NPM 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - master 8 | 9 | jobs: 10 | publish: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: actions/setup-node@v1 15 | with: 16 | node-version: 18 17 | registry-url: https://registry.npmjs.org/ 18 | 19 | - run: yarn 20 | - run: yarn build 21 | - run: yarn publish --access=public --tag=next 22 | env: 23 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 24 | 25 | - name: Get package info 26 | id: package 27 | uses: codex-team/action-nodejs-package-info@v1.1 28 | 29 | - name: Add LATEST tag for the published package if this is not a -rc version 30 | if: steps.package.outputs.is-release-candidate == 'false' 31 | run: npm dist-tag add ${{ steps.package.outputs.name }}@${{ steps.package.outputs.version }} latest 32 | env: 33 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 34 | 35 | notify: 36 | needs: publish 37 | runs-on: ubuntu-latest 38 | steps: 39 | - uses: actions/checkout@v2 40 | - name: Get package info 41 | id: package 42 | uses: codex-team/action-nodejs-package-info@v1 43 | - name: Send a message 44 | uses: codex-team/action-codexbot-notify@v1 45 | with: 46 | webhook: ${{ secrets.CODEX_BOT_NOTIFY_EDITORJS_PUBLIC_CHAT }} 47 | message: '📦 [${{ steps.package.outputs.name }}](${{ steps.package.outputs.npmjs-link }}) ${{ steps.package.outputs.version }} was published' 48 | parse_mode: 'markdown' 49 | disable_web_page_preview: true 50 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Editor.js example page 5 | 6 | 11 | 12 | 13 |
14 | 15 | 16 |

17 | 
18 |   
65 | 
66 | 
67 | 
68 | 


--------------------------------------------------------------------------------
/.github/workflows/bump-version.yml:
--------------------------------------------------------------------------------
 1 | name: Auto bump version
 2 | 
 3 | on:
 4 |   pull_request:
 5 |     branches:
 6 |       - main
 7 |       - master
 8 | 
 9 | jobs:
10 |   # If pull request was merged then we should check for a package version update
11 |   check-for-no-version-changing:
12 |     runs-on: ubuntu-latest
13 |     steps:
14 |       # Checkout to target branch
15 |       - uses: actions/checkout@v2
16 |         with:
17 |           fetch-depth: 0
18 | 
19 |       # Get package new version name
20 |       - name: Get package info
21 |         id: packageNew
22 |         uses: codex-team/action-nodejs-package-info@v1
23 | 
24 |       # Checkout to the base commit before merge
25 |       - name: Checkout to the base commit before merge
26 |         run: git checkout ${{ github.event.pull_request.base.sha }}
27 | 
28 |       # Get package old version name
29 |       - name: Get package info
30 |         id: packageOld
31 |         uses: codex-team/action-nodejs-package-info@v1
32 | 
33 |       # Stop workflow and do not bump version if it was changed already
34 |       - name: Stop workflow and do not bump version if it was changed already
35 |         uses: actions/github-script@v3
36 |         if: steps.packageOld.outputs.version != steps.packageNew.outputs.version
37 |         with:
38 |           script: |
39 |             core.setFailed('Version was changed! ${{ steps.packageOld.outputs.version }} -> ${{ steps.packageNew.outputs.version }}')
40 | 
41 |   bump-version:
42 |     needs: check-for-no-version-changing
43 |     runs-on: ubuntu-latest
44 |     steps:
45 |       # Checkout to target branch
46 |       - uses: actions/checkout@v2
47 | 
48 |       # Setup node environment
49 |       - uses: actions/setup-node@v1
50 |         with:
51 |           node-version: 18
52 | 
53 |       # Bump version to the next prerelease (patch) with rc suffix
54 |       - name: Suggest the new version
55 |         run: yarn version --prerelease --preid rc --no-git-tag-version
56 | 
57 |       # Get package new version name
58 |       - name: Get package info
59 |         id: package
60 |         uses: codex-team/action-nodejs-package-info@v1
61 | 
62 |       # Commit and push changes
63 |       - uses: EndBug/add-and-commit@v7
64 |         with:
65 |           author_name: github-actions
66 |           author_email: 41898282+github-actions[bot]@users.noreply.github.com
67 |           message: "Bump version up to ${{ steps.package.outputs.version }}"


--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
  1 | # Translate Inline Tool for Editor.js
  2 | 
  3 | This tool allows you to translate text inline to english. 
  4 | 
  5 | Requires a translation service. See [Translation Service](#translation-service) for more information.
  6 | 
  7 | ![Translate Inline Demo Video](./assets/demo.gif)
  8 | 
  9 | ## Features
 10 | 
 11 | Works in any block. just select the text and click the Translate button in the toolbar.
 12 | 
 13 | Source language is detected automatically.
 14 | 
 15 | Example of the translation service server is provided.
 16 | 
 17 | `Soon` Choosing the target language to translate.
 18 | 
 19 | `Soon` Support for the offical Google Translate API.
 20 | 
 21 | ## Installation
 22 | 
 23 | ### Translation Service
 24 | 
 25 | Features of the example translation service:
 26 | 
 27 | - uses the [googletrans](https://github.com/ssut/py-googletrans) python package to translate text;
 28 | - runs on port 5000;
 29 | - CORS are enabled for all origins.
 30 | 
 31 | You can run the server locally via [venv](#via-venv) or [docker](#via-docker). On the production you can use  
 32 | 
 33 | For the production environment you should use a different translation service cause the `googletrans` package is not meant for production use. But you can use the example server as a starting point.
 34 | 
 35 | ### Usage
 36 | 
 37 | Use your package manager to install the package `editorjs-translate-inline`.
 38 | 
 39 | ```shell
 40 | npm install -D @editorjs/translate-inline
 41 | 
 42 | yarn add -D @editorjs/translate-inline
 43 | ```
 44 | 
 45 | Import and add the Tool to your Editor.js configuration and provide the endpoint of the translation service.
 46 | 
 47 | ```javascript
 48 | import Translate from '@editorjs/translate-inline';
 49 | 
 50 | const editor = new EditorJS({
 51 |   tools: {
 52 |     translator: {
 53 |       class: Translate,
 54 |       config: {
 55 |         endpoint: 'http://localhost:5000/translate?text=',
 56 |       }
 57 |     },
 58 |   },
 59 | 
 60 |   // ...
 61 | });
 62 | ```
 63 | 
 64 | ## Development
 65 | 
 66 | ### Run package builder
 67 | 
 68 | `npm run dev` / `yarn dev` — run development environment with hot reload
 69 | 
 70 | `npm run build` / `yarn build` — build the tool for production to the `dist` folder
 71 | 
 72 | ### Run translation server
 73 | 
 74 | ### Via venv
 75 | 
 76 | Use venv to create a virtual environment and activate it.
 77 | 
 78 | ```shell
 79 | cd server
 80 | python3 -m venv venv
 81 | source venv/bin/activate
 82 | ```
 83 | 
 84 | Install the requirements and run the server.
 85 | 
 86 | ```shell
 87 | python -m pip install -r requirements.txt
 88 | python main.py
 89 | ```
 90 | 
 91 | Deactivate the virtual environment when you're done.
 92 | 
 93 | ```shell
 94 | deactivate
 95 | ```
 96 | 
 97 | ### Via docker
 98 | 
 99 | Build the docker image and run the container.
100 | 
101 | ```shell
102 | cd server
103 | docker build -t editorjs-translate-inline .
104 | docker run -p 5000:5000 editorjs-translate-inline
105 | ```
106 | 
107 | To rebuild the image after changes run `docker build --no-cache -t editorjs-translate-inline .`
108 | 
109 | ## Links
110 | 
111 | [Editor.js](https://editorjs.io) • [Create Tool](https://github.com/editor-js/create-tool)


--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "compilerOptions": {
 3 |     /* Visit https://aka.ms/tsconfig.json to read more about this file */
 4 | 
 5 |     /* Basic Options */
 6 |     // "incremental": true,                         /* Enable incremental compilation */
 7 |     "target": "es5",                                /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
 8 |     "module": "commonjs",                           /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
 9 |     "lib": ["ES2020", "dom"],                       /* Specify library files to be included in the compilation. */
10 |     // "allowJs": true,                             /* Allow javascript files to be compiled. */
11 |     // "checkJs": true,                             /* Report errors in .js files. */
12 |     // "jsx": "preserve",                           /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
13 |     // "declaration": true,                         /* Generates corresponding '.d.ts' file. */
14 |     // "declarationMap": true,                      /* Generates a sourcemap for each corresponding '.d.ts' file. */
15 |     // "sourceMap": true,                           /* Generates corresponding '.map' file. */
16 |     // "outFile": "./",                             /* Concatenate and emit output to single file. */
17 |     // "outDir": "./",                              /* Redirect output structure to the directory. */
18 |     // "rootDir": "./",                             /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
19 |     // "composite": true,                           /* Enable project compilation */
20 |     // "tsBuildInfoFile": "./",                     /* Specify file to store incremental compilation information */
21 |     // "removeComments": true,                      /* Do not emit comments to output. */
22 |     // "noEmit": true,                              /* Do not emit outputs. */
23 |     // "importHelpers": true,                       /* Import emit helpers from 'tslib'. */
24 |     // "downlevelIteration": true,                  /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
25 |     // "isolatedModules": true,                     /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
26 | 
27 |     /* Strict Type-Checking Options */
28 |     "strict": true,                                 /* Enable all strict type-checking options. */
29 |     // "noImplicitAny": true,                       /* Raise error on expressions and declarations with an implied 'any' type. */
30 |     // "strictNullChecks": true,                    /* Enable strict null checks. */
31 |     // "strictFunctionTypes": true,                 /* Enable strict checking of function types. */
32 |     // "strictBindCallApply": true,                 /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
33 |     // "strictPropertyInitialization": true,        /* Enable strict checking of property initialization in classes. */
34 |     // "noImplicitThis": true,                      /* Raise error on 'this' expressions with an implied 'any' type. */
35 |     // "alwaysStrict": true,                        /* Parse in strict mode and emit "use strict" for each source file. */
36 | 
37 |     /* Additional Checks */
38 |     // "noUnusedLocals": true,                      /* Report errors on unused locals. */
39 |     // "noUnusedParameters": true,                  /* Report errors on unused parameters. */
40 |     // "noImplicitReturns": true,                   /* Report error when not all code paths in function return a value. */
41 |     // "noFallthroughCasesInSwitch": true,          /* Report errors for fallthrough cases in switch statement. */
42 |     // "noUncheckedIndexedAccess": true,            /* Include 'undefined' in index signature results */
43 |     // "noPropertyAccessFromIndexSignature": true,  /* Require undeclared properties from index signatures to use element accesses. */
44 | 
45 |     /* Module Resolution Options */
46 |     // "moduleResolution": "node",                  /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
47 |     // "baseUrl": "./",                             /* Base directory to resolve non-absolute module names. */
48 |     // "paths": {},                                 /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
49 |     // "rootDirs": [],                              /* List of root folders whose combined content represents the structure of the project at runtime. */
50 |     // "typeRoots": [],                             /* List of folders to include type definitions from. */
51 |     // "types": [],                                 /* Type declaration files to be included in compilation. */
52 |     // "allowSyntheticDefaultImports": true,        /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
53 |     "esModuleInterop": true,                        /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
54 |     // "preserveSymlinks": true,                    /* Do not resolve the real path of symlinks. */
55 |     // "allowUmdGlobalAccess": true,                /* Allow accessing UMD globals from modules. */
56 | 
57 |     /* Source Map Options */
58 |     // "sourceRoot": "",                            /* Specify the location where debugger should locate TypeScript files instead of source locations. */
59 |     // "mapRoot": "",                               /* Specify the location where debugger should locate map files instead of generated locations. */
60 |     // "inlineSourceMap": true,                     /* Emit a single file with source maps instead of having a separate file. */
61 |     // "inlineSources": true,                       /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
62 | 
63 |     /* Experimental Options */
64 |     // "experimentalDecorators": true,              /* Enables experimental support for ES7 decorators. */
65 |     // "emitDecoratorMetadata": true,               /* Enables experimental support for emitting type metadata for decorators. */
66 | 
67 |     /* Advanced Options */
68 |     "skipLibCheck": true,                           /* Skip type checking of declaration files. */
69 |     "forceConsistentCasingInFileNames": true,       /* Disallow inconsistently-cased references to the same file. */
70 |     
71 |     "plugins": [{
72 |       "name": "typescript-plugin-css-modules"
73 |     }]
74 |   }
75 | }


--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
  1 | /**
  2 |  * Import styles library
  3 |  */
  4 | import styles from './index.module.css';
  5 | 
  6 | /**
  7 |  * Import icons
  8 |  */
  9 | import { IconTranslate, IconLoader } from '@codexteam/icons';
 10 | 
 11 | /**
 12 |  * Import types
 13 |  */
 14 | import { TranslateConfig } from './types';
 15 | import { API, InlineTool } from '@editorjs/editorjs';
 16 | 
 17 | /**
 18 |  * Translate Tool for Editor.js
 19 |  */
 20 | export default class Translate implements InlineTool {
 21 |   /**
 22 |    * Code API — public methods to work with Editor
 23 |    * 
 24 |    * @link https://editorjs.io/api
 25 |    */
 26 |   private readonly api: API;
 27 | 
 28 |   /**
 29 |    * Configuration object that passed through the initial Editor configuration.
 30 |    */
 31 |   private config: TranslateConfig;
 32 | 
 33 |   /**
 34 |    * Tool's HTML nodes
 35 |    */
 36 |   private nodes: {[key: string]: HTMLElement | null};
 37 | 
 38 |   /**
 39 |    * Saved text before translation to implement 'revert' feature
 40 |    */ 
 41 |   private originalText: string = '';
 42 | 
 43 |   /**
 44 |    * Class constructor
 45 |    * 
 46 |    * @link https://editorjs.io/tools-api#class-constructor
 47 |    */
 48 |   constructor({ config, api }: { config: TranslateConfig, api: API }) {
 49 |     this.config = config;  
 50 |     this.api = api;
 51 | 
 52 |     /**
 53 |      * Declare Tool's nodes
 54 |      */
 55 |     this.nodes = {
 56 |       wrapper: null,
 57 |       translateIcon: null,
 58 |       loader: null,
 59 |     };
 60 |   }
 61 | 
 62 |   /**
 63 |    * Inline Tool flag
 64 |    */ 
 65 |   static get isInline() {
 66 |     return true;
 67 |   }
 68 | 
 69 |   /**
 70 |    * Tool's title
 71 |    */
 72 |   static get title() {
 73 |     return 'Translate';
 74 |   }
 75 | 
 76 |   /**
 77 |    * Tool's button with icon
 78 |    */ 
 79 |   render(): HTMLElement {
 80 |     this.nodes.wrapper = document.createElement('button');
 81 |     this.nodes.wrapper.classList.add(this.api.styles.inlineToolButton);
 82 |     this.nodes.wrapper.type = 'button';
 83 | 
 84 |     this.nodes.translateIcon = this.getElementFromHTML(IconTranslate);
 85 |     this.nodes.wrapper.appendChild(this.nodes.translateIcon);
 86 | 
 87 |     this.nodes.loader = this.getElementFromHTML(IconLoader);
 88 |     this.nodes.loader.classList.add(styles.hidden);
 89 |     this.nodes.wrapper.appendChild(this.nodes.loader);
 90 | 
 91 |     return this.nodes.wrapper;
 92 |   }
 93 | 
 94 |   /**
 95 |    * Processing selected text
 96 |    */
 97 |   async surround(range: Range): Promise {
 98 |     /**
 99 |      * Apply 'revert' feature if button was clicked again after translation
100 |      */
101 |     if (this.originalText) {
102 |       this.toggleLoader();
103 | 
104 |       this.replaceText(range, this.originalText);
105 | 
106 |       /**
107 |        * Wait for animation to complete as UX improvement
108 |        */
109 |       setTimeout(() => {
110 |         this.toggleLoader(false);
111 |       }, 300);
112 | 
113 |       /**
114 |        * Restore selection
115 |        */
116 |       this.select(range);
117 | 
118 |       this.originalText = '';
119 | 
120 |       return;
121 |     }
122 | 
123 |     /**
124 |      * Get selected text
125 |      */
126 |     const inputText = range.toString();
127 | 
128 |     if (!inputText) return;
129 | 
130 |     /**
131 |      * Translation process
132 |      */
133 |     this.toggleLoader();
134 |     const translatedText = await this.translate(inputText);
135 |     this.toggleLoader(false);
136 | 
137 |     if (!translatedText) return;
138 | 
139 |     /**
140 |      * Save original text to implement 'revert' feature
141 |      */ 
142 |     this.originalText = inputText;
143 | 
144 |     this.replaceText(range, translatedText);
145 | 
146 |     /**
147 |      * Restore selection
148 |      */ 
149 |     this.select(range);
150 |   }
151 | 
152 |   /**
153 |    * No need to implement this method
154 |    */
155 |   checkState() {
156 |     return false;
157 |   }
158 | 
159 |   /**
160 |    * Restore selection method
161 |    */
162 |   select(range: Range) {
163 |     const sel = window.getSelection();
164 |     
165 |     if (!sel) return;
166 | 
167 |     sel.removeAllRanges();
168 |     sel.addRange(range);
169 |   }
170 | 
171 |   /**
172 |    * Replace text in the selection
173 |    */
174 |   private replaceText(range: Range, text: string): void {
175 |     range.deleteContents();
176 |     range.insertNode(document.createTextNode(text));
177 |   }
178 | 
179 |   /**
180 |    * Translate text 
181 |    */
182 |   private async translate(text: string): Promise {
183 |     /**
184 |      * Do not send empty strings to the server
185 |      */
186 |     if (!text) return;
187 | 
188 |     try {
189 |       if (!this.config.endpoint) {
190 |         throw new Error('Translation endpoint is not specified');
191 |       }  
192 | 
193 |       let response;
194 | 
195 |       /**
196 |        * Try to send a request to the translation server
197 |        */
198 |       try {
199 |         response = await fetch(`${this.config.endpoint}${text}`);
200 |       } catch (error) {
201 |         throw new Error('Translation server is not available');
202 |       }
203 | 
204 |       /**
205 |        * Process non-200 responses
206 |        */
207 |       if (response.status !== 200) {
208 |         throw new Error('Bad response from translation server');
209 |       }
210 | 
211 |       const data = await response.json();
212 | 
213 |       /**
214 |        * Process server responses with errors
215 |        */
216 |       if (data.status == 'error') {
217 |         throw new Error(`Server error: ${data.message}`);
218 |       }
219 | 
220 |       return data.message;
221 | 
222 |     } catch (error: any) {
223 |       /**
224 |        * Show error notification
225 |        */
226 |       this.api.notifier.show({
227 |         message: error.message,
228 |         style: 'error',
229 |       });
230 |     }
231 |   }
232 | 
233 |   /**
234 |    * Toggle loader element on the button
235 |    * 
236 |    * @param flag — true to add class, false to remove
237 |    */
238 |   private toggleLoader(flag = true): void {
239 |     if (!this.nodes.translateIcon) {
240 |       console.error('[Translate] button is not found');
241 |       return;
242 |     }
243 | 
244 |     if (!this.nodes.loader) {
245 |       console.error('Loader is not found');
246 |       return;
247 |     };
248 | 
249 |     this.nodes.translateIcon.classList.toggle(styles.hidden, flag);
250 |     this.nodes.loader.classList.toggle(styles.hidden, !flag);
251 |   }
252 | 
253 |   /**
254 |    * Create HTML element from string
255 |    * 
256 |    * @param html — HTML string
257 |    */
258 |   private getElementFromHTML(html: string): HTMLElement {
259 |     const template = document.createElement('template');
260 |    
261 |     template.innerHTML = html.trim();
262 |    
263 |     return template.content.firstChild as HTMLElement;
264 |   }
265 | };


--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
  1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
  2 | # yarn lockfile v1
  3 | 
  4 | 
  5 | "@codexteam/icons@0.1.0":
  6 |   version "0.1.0"
  7 |   resolved "https://registry.yarnpkg.com/@codexteam/icons/-/icons-0.1.0.tgz#a02885fe8699f69902d05b077b5f1cd48a2ca6b9"
  8 |   integrity sha512-jW1fWnwtWzcP4FBGsaodbJY3s1ZaRU+IJy1pvJ7ygNQxkQinybJcwXoyt0a5mWwu/4w30A42EWhCrZn8lp4fdw==
  9 | 
 10 | "@codexteam/icons@^0.2.0":
 11 |   version "0.2.0"
 12 |   resolved "https://registry.yarnpkg.com/@codexteam/icons/-/icons-0.2.0.tgz#749e8fdd560d332bd06e7b798cdb53e41d3e88f3"
 13 |   integrity sha512-v6ICziqFGHv9Pzcn5Pib799AHBxsD/0s3QoRC6y/ZUHGtogq4HeV4Nzd8C2wTWrbYoZE2BcksFCMEM1xTZEEXA==
 14 | 
 15 | "@editorjs/editorjs@^2.26.4":
 16 |   version "2.26.4"
 17 |   resolved "https://registry.yarnpkg.com/@editorjs/editorjs/-/editorjs-2.26.4.tgz#097e29341501d81cd1721604a74da1530f5ff74f"
 18 |   integrity sha512-yuJ2NM1Y5+8DDNWr4C00tHMVHKy0uCqK1HS4pwFPVcXUawgJnU2Li2vKGvPLuf0Jj2ir7MVgADO6oC1TbYBOYQ==
 19 |   dependencies:
 20 |     "@codexteam/icons" "0.1.0"
 21 |     codex-notifier "^1.1.2"
 22 |     codex-tooltip "^1.0.5"
 23 |     html-janitor "^2.0.4"
 24 |     nanoid "^3.1.22"
 25 | 
 26 | "@esbuild/android-arm@0.15.16":
 27 |   version "0.15.16"
 28 |   resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.15.16.tgz#0642926178b15e3d1545efae6eee05c4f3451d15"
 29 |   integrity sha512-nyB6CH++2mSgx3GbnrJsZSxzne5K0HMyNIWafDHqYy7IwxFc4fd/CgHVZXr8Eh+Q3KbIAcAe3vGyqIPhGblvMQ==
 30 | 
 31 | "@esbuild/linux-loong64@0.15.16":
 32 |   version "0.15.16"
 33 |   resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.15.16.tgz#284522de76abe951e4ed2bd24a467e8d49c67933"
 34 |   integrity sha512-SDLfP1uoB0HZ14CdVYgagllgrG7Mdxhkt4jDJOKl/MldKrkQ6vDJMZKl2+5XsEY/Lzz37fjgLQoJBGuAw/x8kQ==
 35 | 
 36 | "@types/node@^16.3.3":
 37 |   version "16.18.4"
 38 |   resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.4.tgz#712ba61b4caf091fc6490301b1888356638c17bd"
 39 |   integrity sha512-9qGjJ5GyShZjUfx2ArBIGM+xExdfLvvaCyQR0t6yRXKPcWCVYF/WemtX/uIU3r7FYECXRXkIiw2Vnhn6y8d+pw==
 40 | 
 41 | codex-notifier@^1.1.2:
 42 |   version "1.1.2"
 43 |   resolved "https://registry.yarnpkg.com/codex-notifier/-/codex-notifier-1.1.2.tgz#a733079185f4c927fa296f1d71eb8753fe080895"
 44 |   integrity sha512-DCp6xe/LGueJ1N5sXEwcBc3r3PyVkEEDNWCVigfvywAkeXcZMk9K41a31tkEFBW0Ptlwji6/JlAb49E3Yrxbtg==
 45 | 
 46 | codex-tooltip@^1.0.5:
 47 |   version "1.0.5"
 48 |   resolved "https://registry.yarnpkg.com/codex-tooltip/-/codex-tooltip-1.0.5.tgz#ba25fd5b3a58ba2f73fd667c2b46987ffd1edef2"
 49 |   integrity sha512-IuA8LeyLU5p1B+HyhOsqR6oxyFQ11k3i9e9aXw40CrHFTRO2Y1npNBVU3W1SvhKAbUU7R/YikUBdcYFP0RcJag==
 50 | 
 51 | esbuild-android-64@0.15.16:
 52 |   version "0.15.16"
 53 |   resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.15.16.tgz#0d6a16fa1bea441d5183976f1633183c25a764d5"
 54 |   integrity sha512-Vwkv/sT0zMSgPSVO3Jlt1pUbnZuOgtOQJkJkyyJFAlLe7BiT8e9ESzo0zQSx4c3wW4T6kGChmKDPMbWTgtliQA==
 55 | 
 56 | esbuild-android-arm64@0.15.16:
 57 |   version "0.15.16"
 58 |   resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.15.16.tgz#78643bbbf396d26d20ba1f2fcdff3618c7c033e9"
 59 |   integrity sha512-lqfKuofMExL5niNV3gnhMUYacSXfsvzTa/58sDlBET/hCOG99Zmeh+lz6kvdgvGOsImeo6J9SW21rFCogNPLxg==
 60 | 
 61 | esbuild-darwin-64@0.15.16:
 62 |   version "0.15.16"
 63 |   resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.15.16.tgz#de3e91809dcd1ffb64409e2f990bb86e33e4ffd8"
 64 |   integrity sha512-wo2VWk/n/9V2TmqUZ/KpzRjCEcr00n7yahEdmtzlrfQ3lfMCf3Wa+0sqHAbjk3C6CKkR3WKK/whkMq5Gj4Da9g==
 65 | 
 66 | esbuild-darwin-arm64@0.15.16:
 67 |   version "0.15.16"
 68 |   resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.16.tgz#bc9cc8d51109d8e9db4ffe2c064dd53d1eb5a2a6"
 69 |   integrity sha512-fMXaUr5ou0M4WnewBKsspMtX++C1yIa3nJ5R2LSbLCfJT3uFdcRoU/NZjoM4kOMKyOD9Sa/2vlgN8G07K3SJnw==
 70 | 
 71 | esbuild-freebsd-64@0.15.16:
 72 |   version "0.15.16"
 73 |   resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.16.tgz#f8c54c679c16e9b20a1bf860ca91ba700d6c9c5d"
 74 |   integrity sha512-UzIc0xlRx5x9kRuMr+E3+hlSOxa/aRqfuMfiYBXu2jJ8Mzej4lGL7+o6F5hzhLqWfWm1GWHNakIdlqg1ayaTNQ==
 75 | 
 76 | esbuild-freebsd-arm64@0.15.16:
 77 |   version "0.15.16"
 78 |   resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.16.tgz#dd28a55df0f062e2c1628266008434c32ddc7adf"
 79 |   integrity sha512-8xyiYuGc0DLZphFQIiYaLHlfoP+hAN9RHbE+Ibh8EUcDNHAqbQgUrQg7pE7Bo00rXmQ5Ap6KFgcR0b4ALZls1g==
 80 | 
 81 | esbuild-linux-32@0.15.16:
 82 |   version "0.15.16"
 83 |   resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.15.16.tgz#41eb0b9b49b3430b9cc4577f1ad3d414ef70f806"
 84 |   integrity sha512-iGijUTV+0kIMyUVoynK0v+32Oi8yyp0xwMzX69GX+5+AniNy/C/AL1MjFTsozRp/3xQPl7jVux/PLe2ds10/2w==
 85 | 
 86 | esbuild-linux-64@0.15.16:
 87 |   version "0.15.16"
 88 |   resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.15.16.tgz#b2fb0c7d49b7a579b2de26fbf4c7afb1835f2073"
 89 |   integrity sha512-tuSOjXdLw7VzaUj89fIdAaQT7zFGbKBcz4YxbWrOiXkwscYgE7HtTxUavreBbnRkGxKwr9iT/gmeJWNm4djy/g==
 90 | 
 91 | esbuild-linux-arm64@0.15.16:
 92 |   version "0.15.16"
 93 |   resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.16.tgz#78fed3745b20251fc3bdc8db35ea0781e9b0e7c6"
 94 |   integrity sha512-mPYksnfHnemNrvjrDhZyixL/AfbJN0Xn9S34ZOHYdh6/jJcNd8iTsv3JwJoEvTJqjMggjMhGUPJAdjnFBHoH8A==
 95 | 
 96 | esbuild-linux-arm@0.15.16:
 97 |   version "0.15.16"
 98 |   resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.15.16.tgz#6963f061a2b778aad7df2bfb6fa32d1904313f7f"
 99 |   integrity sha512-XKcrxCEXDTOuoRj5l12tJnkvuxXBMKwEC5j0JISw3ziLf0j4zIwXbKbTmUrKFWbo6ZgvNpa7Y5dnbsjVvH39bQ==
100 | 
101 | esbuild-linux-mips64le@0.15.16:
102 |   version "0.15.16"
103 |   resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.16.tgz#e2aed3527e551f8182c6b0fc8a045726fd98ad87"
104 |   integrity sha512-kSJO2PXaxfm0pWY39+YX+QtpFqyyrcp0ZeI8QPTrcFVQoWEPiPVtOfTZeS3ZKedfH+Ga38c4DSzmKMQJocQv6A==
105 | 
106 | esbuild-linux-ppc64le@0.15.16:
107 |   version "0.15.16"
108 |   resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.16.tgz#fa3095b24950f63408f46f34b6d9a073ed88d53f"
109 |   integrity sha512-NimPikwkBY0yGABw6SlhKrtT35sU4O23xkhlrTT/O6lSxv3Pm5iSc6OYaqVAHWkLdVf31bF4UDVFO+D990WpAA==
110 | 
111 | esbuild-linux-riscv64@0.15.16:
112 |   version "0.15.16"
113 |   resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.16.tgz#19c012dcc55c9d6d2a3855aa77c2c5217182cd1e"
114 |   integrity sha512-ty2YUHZlwFOwp7pR+J87M4CVrXJIf5ZZtU/umpxgVJBXvWjhziSLEQxvl30SYfUPq0nzeWKBGw5i/DieiHeKfw==
115 | 
116 | esbuild-linux-s390x@0.15.16:
117 |   version "0.15.16"
118 |   resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.16.tgz#aa61f64740e5b983cc3ebb4183a03df4b435a873"
119 |   integrity sha512-VkZaGssvPDQtx4fvVdZ9czezmyWyzpQhEbSNsHZZN0BHvxRLOYAQ7sjay8nMQwYswP6O2KlZluRMNPYefFRs+w==
120 | 
121 | esbuild-netbsd-64@0.15.16:
122 |   version "0.15.16"
123 |   resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.16.tgz#dffdc104c1f2bafc42be3faa21376c0a092f5702"
124 |   integrity sha512-ElQ9rhdY51et6MJTWrCPbqOd/YuPowD7Cxx3ee8wlmXQQVW7UvQI6nSprJ9uVFQISqSF5e5EWpwWqXZsECLvXg==
125 | 
126 | esbuild-openbsd-64@0.15.16:
127 |   version "0.15.16"
128 |   resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.16.tgz#e5987f8eda55ea5f6ef6258afb1a838158f890bb"
129 |   integrity sha512-KgxMHyxMCT+NdLQE1zVJEsLSt2QQBAvJfmUGDmgEq8Fvjrf6vSKB00dVHUEDKcJwMID6CdgCpvYNt999tIYhqA==
130 | 
131 | esbuild-sunos-64@0.15.16:
132 |   version "0.15.16"
133 |   resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.15.16.tgz#60a085aa4b74d900e4de8c00a9fce207937320a2"
134 |   integrity sha512-exSAx8Phj7QylXHlMfIyEfNrmqnLxFqLxdQF6MBHPdHAjT7fsKaX6XIJn+aQEFiOcE4X8e7VvdMCJ+WDZxjSRQ==
135 | 
136 | esbuild-windows-32@0.15.16:
137 |   version "0.15.16"
138 |   resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.15.16.tgz#24f94e5fb243d211c7db9a12985fd2880ba98ca3"
139 |   integrity sha512-zQgWpY5pUCSTOwqKQ6/vOCJfRssTvxFuEkpB4f2VUGPBpdddZfdj8hbZuFRdZRPIVHvN7juGcpgCA/XCF37mAQ==
140 | 
141 | esbuild-windows-64@0.15.16:
142 |   version "0.15.16"
143 |   resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.15.16.tgz#71d24d68d8b652bf5a93a6c7453c334584fa2211"
144 |   integrity sha512-HjW1hHRLSncnM3MBCP7iquatHVJq9l0S2xxsHHj4yzf4nm9TU4Z7k4NkeMlD/dHQ4jPlQQhwcMvwbJiOefSuZw==
145 | 
146 | esbuild-windows-arm64@0.15.16:
147 |   version "0.15.16"
148 |   resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.16.tgz#77e804d60dec0390fe8f21401e39b435d5d1b863"
149 |   integrity sha512-oCcUKrJaMn04Vxy9Ekd8x23O8LoU01+4NOkQ2iBToKgnGj5eo1vU9i27NQZ9qC8NFZgnQQZg5oZWAejmbsppNA==
150 | 
151 | esbuild@^0.15.9:
152 |   version "0.15.16"
153 |   resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.15.16.tgz#59324e5667985bf6aee8a91ea576baef6872cf21"
154 |   integrity sha512-o6iS9zxdHrrojjlj6pNGC2NAg86ECZqIETswTM5KmJitq+R1YmahhWtMumeQp9lHqJaROGnsBi2RLawGnfo5ZQ==
155 |   optionalDependencies:
156 |     "@esbuild/android-arm" "0.15.16"
157 |     "@esbuild/linux-loong64" "0.15.16"
158 |     esbuild-android-64 "0.15.16"
159 |     esbuild-android-arm64 "0.15.16"
160 |     esbuild-darwin-64 "0.15.16"
161 |     esbuild-darwin-arm64 "0.15.16"
162 |     esbuild-freebsd-64 "0.15.16"
163 |     esbuild-freebsd-arm64 "0.15.16"
164 |     esbuild-linux-32 "0.15.16"
165 |     esbuild-linux-64 "0.15.16"
166 |     esbuild-linux-arm "0.15.16"
167 |     esbuild-linux-arm64 "0.15.16"
168 |     esbuild-linux-mips64le "0.15.16"
169 |     esbuild-linux-ppc64le "0.15.16"
170 |     esbuild-linux-riscv64 "0.15.16"
171 |     esbuild-linux-s390x "0.15.16"
172 |     esbuild-netbsd-64 "0.15.16"
173 |     esbuild-openbsd-64 "0.15.16"
174 |     esbuild-sunos-64 "0.15.16"
175 |     esbuild-windows-32 "0.15.16"
176 |     esbuild-windows-64 "0.15.16"
177 |     esbuild-windows-arm64 "0.15.16"
178 | 
179 | fsevents@~2.3.2:
180 |   version "2.3.2"
181 |   resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
182 |   integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
183 | 
184 | function-bind@^1.1.1:
185 |   version "1.1.1"
186 |   resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
187 |   integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
188 | 
189 | has@^1.0.3:
190 |   version "1.0.3"
191 |   resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
192 |   integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
193 |   dependencies:
194 |     function-bind "^1.1.1"
195 | 
196 | html-janitor@^2.0.4:
197 |   version "2.0.4"
198 |   resolved "https://registry.yarnpkg.com/html-janitor/-/html-janitor-2.0.4.tgz#ae5a115cdf3331cd5501edd7b5471b18ea44cdbb"
199 |   integrity sha512-92J5h9jNZRk30PMHapjHEJfkrBWKCOy0bq3oW2pBungky6lzYSoboBGPMvxl1XRKB2q+kniQmsLsPbdpY7RM2g==
200 | 
201 | is-core-module@^2.9.0:
202 |   version "2.11.0"
203 |   resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.11.0.tgz#ad4cb3e3863e814523c96f3f58d26cc570ff0144"
204 |   integrity sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==
205 |   dependencies:
206 |     has "^1.0.3"
207 | 
208 | nanoid@^3.1.22, nanoid@^3.3.4:
209 |   version "3.3.4"
210 |   resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
211 |   integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
212 | 
213 | path-parse@^1.0.7:
214 |   version "1.0.7"
215 |   resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
216 |   integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
217 | 
218 | picocolors@^1.0.0:
219 |   version "1.0.0"
220 |   resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
221 |   integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
222 | 
223 | postcss@^8.4.18:
224 |   version "8.4.19"
225 |   resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.19.tgz#61178e2add236b17351897c8bcc0b4c8ecab56fc"
226 |   integrity sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==
227 |   dependencies:
228 |     nanoid "^3.3.4"
229 |     picocolors "^1.0.0"
230 |     source-map-js "^1.0.2"
231 | 
232 | resolve@^1.22.1:
233 |   version "1.22.1"
234 |   resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
235 |   integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
236 |   dependencies:
237 |     is-core-module "^2.9.0"
238 |     path-parse "^1.0.7"
239 |     supports-preserve-symlinks-flag "^1.0.0"
240 | 
241 | rollup@^2.79.1:
242 |   version "2.79.1"
243 |   resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7"
244 |   integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==
245 |   optionalDependencies:
246 |     fsevents "~2.3.2"
247 | 
248 | source-map-js@^1.0.2:
249 |   version "1.0.2"
250 |   resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
251 |   integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
252 | 
253 | supports-preserve-symlinks-flag@^1.0.0:
254 |   version "1.0.0"
255 |   resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
256 |   integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
257 | 
258 | vite-plugin-css-injected-by-js@^2.1.1:
259 |   version "2.1.1"
260 |   resolved "https://registry.yarnpkg.com/vite-plugin-css-injected-by-js/-/vite-plugin-css-injected-by-js-2.1.1.tgz#a79275241c61f1c8d55d228f5b2dded450a580e4"
261 |   integrity sha512-gjIG6iFWde32oRr/bK9CsfN+jdbura2y4GlDzeOiEm6py38ud8dXzFl9zwmHjOjZdr8XEgQ9TovzVGNzp47esw==
262 | 
263 | vite@^3.1.0:
264 |   version "3.2.4"
265 |   resolved "https://registry.yarnpkg.com/vite/-/vite-3.2.4.tgz#d8c7892dd4268064e04fffbe7d866207dd24166e"
266 |   integrity sha512-Z2X6SRAffOUYTa+sLy3NQ7nlHFU100xwanq1WDwqaiFiCe+25zdxP1TfCS5ojPV2oDDcXudHIoPnI1Z/66B7Yw==
267 |   dependencies:
268 |     esbuild "^0.15.9"
269 |     postcss "^8.4.18"
270 |     resolve "^1.22.1"
271 |     rollup "^2.79.1"
272 |   optionalDependencies:
273 |     fsevents "~2.3.2"
274 | 


--------------------------------------------------------------------------------