├── .gitignore ├── LICENSE ├── README.md ├── demos ├── encoded-image │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── public │ │ └── index.html │ ├── src │ │ ├── App.tsx │ │ ├── index.tsx │ │ └── react-app-env.d.ts │ ├── tsconfig.json │ └── yarn.lock ├── offscreen-paragraph-demo │ ├── README.md │ ├── package.json │ ├── public │ │ └── index.html │ ├── src │ │ ├── App.worker.tsx │ │ ├── ParagraphDemo.tsx │ │ ├── index.tsx │ │ └── useAnimationFrame.tsx │ └── tsconfig.json ├── paragraph-demo │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── paragraph-demo.gif │ ├── public │ │ └── index.html │ ├── src │ │ ├── App.tsx │ │ ├── ParagraphDemo.tsx │ │ ├── index.tsx │ │ └── useAnimationFrame.tsx │ ├── tsconfig.json │ └── yarn.lock └── simple-paint │ ├── .gitignore │ ├── README.md │ ├── hello-react-canvaskit.png │ ├── package.json │ ├── public │ └── index.html │ ├── src │ ├── App.tsx │ ├── index.tsx │ └── react-app-env.d.ts │ └── tsconfig.json └── react-canvaskit ├── .eslintrc.js ├── .prettierrc.js ├── LICENSE ├── README.md ├── package.json ├── src ├── CkCanvas.ts ├── CkEncodedImage.ts ├── CkLine.ts ├── CkParagraph.ts ├── CkSurface.ts ├── CkText.ts ├── ReactCanvasKit.tsx ├── SkiaElementMapping.ts ├── SkiaElementTypes.ts └── index.tsx ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### JetBrains template 3 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 4 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 5 | 6 | # User-specific stuff 7 | .idea/**/workspace.xml 8 | .idea/**/tasks.xml 9 | .idea/**/usage.statistics.xml 10 | .idea/**/dictionaries 11 | .idea/**/shelf 12 | 13 | # Generated files 14 | .idea/**/contentModel.xml 15 | 16 | # Sensitive or high-churn files 17 | .idea/**/dataSources/ 18 | .idea/**/dataSources.ids 19 | .idea/**/dataSources.local.xml 20 | .idea/**/sqlDataSources.xml 21 | .idea/**/dynamic.xml 22 | .idea/**/uiDesigner.xml 23 | .idea/**/dbnavigator.xml 24 | 25 | # Gradle 26 | .idea/**/gradle.xml 27 | .idea/**/libraries 28 | 29 | # Gradle and Maven with auto-import 30 | # When using Gradle or Maven with auto-import, you should exclude module files, 31 | # since they will be recreated, and may cause churn. Uncomment if using 32 | # auto-import. 33 | # .idea/artifacts 34 | # .idea/compiler.xml 35 | # .idea/jarRepositories.xml 36 | # .idea/modules.xml 37 | # .idea/*.iml 38 | # .idea/modules 39 | # *.iml 40 | # *.ipr 41 | 42 | # CMake 43 | cmake-build-*/ 44 | 45 | # Mongo Explorer plugin 46 | .idea/**/mongoSettings.xml 47 | 48 | # File-based project format 49 | *.iws 50 | 51 | # IntelliJ 52 | out/ 53 | 54 | # mpeltonen/sbt-idea plugin 55 | .idea_modules/ 56 | 57 | # JIRA plugin 58 | atlassian-ide-plugin.xml 59 | 60 | # Cursive Clojure plugin 61 | .idea/replstate.xml 62 | 63 | # Crashlytics plugin (for Android Studio and IntelliJ) 64 | com_crashlytics_export_strings.xml 65 | crashlytics.properties 66 | crashlytics-build.properties 67 | fabric.properties 68 | 69 | # Editor-based Rest Client 70 | .idea/httpRequests 71 | 72 | # Android studio 3.1+ serialized cache file 73 | .idea/caches/build_file_checksums.ser 74 | 75 | ### Node template 76 | # Logs 77 | logs 78 | *.log 79 | npm-debug.log* 80 | yarn-debug.log* 81 | yarn-error.log* 82 | lerna-debug.log* 83 | 84 | # Diagnostic reports (https://nodejs.org/api/report.html) 85 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 86 | 87 | # Runtime data 88 | pids 89 | *.pid 90 | *.seed 91 | *.pid.lock 92 | 93 | # Directory for instrumented libs generated by jscoverage/JSCover 94 | lib-cov 95 | 96 | # Coverage directory used by tools like istanbul 97 | coverage 98 | *.lcov 99 | 100 | # nyc test coverage 101 | .nyc_output 102 | 103 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 104 | .grunt 105 | 106 | # Bower dependency directory (https://bower.io/) 107 | bower_components 108 | 109 | # node-waf configuration 110 | .lock-wscript 111 | 112 | # Compiled binary addons (https://nodejs.org/api/addons.html) 113 | build/Release 114 | 115 | # Dependency directories 116 | node_modules/ 117 | jspm_packages/ 118 | 119 | # Snowpack dependency directory (https://snowpack.dev/) 120 | web_modules/ 121 | 122 | # TypeScript cache 123 | *.tsbuildinfo 124 | 125 | # Optional npm cache directory 126 | .npm 127 | 128 | # Optional eslint cache 129 | .eslintcache 130 | 131 | # Microbundle cache 132 | .rpt2_cache/ 133 | .rts2_cache_cjs/ 134 | .rts2_cache_es/ 135 | .rts2_cache_umd/ 136 | 137 | # Optional REPL history 138 | .node_repl_history 139 | 140 | # Output of 'npm pack' 141 | *.tgz 142 | 143 | # Yarn Integrity file 144 | .yarn-integrity 145 | 146 | # dotenv environment variables file 147 | .env 148 | .env.test 149 | 150 | # parcel-bundler cache (https://parceljs.org/) 151 | .cache 152 | .parcel-cache 153 | 154 | # Next.js build output 155 | .next 156 | 157 | # Nuxt.js build / generate output 158 | .nuxt 159 | dist 160 | 161 | # Gatsby files 162 | .cache/ 163 | # Comment in the public line in if your project uses Gatsby and not Next.js 164 | # https://nextjs.org/blog/next-9-1#public-directory-support 165 | # public 166 | 167 | # vuepress build output 168 | .vuepress/dist 169 | 170 | # Serverless directories 171 | .serverless/ 172 | 173 | # FuseBox cache 174 | .fusebox/ 175 | 176 | # DynamoDB Local files 177 | .dynamodb/ 178 | 179 | # TernJS port file 180 | .tern-port 181 | 182 | # Stores VSCode versions used for testing VSCode extensions 183 | .vscode-test 184 | 185 | # yarn v2 186 | 187 | .yarn/cache 188 | .yarn/unplugged 189 | .yarn/build-state.yml 190 | .pnp.* 191 | /.idea/vcs.xml 192 | /.idea/react-canvaskit.iml 193 | /.idea/modules.xml 194 | /.idea/codeStyles/codeStyleConfig.xml 195 | /.idea/misc.xml 196 | /.idea/codeStyles/Project.xml 197 | /.idea/.gitignore 198 | /.idea/jsLibraryMappings.xml 199 | /types 200 | /docs 201 | /dist 202 | /react-canvaskit/types/ 203 | /react-canvaskit/docs/ 204 | /demos/paragraph-demo/src/react-app-env.d.ts 205 | /demos/offscreen-paragraph-demo/build 206 | /.idea 207 | /demos/offscreen-paragraph-demo/src/react-app-env.d.ts 208 | /demos/offscreen-paragraph-demo/yarn.lock 209 | /demos/simple-paint/yarn.lock 210 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 uDev.be 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # React-CanvasKit 2 | 3 | ![npm](https://img.shields.io/npm/v/react-canvaskit) 4 | 5 | Experimental implementation of [Skia CanvasKit](https://skia.org/user/modules/canvaskit) using [ReactJS](https://reactjs.org/). 6 | 7 | This implementation allows you to use all familiar React concepts like hooks and contexts, in conjunction with JXS elements that closely match the existing Skia CanvasKit API. Everything is drawn to a hardware accelerated WebGL canvas. 8 | 9 | # Examples 10 | #### Paragraph with dynamic font loading 11 | ![Alt text](/demos/paragraph-demo/paragraph-demo.gif?raw=true "Paragraph Demo") 12 | 13 | ```typescript jsx 14 | import type { FunctionComponent } from 'react' 15 | import React from 'react' 16 | import { FontManagerProvider } from 'react-canvaskit' 17 | import ParagraphDemo from './ParagraphDemo' 18 | 19 | const robotoPromise = fetch('https://storage.googleapis.com/skia-cdn/google-web-fonts/Roboto-Regular.ttf') 20 | .then((resp) => resp.arrayBuffer()) 21 | const notoColorEmojiPromise = fetch('https://storage.googleapis.com/skia-cdn/misc/NotoColorEmoji.ttf') 22 | .then((resp) => resp.arrayBuffer()) 23 | 24 | const fontsPromise = Promise.all([robotoPromise, notoColorEmojiPromise]) 25 | 26 | export const App: FunctionComponent = () => { 27 | const [fonts, setFonts] = React.useState(undefined) 28 | fontsPromise.then(fetchedFonts => setFonts(fetchedFonts)) 29 | 30 | return ( 31 | 32 | 33 | 34 | ) 35 | } 36 | ``` 37 | 38 | ```typescript jsx 39 | import type { SkParagraph } from 'canvaskit-oc' 40 | import React from 'react' 41 | import type { SkObjectRef } from 'react-canvaskit' 42 | import { PaintStyle, TextAlignEnum, useFontManager } from 'react-canvaskit' 43 | import useAnimationFrame from './useAnimationFrame' 44 | 45 | const fontPaint = { style: PaintStyle.Fill, antiAlias: true } 46 | 47 | const X = 250 48 | const Y = 250 49 | const paragraphText = 'The quick brown fox 🦊 ate a zesty hamburgerfonts 🍔.\nThe 👩‍👩‍👧‍👧 laughed.' 50 | 51 | export default () => { 52 | const skParagraphRef = React.useRef>(null) 53 | const fontManager = useFontManager() 54 | 55 | const calcWrapTo = (time: number): number => 350 + 150 * Math.sin(time / 2000) 56 | const [wrapTo, setWrapTo] = React.useState(calcWrapTo(performance.now())) 57 | 58 | useAnimationFrame(time => setWrapTo(calcWrapTo(time))) 59 | 60 | return ( 61 | 62 | 76 | {paragraphText} 77 | 78 | 79 | {`At (${X.toFixed(2)}, ${Y.toFixed(2)}) glyph is '${glyph}'`} 81 | 82 | ) 83 | } 84 | ``` 85 | 86 | #### Simple Paint 87 | ![Alt text](/demos/simple-paint/hello-react-canvaskit.png?raw=true "Hello React-CanvasKit!") 88 | 89 | ```typescript jsx 90 | const App: FunctionComponent = () => { 91 | return ( 92 | 93 | 94 | Hello React-CanvasKit! 95 | 96 | 97 | 98 | React-CanvasKit. 99 | 101 | 102 | 103 | 104 | ) 105 | } 106 | 107 | const htmlCanvasElement = document.createElement('canvas') 108 | const rootElement = document.getElementById('root') 109 | if (rootElement === null) { 110 | throw new Error('No root element defined.') 111 | } 112 | rootElement.appendChild(htmlCanvasElement) 113 | document.body.appendChild(htmlCanvasElement) 114 | htmlCanvasElement.width = 400 115 | htmlCanvasElement.height = 300 116 | 117 | init().then(() => render(, htmlCanvasElement)) 118 | ``` 119 | -------------------------------------------------------------------------------- /demos/encoded-image/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /demos/encoded-image/README.md: -------------------------------------------------------------------------------- 1 | # Build 2 | - `yarn install` 3 | # Run 4 | - `yarn start` 5 | -------------------------------------------------------------------------------- /demos/encoded-image/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "encoded-image", 3 | "version": "0.0.0", 4 | "private": true, 5 | "dependencies": { 6 | "canvaskit-wasm": "0.32.0", 7 | "react": "17.0.2", 8 | "react-canvaskit": "link:../../react-canvaskit", 9 | "react-scripts": "4.0.3" 10 | }, 11 | "devDependencies": { 12 | "@types/react": "^17.0.38", 13 | "typescript": "4.5.4" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts start", 17 | "build": "react-scripts build", 18 | "test": "react-scripts test", 19 | "eject": "react-scripts eject" 20 | }, 21 | "eslintConfig": { 22 | "extends": "react-app" 23 | }, 24 | "browserslist": { 25 | "production": [ 26 | ">0.2%", 27 | "not dead", 28 | "not op_mini all" 29 | ], 30 | "development": [ 31 | "last 1 chrome version", 32 | "last 1 firefox version", 33 | "last 1 safari version" 34 | ] 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /demos/encoded-image/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | React-CanvasKit Simple Paint Demo 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /demos/encoded-image/src/App.tsx: -------------------------------------------------------------------------------- 1 | import type { FunctionComponent } from "react"; 2 | import React, { useState } from "react"; 3 | 4 | const imageDataPromise = fetch( 5 | "https://upload.wikimedia.org/wikipedia/commons/thumb/6/6a/PNG_Test.png/191px-PNG_Test.png" 6 | ).then((resp) => resp.arrayBuffer()); 7 | 8 | export const App: FunctionComponent = () => { 9 | const [imageBytes, setImageBytes] = useState(null); 10 | imageDataPromise.then((imageData) => setImageBytes(imageData)); 11 | 12 | return imageBytes ? ( 13 | 14 | 15 | 16 | ) : null; 17 | }; 18 | -------------------------------------------------------------------------------- /demos/encoded-image/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { init, render } from "react-canvaskit"; 3 | import { App } from "./App"; 4 | 5 | const htmlCanvasElement = document.createElement("canvas"); 6 | const rootElement = document.getElementById("root"); 7 | if (rootElement === null) { 8 | throw new Error("No root element defined."); 9 | } 10 | rootElement.appendChild(htmlCanvasElement); 11 | document.body.appendChild(htmlCanvasElement); 12 | htmlCanvasElement.width = 400; 13 | htmlCanvasElement.height = 300; 14 | 15 | init().then(() => render(, htmlCanvasElement)); 16 | -------------------------------------------------------------------------------- /demos/encoded-image/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /demos/encoded-image/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /demos/offscreen-paragraph-demo/README.md: -------------------------------------------------------------------------------- 1 | # Build 2 | - `yarn install` 3 | # Run 4 | - `yarn start` 5 | 6 | Create-react-app has a bug with babel-loader processing node_modules, so running a dev server might fail. If this is 7 | the case for you, you can try doing a production build instead. 8 | 9 | - `yarn build` 10 | - `yarn global add serve` 11 | - `serve -s build` 12 | -------------------------------------------------------------------------------- /demos/offscreen-paragraph-demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "offscreen-paragraph-demo", 3 | "version": "0.0.0", 4 | "private": true, 5 | "dependencies": { 6 | "canvaskit-wasm": "0.32.0", 7 | "react": "17.0.2", 8 | "react-canvaskit": "link:../../react-canvaskit", 9 | "react-scripts": "4.0.3" 10 | }, 11 | "devDependencies": { 12 | "@types/react": "^17.0.38", 13 | "typescript": "4.5.4", 14 | "worker-loader": "^3.0.8" 15 | }, 16 | "scripts": { 17 | "start": "react-scripts start", 18 | "build": "react-scripts build", 19 | "test": "react-scripts test", 20 | "eject": "react-scripts eject" 21 | }, 22 | "eslintConfig": { 23 | "extends": "react-app" 24 | }, 25 | "browserslist": { 26 | "production": [ 27 | ">0.2%", 28 | "not dead", 29 | "not op_mini all" 30 | ], 31 | "development": [ 32 | "last 1 chrome version", 33 | "last 1 firefox version", 34 | "last 1 safari version" 35 | ] 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /demos/offscreen-paragraph-demo/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | React-CanvasKit Paragraph Demo 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /demos/offscreen-paragraph-demo/src/App.worker.tsx: -------------------------------------------------------------------------------- 1 | import type { FunctionComponent } from "react"; 2 | import React from "react"; 3 | import { FontManagerProvider, init, render } from "react-canvaskit"; 4 | import ParagraphDemo from "./ParagraphDemo"; 5 | 6 | const robotoPromise = fetch( 7 | "https://storage.googleapis.com/skia-cdn/google-web-fonts/Roboto-Regular.ttf" 8 | ).then((resp) => resp.arrayBuffer()); 9 | const notoColorEmojiPromise = fetch( 10 | "https://storage.googleapis.com/skia-cdn/misc/NotoColorEmoji.ttf" 11 | ).then((resp) => resp.arrayBuffer()); 12 | const fontsPromise = Promise.all([robotoPromise, notoColorEmojiPromise]); 13 | 14 | const App: FunctionComponent = () => { 15 | const [fonts, setFonts] = React.useState( 16 | undefined 17 | ); 18 | fontsPromise.then((fetchedFonts) => setFonts(fetchedFonts)); 19 | return ( 20 | 21 | 22 | 23 | ); 24 | }; 25 | 26 | onmessage = async (e: MessageEvent) => { 27 | const offscreenCanvas = e.data.canvas; 28 | await init(); 29 | render(, offscreenCanvas); 30 | }; 31 | -------------------------------------------------------------------------------- /demos/offscreen-paragraph-demo/src/ParagraphDemo.tsx: -------------------------------------------------------------------------------- 1 | import type { Paragraph as SkParagraph } from "canvaskit-wasm"; 2 | import React from "react"; 3 | import { PaintStyle, TextAlignEnum, useFontManager } from "react-canvaskit"; 4 | import useAnimationFrame from "./useAnimationFrame"; 5 | 6 | const fontPaint = { style: PaintStyle.Fill, antiAlias: true }; 7 | 8 | const X = 250; 9 | const Y = 250; 10 | const paragraphText = 11 | "The quick brown fox 🦊 ate a zesty hamburgerfonts 🍔.\nThe 👩‍👩‍👧‍👧 laughed."; 12 | 13 | export default () => { 14 | const skParagraphRef = React.useRef(null); 15 | const fontManager = useFontManager(); 16 | 17 | const calcWrapTo = (time: number): number => 18 | 350 + 150 * Math.sin(time / 2000); 19 | const [wrapTo, setWrapTo] = React.useState(calcWrapTo(performance.now())); 20 | 21 | useAnimationFrame((time) => setWrapTo(calcWrapTo(time))); 22 | 23 | const posA = skParagraphRef.current?.getGlyphPositionAtCoordinate(X, Y); 24 | let glyph; 25 | if (posA) { 26 | const cp = paragraphText.codePointAt(posA.pos); 27 | if (cp) { 28 | glyph = String.fromCodePoint(cp); 29 | } 30 | } 31 | 32 | return ( 33 | 34 | 48 | {paragraphText} 49 | 50 | 51 | {`At (${X.toFixed( 52 | 2 53 | )}, ${Y.toFixed(2)}) glyph is '${glyph}'`} 54 | 55 | ); 56 | }; 57 | -------------------------------------------------------------------------------- /demos/offscreen-paragraph-demo/src/index.tsx: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | // eslint-disable-next-line import/no-webpack-loader-syntax 3 | import workerApp from 'worker-loader!./App.worker' 4 | 5 | const htmlCanvasElement = document.createElement("canvas"); 6 | const rootElement = document.getElementById("root"); 7 | if (rootElement === null) { 8 | throw new Error("No root element defined."); 9 | } 10 | rootElement.appendChild(htmlCanvasElement); 11 | document.body.appendChild(rootElement); 12 | htmlCanvasElement.width = 800; 13 | htmlCanvasElement.height = 600; 14 | 15 | // @ts-ignore 16 | const offscreenCanvas = htmlCanvasElement.transferControlToOffscreen(); 17 | 18 | workerApp().postMessage({ canvas: offscreenCanvas }, [offscreenCanvas]); 19 | -------------------------------------------------------------------------------- /demos/offscreen-paragraph-demo/src/useAnimationFrame.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export default (callback: (time: number) => void) => { 4 | // Use useRef for mutable variables that we want to persist 5 | // without triggering a re-render on their change 6 | const requestRef = React.useRef(); 7 | 8 | const animate = (time: number) => { 9 | callback(time); 10 | requestRef.current = requestAnimationFrame(animate); 11 | }; 12 | 13 | React.useEffect(() => { 14 | requestRef.current = requestAnimationFrame(animate); 15 | return () => { 16 | if (requestRef.current) { 17 | cancelAnimationFrame(requestRef.current); 18 | } 19 | }; 20 | }, []); // Make sure the effect runs only once 21 | }; 22 | -------------------------------------------------------------------------------- /demos/offscreen-paragraph-demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /demos/paragraph-demo/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /demos/paragraph-demo/README.md: -------------------------------------------------------------------------------- 1 | # Build 2 | - `yarn install` 3 | # Run 4 | - `yarn start` 5 | -------------------------------------------------------------------------------- /demos/paragraph-demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "paragraph-demo", 3 | "version": "0.0.0", 4 | "private": true, 5 | "dependencies": { 6 | "canvaskit-wasm": "0.32.0", 7 | "react": "17.0.2", 8 | "react-canvaskit": "link: ../../react-canvaskit", 9 | "react-scripts": "4.0.3" 10 | }, 11 | "devDependencies": { 12 | "@types/react": "^17.0.38", 13 | "typescript": "4.5.4" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts start", 17 | "build": "react-scripts build", 18 | "test": "react-scripts test", 19 | "eject": "react-scripts eject" 20 | }, 21 | "browserslist": { 22 | "production": [ 23 | ">0.2%", 24 | "not dead", 25 | "not op_mini all" 26 | ], 27 | "development": [ 28 | "last 1 chrome version", 29 | "last 1 firefox version", 30 | "last 1 safari version" 31 | ] 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /demos/paragraph-demo/paragraph-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udevbe/react-canvaskit/7195cd2b8ebe1825c3f3d03bc2ac2749b5cdc9e7/demos/paragraph-demo/paragraph-demo.gif -------------------------------------------------------------------------------- /demos/paragraph-demo/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | React-CanvasKit Paragraph Demo 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /demos/paragraph-demo/src/App.tsx: -------------------------------------------------------------------------------- 1 | import type { FunctionComponent } from "react"; 2 | import React from "react"; 3 | import { FontManagerProvider } from "react-canvaskit"; 4 | import ParagraphDemo from "./ParagraphDemo"; 5 | 6 | const robotoPromise = fetch( 7 | "https://storage.googleapis.com/skia-cdn/google-web-fonts/Roboto-Regular.ttf" 8 | ).then((resp) => resp.arrayBuffer()); 9 | const notoColorEmojiPromise = fetch( 10 | "https://storage.googleapis.com/skia-cdn/misc/NotoColorEmoji.ttf" 11 | ).then((resp) => resp.arrayBuffer()); 12 | 13 | const fontsPromise = Promise.all([robotoPromise, notoColorEmojiPromise]); 14 | 15 | export const App: FunctionComponent = () => { 16 | const [fonts, setFonts] = React.useState( 17 | undefined 18 | ); 19 | fontsPromise.then((fetchedFonts) => setFonts(fetchedFonts)); 20 | 21 | return ( 22 | 23 | 24 | 25 | ); 26 | }; 27 | -------------------------------------------------------------------------------- /demos/paragraph-demo/src/ParagraphDemo.tsx: -------------------------------------------------------------------------------- 1 | import type { Paragraph as SkParagraph } from "canvaskit-wasm"; 2 | import React from "react"; 3 | import { PaintStyle, TextAlignEnum, useFontManager } from "react-canvaskit"; 4 | import useAnimationFrame from "./useAnimationFrame"; 5 | 6 | const fontPaint = { style: PaintStyle.Fill, antiAlias: true }; 7 | 8 | const X = 250; 9 | const Y = 250; 10 | const paragraphText = 11 | "The quick brown fox 🦊 ate a zesty hamburgerfonts 🍔.\nThe 👩‍👩‍👧‍👧 laughed."; 12 | 13 | export default () => { 14 | const skParagraphRef = React.useRef(null); 15 | const fontManager = useFontManager(); 16 | 17 | const calcWrapTo = (time: number): number => 18 | 350 + 150 * Math.sin(time / 2000); 19 | const [wrapTo, setWrapTo] = React.useState(calcWrapTo(performance.now())); 20 | 21 | useAnimationFrame((time) => setWrapTo(calcWrapTo(time))); 22 | 23 | const posA = skParagraphRef.current?.getGlyphPositionAtCoordinate(X, Y); 24 | let glyph; 25 | if (posA) { 26 | const cp = paragraphText.codePointAt(posA.pos); 27 | if (cp) { 28 | glyph = String.fromCodePoint(cp); 29 | } 30 | } 31 | 32 | return ( 33 | 34 | 48 | {paragraphText} 49 | 50 | 51 | {`At (${X.toFixed( 52 | 2 53 | )}, ${Y.toFixed(2)}) glyph is '${glyph}'`} 54 | 55 | ); 56 | }; 57 | -------------------------------------------------------------------------------- /demos/paragraph-demo/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { init, render } from "react-canvaskit"; 3 | import { App } from "./App"; 4 | 5 | const htmlCanvasElement = document.createElement("canvas"); 6 | const rootElement = document.getElementById("root"); 7 | if (rootElement === null) { 8 | throw new Error("No root element defined."); 9 | } 10 | rootElement.appendChild(htmlCanvasElement); 11 | document.body.appendChild(htmlCanvasElement); 12 | htmlCanvasElement.width = 800; 13 | htmlCanvasElement.height = 600; 14 | 15 | init().then(() => render(, htmlCanvasElement)); 16 | -------------------------------------------------------------------------------- /demos/paragraph-demo/src/useAnimationFrame.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export default (callback: (time: number) => void) => { 4 | // Use useRef for mutable variables that we want to persist 5 | // without triggering a re-render on their change 6 | const requestRef = React.useRef(); 7 | 8 | const animate = (time: number) => { 9 | callback(time); 10 | requestRef.current = requestAnimationFrame(animate); 11 | }; 12 | 13 | React.useEffect(() => { 14 | requestRef.current = requestAnimationFrame(animate); 15 | return () => { 16 | if (requestRef.current) { 17 | cancelAnimationFrame(requestRef.current); 18 | } 19 | }; 20 | }, []); // Make sure the effect runs only once 21 | }; 22 | -------------------------------------------------------------------------------- /demos/paragraph-demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /demos/simple-paint/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /demos/simple-paint/README.md: -------------------------------------------------------------------------------- 1 | # Build 2 | - `yarn install` 3 | # Run 4 | - `yarn start` 5 | -------------------------------------------------------------------------------- /demos/simple-paint/hello-react-canvaskit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udevbe/react-canvaskit/7195cd2b8ebe1825c3f3d03bc2ac2749b5cdc9e7/demos/simple-paint/hello-react-canvaskit.png -------------------------------------------------------------------------------- /demos/simple-paint/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple-paint", 3 | "version": "0.0.0", 4 | "private": true, 5 | "dependencies": { 6 | "canvaskit-wasm": "0.32.0", 7 | "react": "17.0.2", 8 | "react-canvaskit": "link:../../react-canvaskit", 9 | "react-scripts": "4.0.3" 10 | }, 11 | "devDependencies": { 12 | "@types/react": "^17.0.38", 13 | "typescript": "4.5.4" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts start", 17 | "build": "react-scripts build", 18 | "test": "react-scripts test", 19 | "eject": "react-scripts eject" 20 | }, 21 | "eslintConfig": { 22 | "extends": "react-app" 23 | }, 24 | "browserslist": { 25 | "production": [ 26 | ">0.2%", 27 | "not dead", 28 | "not op_mini all" 29 | ], 30 | "development": [ 31 | "last 1 chrome version", 32 | "last 1 firefox version", 33 | "last 1 safari version" 34 | ] 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /demos/simple-paint/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | React-CanvasKit Simple Paint Demo 8 | 9 | 10 | 11 |
12 | 13 | 14 | -------------------------------------------------------------------------------- /demos/simple-paint/src/App.tsx: -------------------------------------------------------------------------------- 1 | import type { FunctionComponent } from "react"; 2 | import React from "react"; 3 | 4 | export const App: FunctionComponent = () => { 5 | return ( 6 | 7 | 13 | Hello React-CanvasKit! 14 | 15 | 16 | 17 | React-CanvasKit. 18 | 25 | 26 | 27 | 28 | ); 29 | }; 30 | -------------------------------------------------------------------------------- /demos/simple-paint/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { init, render } from "react-canvaskit"; 3 | import { App } from "./App"; 4 | 5 | const htmlCanvasElement = document.createElement("canvas"); 6 | const rootElement = document.getElementById("root"); 7 | if (rootElement === null) { 8 | throw new Error("No root element defined."); 9 | } 10 | rootElement.appendChild(htmlCanvasElement); 11 | document.body.appendChild(htmlCanvasElement); 12 | htmlCanvasElement.width = 400; 13 | htmlCanvasElement.height = 300; 14 | 15 | init().then(() => render(, htmlCanvasElement)); 16 | -------------------------------------------------------------------------------- /demos/simple-paint/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /demos/simple-paint/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "esnext" 8 | ], 9 | "allowJs": true, 10 | "skipLibCheck": true, 11 | "esModuleInterop": true, 12 | "allowSyntheticDefaultImports": true, 13 | "strict": true, 14 | "forceConsistentCasingInFileNames": true, 15 | "noFallthroughCasesInSwitch": true, 16 | "module": "esnext", 17 | "moduleResolution": "node", 18 | "resolveJsonModule": true, 19 | "isolatedModules": true, 20 | "noEmit": true, 21 | "jsx": "react-jsx" 22 | }, 23 | "include": [ 24 | "src" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /react-canvaskit/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', // Specifies the ESLint parser 3 | parserOptions: { 4 | ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features 5 | sourceType: 'module', // Allows for the use of imports 6 | ecmaFeatures: { 7 | jsx: false, 8 | }, 9 | }, 10 | extends: [ 11 | 'plugin:@typescript-eslint/recommended', // Uses the recommended rules from @typescript-eslint/eslint-plugin, 12 | 'plugin:prettier/recommended', // Enables eslint-plugin-prettier and eslint-config-prettier. This will display prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array. 13 | ], 14 | rules: { 15 | // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs 16 | '@typescript-eslint/ban-ts-comment': 'warn', 17 | }, 18 | } 19 | -------------------------------------------------------------------------------- /react-canvaskit/.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: false, 3 | trailingComma: 'all', 4 | singleQuote: true, 5 | printWidth: 120, 6 | } 7 | -------------------------------------------------------------------------------- /react-canvaskit/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Erik De Rijcke 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 | -------------------------------------------------------------------------------- /react-canvaskit/README.md: -------------------------------------------------------------------------------- 1 | # React-CanvasKit 2 | 3 | ![npm](https://img.shields.io/npm/v/react-canvaskit) 4 | 5 | Experimental implementation of [Skia CanvasKit](https://skia.org/user/modules/canvaskit) using [ReactJS](https://reactjs.org/). 6 | 7 | This implementation allows you to use all familiar React concepts like hooks and contexts, in conjunction with JXS elements that closely match the existing Skia CanvasKit API. Everything is drawn to a hardware accelerated WebGL canvas. 8 | 9 | #Examples 10 | #### Simple Paint 11 | ![Alt text](/demos/simple-paint/hello-react-canvaskit.png?raw=true "Hello React-CanvasKit!") 12 | 13 | ```typescript jsx 14 | const App: FunctionComponent = () => { 15 | return ( 16 | 17 | 18 | Hello React-CanvasKit! 19 | 20 | 21 | 22 | React-CanvasKit. 23 | 25 | 26 | 27 | 28 | ) 29 | } 30 | 31 | const htmlCanvasElement = document.createElement('canvas') 32 | const rootElement = document.getElementById('root') 33 | if (rootElement === null) { 34 | throw new Error('No root element defined.') 35 | } 36 | rootElement.appendChild(htmlCanvasElement) 37 | document.body.appendChild(htmlCanvasElement) 38 | htmlCanvasElement.width = 400 39 | htmlCanvasElement.height = 300 40 | 41 | init().then(() => render(, htmlCanvasElement)) 42 | ``` 43 | 44 | #### Paragraph with dynamic font loading 45 | ![Alt text](/demos/paragraph-demo/paragraph-demo.gif?raw=true "Paragraph Demo") 46 | 47 | ```typescript jsx 48 | import type { FunctionComponent } from 'react' 49 | import React from 'react' 50 | import { FontManagerProvider } from 'react-canvaskit' 51 | import ParagraphDemo from './ParagraphDemo' 52 | 53 | const robotoPromise = fetch('https://storage.googleapis.com/skia-cdn/google-web-fonts/Roboto-Regular.ttf') 54 | .then((resp) => resp.arrayBuffer()) 55 | const notoColorEmojiPromise = fetch('https://storage.googleapis.com/skia-cdn/misc/NotoColorEmoji.ttf') 56 | .then((resp) => resp.arrayBuffer()) 57 | 58 | const fontsPromise = Promise.all([robotoPromise, notoColorEmojiPromise]) 59 | 60 | export const App: FunctionComponent = () => { 61 | const [fonts, setFonts] = React.useState(undefined) 62 | fontsPromise.then(fetchedFonts => setFonts(fetchedFonts)) 63 | 64 | return ( 65 | 66 | 67 | 68 | ) 69 | } 70 | ``` 71 | 72 | ```typescript jsx 73 | import type { SkParagraph } from 'canvaskit-oc' 74 | import React from 'react' 75 | import type { SkObjectRef } from 'react-canvaskit' 76 | import { PaintStyle, TextAlignEnum, useFontManager } from 'react-canvaskit' 77 | import useAnimationFrame from './useAnimationFrame' 78 | 79 | const fontPaint = { style: PaintStyle.Fill, antiAlias: true } 80 | 81 | const X = 250 82 | const Y = 250 83 | const paragraphText = 'The quick brown fox 🦊 ate a zesty hamburgerfonts 🍔.\nThe 👩‍👩‍👧‍👧 laughed.' 84 | 85 | export default () => { 86 | const skParagraphRef = React.useRef>(null) 87 | const fontManager = useFontManager() 88 | 89 | const calcWrapTo = (time: number): number => 350 + 150 * Math.sin(time / 2000) 90 | const [wrapTo, setWrapTo] = React.useState(calcWrapTo(performance.now())) 91 | 92 | useAnimationFrame(time => setWrapTo(calcWrapTo(time))) 93 | 94 | return ( 95 | 96 | 110 | {paragraphText} 111 | 112 | 113 | {`At (${X.toFixed(2)}, ${Y.toFixed(2)}) glyph is '${glyph}'`} 115 | 116 | ) 117 | } 118 | ``` 119 | -------------------------------------------------------------------------------- /react-canvaskit/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-canvaskit", 3 | "version": "0.0.1-alpha.8", 4 | "description": "A React implementation of the Skia-CanvasKit drawing library.", 5 | "keywords": [ 6 | "react", 7 | "reactjs", 8 | "skia", 9 | "skia-library", 10 | "canvas", 11 | "webgl", 12 | "html5-canvas", 13 | "html5", 14 | "react-reconciler", 15 | "canvaskit", 16 | "accelerated", 17 | "hardware-acceleration" 18 | ], 19 | "main": "dist/index.js", 20 | "typings": "types/index.d.ts", 21 | "files": [ 22 | "dist", 23 | "types" 24 | ], 25 | "scripts": { 26 | "prebuild": "rimraf dist types", 27 | "build": "tsc", 28 | "test": "jest --coverage", 29 | "test:watch": "jest --coverage --watch", 30 | "test:prod": "yarn test -- --no-cache" 31 | }, 32 | "dependencies": { 33 | "react-reconciler": "0.26.2" 34 | }, 35 | "peerDependencies": { 36 | "canvaskit-wasm": "0.32.0", 37 | "react": "17.0.2" 38 | }, 39 | "devDependencies": { 40 | "@types/node": "^16.4.1", 41 | "@types/react-reconciler": "^0.26.3", 42 | "canvaskit-wasm": "0.32.0", 43 | "prettier": "^2.5.1", 44 | "react-devtools": "^4.14.0", 45 | "rimraf": "^3.0.2", 46 | "ts-jest": "^27.1.2", 47 | "ts-node": "^10.1.0", 48 | "typescript": "^4.3.5" 49 | }, 50 | "author": "Erik De Rijcke", 51 | "homepage": "https://github.com/udevbe/react-canvaskit", 52 | "license": "MIT", 53 | "repository": { 54 | "type": "git", 55 | "url": "https://github.com/udevbe/react-canvaskit" 56 | }, 57 | "engines": { 58 | "node": ">=14.0.0" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /react-canvaskit/src/CkCanvas.ts: -------------------------------------------------------------------------------- 1 | import type { Canvas as SkCanvas, CanvasKit } from 'canvaskit-wasm' 2 | import type { ReactNode } from 'react' 3 | import { isCkSurface } from './CkSurface' 4 | import { toSkColor } from './SkiaElementMapping' 5 | import { 6 | CkElement, 7 | CkElementContainer, 8 | CkElementCreator, 9 | CkElementProps, 10 | CkObjectTyping, 11 | Color, 12 | } from './SkiaElementTypes' 13 | 14 | export interface CkCanvasProps extends CkElementProps { 15 | clear?: Color | string 16 | rotate?: { degree: number; px?: number; py?: number } 17 | children?: ReactNode 18 | } 19 | 20 | type CkCanvasChild = CkElement<'ck-surface'> | CkElement<'ck-text'> 21 | 22 | export class CkCanvas implements CkElementContainer<'ck-canvas'> { 23 | readonly canvasKit: CanvasKit 24 | readonly props: CkObjectTyping['ck-canvas']['props'] 25 | skObject?: CkObjectTyping['ck-canvas']['type'] 26 | readonly skObjectType: CkObjectTyping['ck-canvas']['name'] = 'SkCanvas' 27 | readonly type: 'ck-canvas' = 'ck-canvas' 28 | children: CkCanvasChild[] = [] 29 | 30 | private deleted = false 31 | 32 | constructor(canvasKit: CanvasKit, props: CkObjectTyping['ck-canvas']['props']) { 33 | this.canvasKit = canvasKit 34 | this.props = props 35 | } 36 | 37 | render(parent: CkElementContainer): void { 38 | if (this.deleted) { 39 | throw new Error('BUG. canvas element deleted.') 40 | } 41 | 42 | if (parent.skObject && isCkSurface(parent)) { 43 | if (this.skObject === undefined) { 44 | this.skObject = parent.skObject.getCanvas() 45 | } 46 | } else { 47 | throw new Error('Expected an initialized ck-surface as parent of ck-canvas') 48 | } 49 | 50 | this.skObject.save() 51 | this.drawSelf(this.skObject) 52 | this.children.forEach((child) => child.render(this)) 53 | this.skObject.restore() 54 | parent.skObject?.flush() 55 | } 56 | 57 | private drawSelf(skCanvas: SkCanvas) { 58 | const skColor = toSkColor(this.canvasKit, this.props.clear) 59 | if (skColor) { 60 | skCanvas.clear(skColor) 61 | } 62 | 63 | if (this.props.rotate) { 64 | const { degree, px, py } = this.props.rotate 65 | skCanvas.rotate(degree, px ?? 0, py ?? 0) 66 | } 67 | } 68 | 69 | delete() { 70 | if (this.deleted) { 71 | return 72 | } 73 | this.deleted = true 74 | // The canvas object is 1-to-1 linked to the parent surface object, so deleting it means we could never recreate it. 75 | // this.skObject?.delete() 76 | this.skObject = undefined 77 | } 78 | } 79 | 80 | export function isCkCanvas(ckElement: CkElement): ckElement is CkCanvas { 81 | return ckElement.type === 'ck-canvas' 82 | } 83 | 84 | export const createCkCanvas: CkElementCreator<'ck-canvas'> = ( 85 | type, 86 | props, 87 | canvasKit: CanvasKit, 88 | ): CkElementContainer<'ck-canvas'> => new CkCanvas(canvasKit, props) 89 | -------------------------------------------------------------------------------- /react-canvaskit/src/CkEncodedImage.ts: -------------------------------------------------------------------------------- 1 | import { CanvasKit, Image as SkImage, Paint as SkPaint } from 'canvaskit-wasm' 2 | import { isCkCanvas } from './CkCanvas' 3 | import { toSkPaint } from './SkiaElementMapping' 4 | import { 5 | CkElement, 6 | CkElementContainer, 7 | CkElementCreator, 8 | CkElementProps, 9 | CkObjectTyping, 10 | Paint, 11 | } from './SkiaElementTypes' 12 | 13 | export interface CkEncodedImageProps extends CkElementProps { 14 | left: number 15 | top: number 16 | bytes: Uint8Array | ArrayBuffer 17 | paint?: Paint 18 | } 19 | 20 | class CkEncodedImage implements CkElement<'ck-encoded-image'> { 21 | readonly skObjectType: CkObjectTyping['ck-encoded-image']['name'] = 'SkImage' 22 | readonly type: 'ck-encoded-image' = 'ck-encoded-image' 23 | deleted = false 24 | 25 | private readonly defaultPaint: SkPaint 26 | private renderPaint?: SkPaint 27 | 28 | private image?: SkImage 29 | 30 | constructor(readonly canvasKit: CanvasKit, readonly props: CkObjectTyping['ck-encoded-image']['props']) { 31 | this.defaultPaint = new this.canvasKit.Paint() 32 | this.defaultPaint.setStyle(this.canvasKit.PaintStyle.Fill) 33 | this.defaultPaint.setAntiAlias(true) 34 | } 35 | 36 | delete(): void { 37 | if (this.deleted) { 38 | return 39 | } 40 | 41 | this.image?.delete() 42 | this.defaultPaint.delete() 43 | this.renderPaint?.delete() 44 | this.deleted = true 45 | } 46 | 47 | render(parent: CkElementContainer): void { 48 | if (this.deleted) { 49 | throw new Error('BUG. line element deleted.') 50 | } 51 | 52 | if (parent && isCkCanvas(parent)) { 53 | this.image = this.canvasKit.MakeImageFromEncoded(this.props.bytes) ?? undefined 54 | if (this.image) { 55 | this.renderPaint?.delete() 56 | this.renderPaint = toSkPaint(this.canvasKit, this.props.paint) 57 | parent.skObject?.drawImage(this.image, this.props.left, this.props.top, this.renderPaint ?? this.defaultPaint) 58 | } 59 | } 60 | } 61 | } 62 | 63 | export const createCkEncodedImage: CkElementCreator<'ck-encoded-image'> = (type, props, canvasKit) => 64 | new CkEncodedImage(canvasKit, props) 65 | -------------------------------------------------------------------------------- /react-canvaskit/src/CkLine.ts: -------------------------------------------------------------------------------- 1 | import type { CanvasKit, Paint as SkPaint } from 'canvaskit-wasm' 2 | import { isCkCanvas } from './CkCanvas' 3 | import { toSkPaint } from './SkiaElementMapping' 4 | import { 5 | CkElement, 6 | CkElementContainer, 7 | CkElementCreator, 8 | CkElementProps, 9 | CkObjectTyping, 10 | Paint, 11 | } from './SkiaElementTypes' 12 | 13 | export interface CkLineProps extends CkElementProps { 14 | x1: number 15 | y1: number 16 | x2: number 17 | y2: number 18 | paint?: Paint 19 | } 20 | 21 | class CkLine implements CkElement<'ck-line'> { 22 | readonly skObjectType: CkObjectTyping['ck-line']['name'] = 'Line' 23 | readonly type: 'ck-line' = 'ck-line' 24 | 25 | private readonly defaultPaint: SkPaint 26 | private renderPaint?: SkPaint 27 | deleted = false 28 | 29 | constructor(readonly canvasKit: CanvasKit, readonly props: CkObjectTyping['ck-line']['props']) { 30 | this.defaultPaint = new this.canvasKit.Paint() 31 | this.defaultPaint.setStyle(this.canvasKit.PaintStyle.Fill) 32 | this.defaultPaint.setAntiAlias(true) 33 | } 34 | 35 | render(parent: CkElementContainer): void { 36 | if (this.deleted) { 37 | throw new Error('BUG. line element deleted.') 38 | } 39 | if (parent && isCkCanvas(parent)) { 40 | // TODO we can be smart and only recreate the paint object if the paint props have changed? 41 | this.renderPaint?.delete() 42 | this.renderPaint = toSkPaint(this.canvasKit, this.props.paint) 43 | parent.skObject?.drawLine( 44 | this.props.x1, 45 | this.props.y1, 46 | this.props.x2, 47 | this.props.y2, 48 | this.renderPaint ?? this.defaultPaint, 49 | ) 50 | } 51 | } 52 | 53 | delete() { 54 | if (this.deleted) { 55 | return 56 | } 57 | this.deleted = true 58 | this.defaultPaint.delete() 59 | this.renderPaint?.delete() 60 | } 61 | } 62 | 63 | export const createCkLine: CkElementCreator<'ck-line'> = (type, props, canvasKit) => new CkLine(canvasKit, props) 64 | -------------------------------------------------------------------------------- /react-canvaskit/src/CkParagraph.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | CanvasKit, 3 | FontMgr as SkFontManager, 4 | Paragraph as SkParagraph, 5 | ParagraphStyle as SkParagraphStyle, 6 | } from 'canvaskit-wasm' 7 | import { isCkCanvas } from './CkCanvas' 8 | import { toSkParagraphStyle } from './SkiaElementMapping' 9 | import { 10 | CkElement, 11 | CkElementContainer, 12 | CkElementCreator, 13 | CkElementProps, 14 | CkObjectTyping, 15 | ParagraphStyle, 16 | } from './SkiaElementTypes' 17 | 18 | export interface CkParagraphProps extends ParagraphStyle, CkElementProps { 19 | layout: number 20 | fontManager: SkFontManager 21 | x?: number 22 | y?: number 23 | children?: string 24 | } 25 | 26 | class CkParagraph implements CkElement<'ck-paragraph'> { 27 | readonly canvasKit: CanvasKit 28 | readonly props: CkObjectTyping['ck-paragraph']['props'] 29 | skObject?: CkObjectTyping['ck-paragraph']['type'] 30 | readonly skObjectType: CkObjectTyping['ck-paragraph']['name'] = 'SkParagraph' 31 | readonly type: 'ck-paragraph' = 'ck-paragraph' 32 | 33 | deleted = false 34 | 35 | constructor(canvasKit: CanvasKit, props: CkObjectTyping['ck-paragraph']['props']) { 36 | this.canvasKit = canvasKit 37 | this.props = props 38 | } 39 | 40 | render(parent: CkElementContainer): void { 41 | if (this.deleted) { 42 | throw new Error('BUG. paragraph element deleted.') 43 | } 44 | 45 | const skParagraphBuilder = this.canvasKit.ParagraphBuilder.Make( 46 | toSkParagraphStyle(this.canvasKit, this.props), 47 | this.props.fontManager, 48 | ) 49 | if (this.props.children) { 50 | skParagraphBuilder.addText(this.props.children) 51 | } 52 | this.skObject?.delete() 53 | this.skObject = skParagraphBuilder.build() 54 | this.skObject.layout(this.props.layout) 55 | if (isCkCanvas(parent)) { 56 | parent.skObject?.drawParagraph(this.skObject, this.props.x ?? 0, this.props.y ?? 0) 57 | } 58 | // TODO we can avoid deleting & recreating the paragraph skobject by checkin props that require a new paragraph instance. 59 | } 60 | 61 | delete() { 62 | if (this.deleted) { 63 | return 64 | } 65 | this.deleted = true 66 | this.skObject?.delete() 67 | } 68 | } 69 | 70 | export const createCkParagraph: CkElementCreator<'ck-paragraph'> = ( 71 | type, 72 | props, 73 | canvasKit, 74 | ): CkElement<'ck-paragraph'> => new CkParagraph(canvasKit, props) 75 | -------------------------------------------------------------------------------- /react-canvaskit/src/CkSurface.ts: -------------------------------------------------------------------------------- 1 | import type { Canvas as SkCanvas, CanvasKit, Paint as SkPaint, Surface as SkSurface } from 'canvaskit-wasm' 2 | import type { ReactElement } from 'react' 3 | import type { CkCanvasProps } from './CkCanvas' 4 | import { isCkCanvas } from './CkCanvas' 5 | import { toSkPaint } from './SkiaElementMapping' 6 | import { 7 | CkElement, 8 | CkElementContainer, 9 | CkElementCreator, 10 | CkElementProps, 11 | CkObjectTyping, 12 | Paint, 13 | } from './SkiaElementTypes' 14 | 15 | export interface CkSurfaceProps extends CkElementProps { 16 | width: number 17 | height: number 18 | dx?: number 19 | dy?: number 20 | paint?: Paint 21 | 22 | children?: ReactElement | ReactElement[] 23 | } 24 | 25 | export class CkSurface implements CkElementContainer<'ck-surface'> { 26 | readonly canvasKit: CanvasKit 27 | readonly props: CkObjectTyping['ck-surface']['props'] 28 | skObject?: CkObjectTyping['ck-surface']['type'] 29 | readonly skObjectType: CkObjectTyping['ck-surface']['name'] = 'SkSurface' 30 | readonly type: 'ck-surface' = 'ck-surface' 31 | children: CkElementContainer<'ck-canvas'>[] = [] 32 | 33 | readonly defaultPaint: SkPaint 34 | private renderPaint?: SkPaint 35 | deleted = false 36 | 37 | constructor(canvasKit: CanvasKit, props: CkObjectTyping['ck-surface']['props']) { 38 | this.canvasKit = canvasKit 39 | this.props = props 40 | this.defaultPaint = new this.canvasKit.Paint() 41 | } 42 | 43 | render(parent: CkElementContainer) { 44 | if (this.deleted) { 45 | throw new Error('BUG. surface element deleted.') 46 | } 47 | 48 | if (parent.skObject && isCkCanvas(parent)) { 49 | if (this.skObject === undefined) { 50 | const { width, height } = this.props 51 | this.skObject = this.canvasKit.MakeSurface(width, height) ?? undefined 52 | if (this.skObject === undefined) { 53 | throw new Error('Failed to create a cpu backed skia surface.') 54 | } 55 | } 56 | } else { 57 | throw new Error('Expected an initialized ck-canvas as parent of ck-surface') 58 | } 59 | 60 | this.children.forEach((child) => child.render(this)) 61 | this.drawSelf(parent.skObject, this.skObject) 62 | } 63 | 64 | private drawSelf(parent: SkCanvas, skSurface: SkSurface) { 65 | const skImage = skSurface.makeImageSnapshot() 66 | const { dx, dy, paint } = this.props 67 | // TODO we can be smart and only recreate the paint object if the paint props have changed. 68 | this.renderPaint?.delete() 69 | this.renderPaint = toSkPaint(this.canvasKit, paint) 70 | parent.drawImage(skImage, dx ?? 0, dy ?? 0, this.renderPaint ?? this.defaultPaint) 71 | } 72 | 73 | delete() { 74 | if (this.deleted) { 75 | return 76 | } 77 | this.deleted = true 78 | this.defaultPaint.delete() 79 | this.renderPaint?.delete() 80 | this.renderPaint = undefined 81 | this.skObject?.delete() 82 | this.skObject = undefined 83 | } 84 | } 85 | 86 | export const createCkSurface: CkElementCreator<'ck-surface'> = ( 87 | type, 88 | props, 89 | canvasKit, 90 | ): CkElementContainer<'ck-surface'> => { 91 | return new CkSurface(canvasKit, props) 92 | } 93 | 94 | export function isCkSurface(ckElement: CkElement): ckElement is CkSurface { 95 | return ckElement.type === 'ck-surface' 96 | } 97 | -------------------------------------------------------------------------------- /react-canvaskit/src/CkText.ts: -------------------------------------------------------------------------------- 1 | import type { CanvasKit, Font as SkFont, Paint as SkPaint } from 'canvaskit-wasm' 2 | import { isCkCanvas } from './CkCanvas' 3 | import { toSkFont, toSkPaint } from './SkiaElementMapping' 4 | import { 5 | CkElement, 6 | CkElementContainer, 7 | CkElementCreator, 8 | CkElementProps, 9 | CkObjectTyping, 10 | Font, 11 | Paint, 12 | } from './SkiaElementTypes' 13 | 14 | export interface CkTextProps extends CkElementProps { 15 | x?: number 16 | y?: number 17 | paint?: Paint 18 | font?: Font 19 | children: string 20 | } 21 | 22 | class CkText implements CkElement<'ck-text'> { 23 | readonly canvasKit: CanvasKit 24 | readonly props: CkObjectTyping['ck-text']['props'] 25 | readonly skObjectType: CkObjectTyping['ck-text']['name'] = 'Text' 26 | readonly type: 'ck-text' = 'ck-text' 27 | 28 | private readonly defaultPaint: SkPaint 29 | private readonly defaultFont: SkFont 30 | 31 | private renderPaint?: SkPaint 32 | private renderFont?: SkFont 33 | deleted = false 34 | 35 | constructor(canvasKit: CanvasKit, props: CkObjectTyping['ck-text']['props']) { 36 | this.canvasKit = canvasKit 37 | this.props = props 38 | 39 | this.defaultPaint = new this.canvasKit.Paint() 40 | this.defaultPaint.setStyle(this.canvasKit.PaintStyle.Fill) 41 | this.defaultPaint.setAntiAlias(true) 42 | 43 | this.defaultFont = new this.canvasKit.Font(null, 14) 44 | } 45 | 46 | render(parent?: CkElementContainer): void { 47 | if (parent && isCkCanvas(parent)) { 48 | // TODO we can be smart and only recreate the paint object if the paint props have changed. 49 | this.renderPaint?.delete() 50 | this.renderPaint = toSkPaint(this.canvasKit, this.props.paint) 51 | // TODO we can be smart and only recreate the font object if the font props have changed. 52 | this.renderFont?.delete() 53 | this.renderFont = toSkFont(this.canvasKit, this.props.font) 54 | parent.skObject?.drawText( 55 | this.props.children, 56 | this.props.x ?? 0, 57 | this.props.y ?? 0, 58 | this.renderPaint ?? this.defaultPaint, 59 | this.renderFont ?? this.defaultFont, 60 | ) 61 | } 62 | } 63 | 64 | delete() { 65 | if (this.deleted) { 66 | return 67 | } 68 | this.deleted = true 69 | this.defaultFont.delete() 70 | this.defaultPaint.delete() 71 | this.renderPaint?.delete() 72 | this.renderFont?.delete() 73 | } 74 | } 75 | 76 | export const createCkText: CkElementCreator<'ck-text'> = (type, props, canvasKit) => new CkText(canvasKit, props) 77 | -------------------------------------------------------------------------------- /react-canvaskit/src/ReactCanvasKit.tsx: -------------------------------------------------------------------------------- 1 | import type { CanvasKit, FontMgr as SkFontManager } from 'canvaskit-wasm' 2 | import * as CanvasKitInit from 'canvaskit-wasm' 3 | import type { FunctionComponent, ReactNode } from 'react' 4 | import * as React from 'react' 5 | import type { HostConfig } from 'react-reconciler' 6 | import * as ReactReconciler from 'react-reconciler' 7 | import { 8 | CkElement, 9 | CkElementContainer, 10 | CkElementProps, 11 | CkElementType, 12 | createCkElement, 13 | isContainerElement, 14 | } from './SkiaElementTypes' 15 | 16 | const loadRobotoFontData = fetch('https://storage.googleapis.com/skia-cdn/misc/Roboto-Regular.ttf').then((response) => 17 | response.arrayBuffer(), 18 | ) 19 | // @ts-ignore 20 | const canvasKitPromise: Promise = CanvasKitInit({ 21 | locateFile: (file: string): string => `https://unpkg.com/canvaskit-wasm@0.32.0/bin/${file}`, 22 | }) 23 | let canvasKit: CanvasKit | undefined 24 | 25 | let CanvasKitContext: React.Context 26 | export let useCanvasKit: () => CanvasKit 27 | export let CanvasKitProvider: FunctionComponent 28 | 29 | let FontManagerContext: React.Context 30 | export let useFontManager: () => SkFontManager 31 | export let FontManagerProvider: FunctionComponent<{ fontData: ArrayBuffer[] | undefined; children?: ReactNode }> 32 | 33 | export async function init() { 34 | canvasKit = await canvasKitPromise 35 | const robotoFontData = await loadRobotoFontData 36 | // const copy to make the TS compiler happy when we pass it down to a lambda 37 | const ck = canvasKit 38 | 39 | CanvasKitContext = React.createContext(ck) 40 | useCanvasKit = () => React.useContext(CanvasKitContext) 41 | CanvasKitProvider = ({ children }) => children 42 | 43 | const defaultFontManager = ck.FontMgr.FromData(robotoFontData) as SkFontManager 44 | FontManagerContext = React.createContext(defaultFontManager) 45 | useFontManager = () => React.useContext(FontManagerContext) 46 | FontManagerProvider = (props: { fontData: ArrayBuffer[] | undefined; children?: ReactNode }) => { 47 | if (props.fontData) { 48 | const fontMgrFromData = ck.FontMgr.FromData(...props.fontData) 49 | if (fontMgrFromData === null) { 50 | throw new Error('Failed to create font manager from font data.') 51 | } 52 | 53 | return {props.children} 54 | } else { 55 | return {props.children} 56 | } 57 | } 58 | } 59 | 60 | type ContainerContext = { 61 | ckElement: CkElement 62 | } 63 | 64 | export interface SkObjectRef { 65 | current: T 66 | } 67 | 68 | interface ReactCanvasKitHostConfig 69 | extends HostConfig< 70 | CkElementType, // Type 71 | CkElementProps, // Props 72 | CkElementContainer, // Container 73 | CkElement, // Instance 74 | CkElement<'ck-text'> | CkElement<'ck-paragraph'>, // TextInstance 75 | any, // SuspenceInstance 76 | any, // HydratableInstance 77 | SkObjectRef, // PublicInstance 78 | ContainerContext, // HostContext 79 | any, // UpdatePayload 80 | CkElement[], // _ChildSet 81 | any, // TimeoutHandle 82 | any // NoTimout 83 | > {} 84 | 85 | // @ts-ignore TODO implement missing functions 86 | const hostConfig: ReactCanvasKitHostConfig = { 87 | /** 88 | * This function is used by the reconciler in order to calculate current time for prioritising work. 89 | */ 90 | now: Date.now, 91 | supportsMutation: false, 92 | supportsPersistence: true, 93 | supportsHydration: false, 94 | 95 | createContainerChildSet(container: CkElementContainer): CkElement[] { 96 | return [] 97 | }, 98 | /** 99 | * Attaches new children to the set returned by createContainerChildSet 100 | * @param childSet 101 | * @param child 102 | */ 103 | appendChildToContainerChildSet(childSet: CkElement[], child: CkElement) { 104 | childSet.push(child) 105 | }, 106 | replaceContainerChildren(container: CkElementContainer, newChildren: CkElement[]) { 107 | container.children.forEach((child) => child.delete()) 108 | container.children = newChildren 109 | }, 110 | /** 111 | * This function lets you share some context with the other functions in this HostConfig. 112 | * 113 | * This method lets you return the initial host context from the root of the tree. See `getChildHostContext` for the explanation of host context. 114 | * 115 | * If you don't intend to use host context, you can return `null`. 116 | * 117 | * This method happens **in the render phase**. Do not mutate the tree from it. 118 | * 119 | * @param rootContainerInstance is basically the root dom node you specify while calling render. This is most commonly 120 | *
121 | * @return A context object that you wish to pass to immediate child. 122 | */ 123 | getRootHostContext(rootContainerInstance): ContainerContext { 124 | return { ckElement: rootContainerInstance } 125 | }, 126 | 127 | /** 128 | * This function provides a way to access context from the parent and also a way to pass some context to the immediate 129 | * children of the current node. Context is basically a regular object containing some information. 130 | * 131 | * Host context lets you track some information about where you are in the tree so that it's available inside `createInstance` as the `hostContext` parameter. For example, the DOM renderer uses it to track whether it's inside an HTML or an SVG tree, because `createInstance` implementation needs to be different for them. 132 | * 133 | * If the node of this `type` does not influence the context you want to pass down, you can return `parentHostContext`. Alternatively, you can return any custom object representing the information you want to pass down. 134 | * 135 | * If you don't want to do anything here, return `parentHostContext`. 136 | * 137 | * This method happens **in the render phase**. Do not mutate the tree from it. 138 | * 139 | * @param parentHostContext Context from parent. Example: This will contain rootContext for the immediate child of 140 | * roothost. 141 | * @param type This contains the type of fiber i.e, ‘div’, ‘span’, ‘p’, ‘input’ etc. 142 | * @param rootContainerInstance rootInstance is basically the root dom node you specify while calling render. This is 143 | * most commonly
144 | * @return A context object that you wish to pass to immediate child. 145 | */ 146 | getChildHostContext(parentHostContext, type, rootContainerInstance): ContainerContext { 147 | return parentHostContext 148 | }, 149 | 150 | /** 151 | * If the function returns true, the text would be created inside the host element and no new text element would be 152 | * created separately. 153 | * 154 | * If this returned true, the next call would be to createInstance for the current element and traversal would stop at 155 | * this node (children of this element wont be traversed). 156 | * 157 | * If it returns false, getChildHostContext and shouldSetTextContent will be called on the child elements and it will 158 | * continue till shouldSetTextContent returns true or if the recursion reaches the last tree endpoint which usually is 159 | * a text node. When it reaches the last leaf text node it will call createTextInstance 160 | * 161 | * Some target platforms support setting an instance's text content without manually creating a text node. For example, in the DOM, you can set `node.textContent` instead of creating a text node and appending it. 162 | * 163 | * If you return `true` from this method, React will assume that this node's children are text, and will not create nodes for them. It will instead rely on you to have filled that text during `createInstance`. This is a performance optimization. For example, the DOM renderer returns `true` only if `type` is a known text-only parent (like `'textarea'`) or if `props.children` has a `'string'` type. If you return `true`, you will need to implement `resetTextContent` too. 164 | * 165 | * If you don't want to do anything here, you should return `false`. 166 | * 167 | * This method happens **in the render phase**. Do not mutate the tree from it. 168 | * 169 | * @param type This contains the type of fiber i.e, ‘div’, ‘span’, ‘p’, ‘input’ etc. 170 | * @param props Contains the props passed to the host react element. 171 | * @return This should be a boolean value. 172 | */ 173 | shouldSetTextContent(type, props): boolean { 174 | return type === 'ck-text' || type === 'ck-paragraph' 175 | }, 176 | 177 | /** 178 | * Here we specify how should renderer handle the text content 179 | * 180 | * Same as `createInstance`, but for text nodes. If your renderer doesn't support text nodes, you can throw here. 181 | * 182 | * @param text contains the text string that needs to be rendered. 183 | * @param rootContainerInstance root dom node you specify while calling render. This is most commonly 184 | *
185 | * @param hostContext contains the context from the host node enclosing this text node. For example, in the case of 186 | *

Hello

: currentHostContext for Hello text node will be host context of p. 187 | * @param internalInstanceHandle The fiber node for the text instance. This manages work for this instance. 188 | * @return This should be an actual text view element. In case of dom it would be a textNode. 189 | */ 190 | createTextInstance( 191 | text, 192 | rootContainerInstance, 193 | hostContext, 194 | internalInstanceHandle, 195 | ): CkElement<'ck-text'> | CkElement<'ck-paragraph'> { 196 | throw new Error(`The text '${text}' must be wrapped in a ck-text or ck-paragraph element.`) 197 | }, 198 | 199 | /** 200 | * Create instance is called on all host nodes except the leaf text nodes. So we should return the correct view 201 | * element for each host type here. We are also supposed to take care of the props sent to the host element. For 202 | * example: setting up onClickListeners or setting up styling etc. 203 | * 204 | * This method should return a newly created node. For example, the DOM renderer would call `document.createElement(type)` here and then set the properties from `props`. 205 | * 206 | * You can use `rootContainer` to access the root container associated with that tree. For example, in the DOM renderer, this is useful to get the correct `document` reference that the root belongs to. 207 | * 208 | * The `hostContext` parameter lets you keep track of some information about your current place in the tree. To learn more about it, see `getChildHostContext` below. 209 | * 210 | * The `internalHandle` data structure is meant to be opaque. If you bend the rules and rely on its internal fields, be aware that it may change significantly between versions. You're taking on additional maintenance risk by reading from it, and giving up all guarantees if you write something to it. 211 | * 212 | * This method happens **in the render phase**. It can (and usually should) mutate the node it has just created before returning it, but it must not modify any other nodes. It must not register any event handlers on the parent tree. This is because an instance being created doesn't guarantee it would be placed in the tree — it could be left unused and later collected by GC. If you need to do something when an instance is definitely in the tree, look at `commitMount` instead. 213 | * 214 | * @param type This contains the type of fiber i.e, ‘div’, ‘span’, ‘p’, ‘input’ etc. 215 | * @param props Contains the props passed to the host react element. 216 | * @param rootContainerInstance Root dom node you specify while calling render. This is most commonly
217 | * @param hostContext contains the context from the parent node enclosing this node. This is the return value from getChildHostContext of the parent node. 218 | * @param internalInstanceHandle The fiber node for the text instance. This manages work for this instance. 219 | */ 220 | createInstance(type, props, rootContainerInstance, hostContext, internalInstanceHandle) { 221 | return createCkElement(type, props, hostContext.ckElement.canvasKit) 222 | }, 223 | 224 | /** 225 | * Here we will attach the child dom node to the parent on the initial render phase. This method will be called for 226 | * each child of the current node. 227 | * 228 | * This method should mutate the `parentInstance` and add the child to its list of children. For example, in the DOM this would translate to a `parentInstance.appendChild(child)` call. 229 | * 230 | * This method happens **in the render phase**. It can mutate `parentInstance` and `child`, but it must not modify any other nodes. It's called while the tree is still being built up and not connected to the actual tree on the screen. 231 | * 232 | * @param parentInstance The current node in the traversal 233 | * @param child The child dom node of the current node. 234 | */ 235 | appendInitialChild(parentInstance, child) { 236 | if (isContainerElement(parentInstance)) { 237 | parentInstance.children.push(child) 238 | } else { 239 | throw new Error('Bug? Trying to append a child to a parent that is not a container.') 240 | } 241 | }, 242 | 243 | /** 244 | * In case of react native renderer, this function does nothing but return false. 245 | * 246 | * In case of react-dom, this adds default dom properties such as event listeners, etc. 247 | * For implementing auto focus for certain input elements (autofocus can happen only 248 | * after render is done), react-dom sends return type as true. This results in commitMount 249 | * method for this element to be called. The commitMount will be called only if an element 250 | * returns true in finalizeInitialChildren and after the all elements of the tree has been 251 | * rendered (even after resetAfterCommit). 252 | * 253 | * In this method, you can perform some final mutations on the `instance`. Unlike with `createInstance`, by the time `finalizeInitialChildren` is called, all the initial children have already been added to the `instance`, but the instance itself has not yet been connected to the tree on the screen. 254 | * 255 | * This method happens **in the render phase**. It can mutate `instance`, but it must not modify any other nodes. It's called while the tree is still being built up and not connected to the actual tree on the screen. 256 | * 257 | * There is a second purpose to this method. It lets you specify whether there is some work that needs to happen when the node is connected to the tree on the screen. If you return `true`, the instance will receive a `commitMount` call later. See its documentation below. 258 | * 259 | * If you don't want to do anything here, you should return `false`. 260 | * 261 | * @param parentInstance The instance is the dom element after appendInitialChild. 262 | * @param type This contains the type of fiber i.e, ‘div’, ‘span’, ‘p’, ‘input’ etc. 263 | * @param props Contains the props passed to the host react element. 264 | * @param rootContainerInstance root dom node you specify while calling render. This is most commonly
265 | * @param hostContext contains the context from the parent node enclosing this node. This is the return value from getChildHostContext of the parent node. 266 | */ 267 | finalizeInitialChildren(parentInstance, type, props, rootContainerInstance, hostContext) { 268 | return false 269 | }, 270 | finalizeContainerChildren(container: CkElementContainer, newChildren: CkElement[]) {}, 271 | 272 | /** 273 | * 274 | * This function is called when we have made a in-memory render tree of all the views (Remember we are yet to attach 275 | * it the the actual root dom node). Here we can do any preparation that needs to be done on the rootContainer before 276 | * attaching the in memory render tree. For example: In the case of react-dom, it keeps track of all the currently 277 | * focused elements, disabled events temporarily, etc. 278 | * 279 | * This method lets you store some information before React starts making changes to the tree on the screen. For example, the DOM renderer stores the current text selection so that it can later restore it. This method is mirrored by `resetAfterCommit`. 280 | * 281 | * Even if you don't want to do anything here, you need to return `null` from it. 282 | * 283 | * @param containerInfo root dom node you specify while calling render. This is most commonly
284 | */ 285 | prepareForCommit(containerInfo) { 286 | return null 287 | }, 288 | 289 | /** 290 | * This function gets executed after the inmemory tree has been attached to the root dom element. Here we can do any 291 | * post attach operations that needs to be done. For example: react-dom re-enabled events which were temporarily 292 | * disabled in prepareForCommit and refocuses elements, etc. 293 | * 294 | * This method is called right after React has performed the tree mutations. You can use it to restore something you've stored in `prepareForCommit` — for example, text selection. 295 | * 296 | * You can leave it empty. 297 | * 298 | * @param containerInfo root dom node you specify while calling render. This is most commonly
299 | */ 300 | resetAfterCommit(containerInfo) { 301 | // TODO instead of re-rendering everything, only rerender dirty nodes? 302 | containerInfo.children.forEach((child) => child.render(containerInfo)) 303 | containerInfo.props.renderCallback?.() 304 | }, 305 | 306 | getPublicInstance(instance: CkElement | CkElement<'ck-text'>): SkObjectRef { 307 | return instance.skObject 308 | }, 309 | 310 | /** 311 | * React calls this method so that you can compare the previous and the next props, and decide whether you need to update the underlying instance or not. If you don't need to update it, return `null`. If you need to update it, you can return an arbitrary object representing the changes that need to happen. Then in `commitUpdate` you would need to apply those changes to the instance. 312 | * 313 | * This method happens **in the render phase**. It should only *calculate* the update — but not apply it! For example, the DOM renderer returns an array that looks like `[prop1, value1, prop2, value2, ...]` for all props that have actually changed. And only in `commitUpdate` it applies those changes. You should calculate as much as you can in `prepareUpdate` so that `commitUpdate` can be very fast and straightforward. 314 | * 315 | * See the meaning of `rootContainer` and `hostContext` in the `createInstance` documentation. 316 | */ 317 | prepareUpdate(instance, type, oldProps, newProps, rootContainerInstance, hostContext) { 318 | // TODO check & return if we can need to create an entire new object or we can reuse the underlying skobject and use it as the payload in cloneInstance. 319 | }, 320 | 321 | cloneInstance( 322 | instance: CkElement, 323 | updatePayload: any, 324 | type: CkElementType, 325 | oldProps: CkElementProps, 326 | newProps: CkElementProps, 327 | internalInstanceHandle: SkObjectRef, 328 | keepChildren: boolean, 329 | recyclableInstance: CkElement, 330 | ): CkElement { 331 | // TODO implement a way where we can create a new instance and reuse the underlying canvaskit objects where possible 332 | 333 | const ckElement = createCkElement(type, newProps, instance.canvasKit) 334 | if (keepChildren && isContainerElement(ckElement) && isContainerElement(instance)) { 335 | ckElement.children = instance.children 336 | } 337 | // recyclableInstance.props = newProps 338 | // return recyclableInstance 339 | return ckElement 340 | }, 341 | } 342 | 343 | const canvaskitReconciler = ReactReconciler(hostConfig) 344 | canvaskitReconciler.injectIntoDevTools({ 345 | bundleType: 1, // 0 for PROD, 1 for DEV 346 | version: '0.0.1', // version for your renderer 347 | rendererPackageName: 'react-canvaskit', // package name 348 | }) 349 | 350 | export function render(element: ReactNode, canvas: HTMLCanvasElement, renderCallback?: () => void) { 351 | if (canvasKit === undefined) { 352 | throw new Error('Not initialized') 353 | } 354 | 355 | const rootTag = 0 356 | const hydrate = false 357 | 358 | const skSurface = canvasKit.MakeWebGLCanvasSurface(canvas, undefined) 359 | if (skSurface === null) { 360 | throw new Error('Failed to create surface from canvas.') 361 | } 362 | 363 | const ckSurfaceElement: CkElementContainer<'ck-surface'> = { 364 | canvasKit, 365 | type: 'ck-surface', 366 | // @ts-ignore 367 | props: { width: canvas.width, height: canvas.height, renderCallback }, 368 | skObjectType: 'SkSurface', 369 | skObject: skSurface, 370 | children: [], 371 | render() { 372 | this.children.forEach((child) => child.render(ckSurfaceElement)) 373 | }, 374 | } 375 | const container = canvaskitReconciler.createContainer(ckSurfaceElement, rootTag, hydrate, null) 376 | 377 | return new Promise((resolve) => { 378 | canvaskitReconciler.updateContainer(element, container, null, () => resolve()) 379 | }) 380 | } 381 | -------------------------------------------------------------------------------- /react-canvaskit/src/SkiaElementMapping.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | CanvasKit, 3 | Color as SkColor, 4 | Font as SkFont, 5 | FontStyle, 6 | Paint as SkPaint, 7 | ParagraphStyle as SkParagraphStyle, 8 | TextStyle as SkTextStyle, 9 | Typeface as SkTypeface, 10 | } from 'canvaskit-wasm' 11 | import type { CkFontStyle, Color, Font, Paint, ParagraphStyle, TextStyle, TypeFace } from './SkiaElementTypes' 12 | import { FontSlantEnum, FontWeightEnum, FontWidthEnum } from './SkiaElementTypes' 13 | 14 | export interface PropsConverter { 15 | (canvasKit: CanvasKit, propIn?: IN): OUT | undefined 16 | } 17 | 18 | export const toSkTypeFace: PropsConverter = (canvasKit, typeFace) => 19 | typeFace ? canvasKit.Typeface.MakeFreeTypeFaceFromData(typeFace.data) ?? undefined : undefined 20 | export const toSkFont: PropsConverter = (canvasKit, font) => 21 | font 22 | ? new canvasKit.Font(font.typeFace === undefined ? null : toSkTypeFace(canvasKit, font.typeFace)!!, font.size) 23 | : undefined 24 | export const toSkColor: PropsConverter = (canvasKit, color) => { 25 | if (typeof color === 'string') { 26 | // @ts-ignore 27 | return canvasKit.parseColorString(color) 28 | } else { 29 | return color ? canvasKit.Color(color.red, color.green, color.blue, color.alpha ?? 1) : undefined 30 | } 31 | } 32 | 33 | export const toSkPaint: PropsConverter = (canvasKit, paint) => { 34 | if (paint === undefined) { 35 | return undefined 36 | } 37 | 38 | const skPaint = new canvasKit.Paint() 39 | 40 | // TODO blendMode?: BlendMode; 41 | 42 | const skColor = toSkColor(canvasKit, paint.color) 43 | if (skColor) { 44 | skPaint.setColor(skColor) 45 | } 46 | 47 | // TODO filterQuality?: FilterQuality; 48 | // TODO strokeCap?: StrokeCap; 49 | // TODO strokeJoin?: StrokeJoin; 50 | 51 | if (paint.strokeMiter) { 52 | skPaint.setStrokeMiter(paint.strokeMiter) 53 | } 54 | if (paint.strokeWidth) { 55 | skPaint.setStrokeWidth(paint.strokeWidth) 56 | } 57 | if (paint.antiAlias) { 58 | skPaint.setAntiAlias(paint.antiAlias) 59 | } 60 | // TODO colorFilter?: ColorFilter 61 | // TODO imageFilter?: ImageFilter; 62 | // TODO maskFilter?: MaskFilter 63 | // TODO pathEffect?: PathEffect 64 | // TODO shader?: Shader 65 | // TODO style?: PaintStyle 66 | 67 | return skPaint 68 | } 69 | 70 | export const toFontStyle: PropsConverter = (canvasKit, fontStyle): FontStyle => { 71 | return { 72 | slant: { value: fontStyle?.slant ?? FontSlantEnum.Upright }, 73 | weight: { value: fontStyle?.weight ?? FontWeightEnum.Normal }, 74 | width: { value: fontStyle?.width ?? FontWidthEnum.Normal }, 75 | } 76 | } 77 | 78 | export const toSkTextStyle: PropsConverter = (canvasKit, textStyle) => { 79 | return { 80 | backgroundColor: toSkColor(canvasKit, textStyle?.backgroundColor) ?? canvasKit.WHITE, 81 | color: toSkColor(canvasKit, textStyle?.color) ?? canvasKit.BLACK, 82 | decoration: textStyle?.decoration ?? 0, 83 | decorationThickness: textStyle?.decorationThickness ?? 0, 84 | fontFamilies: textStyle?.fontFamilies ?? [], 85 | fontSize: textStyle?.fontSize ?? 14, 86 | fontStyle: toFontStyle(canvasKit, textStyle?.fontStyle), 87 | foregroundColor: toSkColor(canvasKit, textStyle?.foregroundColor) ?? canvasKit.BLACK, 88 | } 89 | } 90 | 91 | export const toSkParagraphStyle: PropsConverter = (canvasKit, paragraphStyle) => { 92 | const textAlign = paragraphStyle?.textAlign ? { value: paragraphStyle.textAlign } : undefined 93 | const textDirection = paragraphStyle?.textDirection ? { value: paragraphStyle.textDirection } : undefined 94 | 95 | return new canvasKit.ParagraphStyle({ 96 | disableHinting: paragraphStyle?.disableHinting, 97 | ellipsis: paragraphStyle?.ellipsis, 98 | maxLines: paragraphStyle?.maxLines, 99 | textAlign, 100 | textDirection, 101 | textStyle: toSkTextStyle(canvasKit, paragraphStyle?.textStyle), 102 | }) 103 | } 104 | -------------------------------------------------------------------------------- /react-canvaskit/src/SkiaElementTypes.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | Canvas as SkCanvas, 3 | CanvasKit, 4 | Image as SkImage, 5 | Paragraph as SkParagraph, 6 | Surface as SkSurface, 7 | } from 'canvaskit-wasm' 8 | import type { MutableRefObject } from 'react' 9 | import type { CkCanvasProps } from './CkCanvas' 10 | import { createCkCanvas } from './CkCanvas' 11 | import type { CkEncodedImageProps } from './CkEncodedImage' 12 | import { createCkEncodedImage } from './CkEncodedImage' 13 | import type { CkLineProps } from './CkLine' 14 | import { createCkLine } from './CkLine' 15 | import type { CkParagraphProps } from './CkParagraph' 16 | import { createCkParagraph } from './CkParagraph' 17 | import type { CkSurfaceProps } from './CkSurface' 18 | import { createCkSurface } from './CkSurface' 19 | import type { CkTextProps } from './CkText' 20 | import { createCkText } from './CkText' 21 | 22 | export type CkElementProps = { 23 | ref?: MutableRefObject 24 | } 25 | 26 | export interface CkObjectTyping { 27 | 'ck-surface': { type: SkSurface; name: 'SkSurface'; props: CkSurfaceProps } 28 | 'ck-canvas': { type: SkCanvas; name: 'SkCanvas'; props: CkCanvasProps } 29 | 'ck-line': { type: never; name: 'Line'; props: CkLineProps } 30 | 'ck-text': { type: never; name: 'Text'; props: CkTextProps } 31 | 'ck-paragraph': { type: SkParagraph; name: 'SkParagraph'; props: CkParagraphProps } 32 | 'ck-encoded-image': { type: SkImage; name: 'SkImage'; props: CkEncodedImageProps } 33 | } 34 | 35 | export type CkElementType = keyof CkObjectTyping 36 | 37 | export interface CkElement { 38 | readonly canvasKit: CanvasKit 39 | readonly type: TypeName 40 | props: CkObjectTyping[TypeName]['props'] 41 | readonly skObjectType: CkObjectTyping[TypeName]['name'] 42 | skObject?: CkObjectTyping[TypeName]['type'] 43 | 44 | render(parent: CkElementContainer): void 45 | 46 | delete(): void 47 | } 48 | 49 | export interface CkElementCreator { 50 | (type: TypeName, props: CkObjectTyping[TypeName]['props'], canvasKit: CanvasKit): CkElement 51 | } 52 | 53 | export function isContainerElement(ckElement: CkElement): ckElement is CkElementContainer { 54 | return (ckElement as CkElementContainer).children !== undefined 55 | } 56 | 57 | export interface CkElementContainer extends CkElement { 58 | children: CkElement[] 59 | } 60 | 61 | namespace CkPropTypes { 62 | export const Color = { 63 | red: 'number', 64 | green: 'number', 65 | blue: 'number', 66 | alpha: 'number', 67 | } 68 | } 69 | 70 | export interface Color { 71 | red: number 72 | green: number 73 | blue: number 74 | alpha?: number 75 | } 76 | 77 | export type ColorTypeName = 'Color' 78 | 79 | export enum FilterQuality {} 80 | // TODO 81 | 82 | export enum StrokeCap {} 83 | // TODO 84 | 85 | export enum StrokeJoin {} 86 | // TODO 87 | 88 | export enum BlendMode {} 89 | // TODO 90 | 91 | export type ColorFilter = 92 | | BlendColorFilter 93 | | ComposeColorFilter 94 | | LerpColorFilter 95 | | LinearToSRGBGammaColorFilter 96 | | MatrixColorFilter 97 | | SRGBToLinearGammaColorFilter 98 | 99 | export interface BlendColorFilter { 100 | color: Color 101 | blendMode: BlendMode 102 | } 103 | 104 | export interface ComposeColorFilter { 105 | first: ColorFilter 106 | second: ColorFilter 107 | } 108 | 109 | export interface LerpColorFilter { 110 | lerp: number 111 | first: ColorFilter 112 | second: ColorFilter 113 | } 114 | 115 | export type LinearToSRGBGammaColorFilter = 'LinearToSRGBGamma' 116 | 117 | export interface MatrixColorFilter { 118 | matrix: Matrix 119 | } 120 | 121 | export type SRGBToLinearGammaColorFilter = 'SRGBToLinearGamma' 122 | 123 | export type ImageFilter = BlurImageFilter | ColorImageFilter | ComposeImageFilter | MatrixTransformImageFilter 124 | 125 | export enum TileMode {} 126 | // TODO 127 | 128 | export interface BlurImageFilter { 129 | rx: number 130 | ry: number 131 | tileMode: TileMode 132 | next: ImageFilter | null 133 | } 134 | 135 | export interface ColorImageFilter { 136 | filter: ColorFilter 137 | next: ImageFilter | null 138 | } 139 | 140 | export interface ComposeImageFilter { 141 | first: ImageFilter 142 | second: ImageFilter 143 | } 144 | 145 | export enum FilterQuality {} 146 | // TODO 147 | 148 | export interface MatrixTransformImageFilter { 149 | matrix: MatrixColorFilter 150 | filterQuality: FilterQuality 151 | next: ImageFilter | null 152 | } 153 | 154 | export type MaskFilter = BlurMaskFilter 155 | 156 | export enum BlurStyle {} 157 | // TODO 158 | 159 | export interface BlurMaskFilter { 160 | blurStyle: BlurStyle 161 | radius: number 162 | b: boolean 163 | } 164 | 165 | export type PathEffect = DashPathEffect | CornerPathEffect | DiscretePathEffect 166 | 167 | export interface DashPathEffect { 168 | intervals: number[] 169 | phase: number 170 | } 171 | 172 | export interface CornerPathEffect { 173 | radius: number 174 | } 175 | 176 | export interface DiscretePathEffect { 177 | frequency: number 178 | amplitude: number 179 | seed: number 180 | } 181 | 182 | export type Shader = LinearGradientShader | RadialGradientShader | TwoPointConicalGradientShader 183 | 184 | export type Point = [number, number] 185 | 186 | export type Matrix = [number, number, number, number, number, number, number, number, number] 187 | 188 | export interface LinearGradientShader { 189 | start: Point 190 | end: Point 191 | colors: Color[] 192 | positions: number[] 193 | mode: number 194 | localMatrix: Matrix | null 195 | flags: number 196 | } 197 | 198 | export interface RadialGradientShader { 199 | center: Point 200 | radius: number 201 | colors: Color[] 202 | positions: number[] 203 | mode: number 204 | localMatrix?: Matrix 205 | flags: number 206 | } 207 | 208 | export interface TwoPointConicalGradientShader { 209 | start: Point 210 | startRadius: number 211 | end: Point 212 | endRadius: number 213 | colors: Color[] 214 | positions: number[] 215 | mode: number 216 | localMatrix?: Matrix 217 | flags: number 218 | } 219 | 220 | export enum PaintStyle { 221 | /** 222 | * Fill the geometry. 223 | */ 224 | Fill = 0, 225 | /** 226 | * Stroke the geometry. 227 | */ 228 | Stroke = 1, 229 | /** 230 | * Fill and stroke the geometry. 231 | */ 232 | StrokeAndFill = 2, 233 | } 234 | 235 | export interface Paint { 236 | blendMode?: BlendMode 237 | color?: Color | string 238 | filterQuality?: FilterQuality 239 | strokeCap?: StrokeCap 240 | strokeJoin?: StrokeJoin 241 | strokeMiter?: number 242 | strokeWidth?: number 243 | antiAlias?: boolean 244 | colorFilter?: ColorFilter 245 | imageFilter?: ImageFilter 246 | maskFilter?: MaskFilter 247 | pathEffect?: PathEffect 248 | shader?: Shader 249 | style?: PaintStyle 250 | } 251 | 252 | export interface LineProps { 253 | x1: number 254 | y1: number 255 | x2: number 256 | y2: number 257 | paint: Paint 258 | } 259 | 260 | export enum TextAlignEnum { 261 | Left = 0, 262 | Center = 1, 263 | Right = 2, 264 | } 265 | 266 | export enum TextDirectionEnum { 267 | Ltr = 0, 268 | Rtl = 1, 269 | // TODO 270 | } 271 | 272 | export enum FontWeightEnum { 273 | /** 274 | * A thick font weight of 900. 275 | */ 276 | Black = 900, 277 | /** 278 | * A thick font weight of 700. This is the default for a bold font. 279 | */ 280 | Bold = 700, 281 | /** 282 | * A thick font weight of 1000. 283 | */ 284 | ExtraBlack = 1000, 285 | /** 286 | * A thick font weight of 800. 287 | */ 288 | ExtraBold = 800, 289 | /** 290 | * A thin font weight of 200. 291 | */ 292 | ExtraLight = 200, 293 | /** 294 | * The font has no thickness at all. 295 | */ 296 | Invisible = 0, 297 | 298 | /** 299 | * A thin font weight of 300. 300 | */ 301 | Light = 300, 302 | 303 | /** 304 | *A thicker font weight of 500. 305 | */ 306 | Medium = 500, 307 | 308 | /** 309 | *A typical font weight of 400. This is the default font weight. 310 | */ 311 | Normal = 400, 312 | 313 | /** 314 | *A thick font weight of 600. 315 | */ 316 | SemiBold = 600, 317 | 318 | /** 319 | *A thin font weight of 100. 320 | */ 321 | Thin = 100, 322 | } 323 | 324 | export enum FontSlantEnum { 325 | Upright, 326 | Italic, 327 | Oblique, 328 | } 329 | 330 | export enum FontWidthEnum { 331 | /** 332 | * A condensed font width of 3. 333 | */ 334 | Condensed = 3, 335 | /** 336 | * An expanded font width of 7. 337 | */ 338 | Expanded = 7, 339 | /** 340 | *A condensed font width of 2. 341 | */ 342 | ExtraCondensed = 2, 343 | /** 344 | *An expanded font width of 8. 345 | */ 346 | ExtraExpanded = 8, 347 | /** 348 | *A normal font width of 5. This is the default font width. 349 | */ 350 | Normal = 5, 351 | /** 352 | *A condensed font width of 4. 353 | */ 354 | SemiCondensed = 4, 355 | /** 356 | *An expanded font width of 6. 357 | */ 358 | SemiExpanded = 6, 359 | /** 360 | *A condensed font width of 1. 361 | */ 362 | UltraCondensed = 1, 363 | /** 364 | *An expanded font width of 9. 365 | */ 366 | UltraExpanded = 9, 367 | } 368 | 369 | export interface TypeFace { 370 | data: ArrayBuffer 371 | } 372 | 373 | export interface Font { 374 | typeFace?: TypeFace 375 | size: number 376 | } 377 | 378 | export interface CkFontStyle { 379 | weight?: FontWeightEnum 380 | slant?: FontSlantEnum 381 | width?: FontWidthEnum 382 | } 383 | 384 | export interface TextStyle { 385 | backgroundColor?: Color | string 386 | color?: Color | string 387 | decoration?: number 388 | decorationThickness?: number 389 | fontFamilies?: string[] 390 | fontSize?: number 391 | fontStyle?: CkFontStyle 392 | foregroundColor?: Color | string 393 | } 394 | 395 | export interface ParagraphStyle { 396 | disableHinting?: boolean 397 | heightMultiplier?: number 398 | ellipsis?: string 399 | maxLines?: number 400 | textAlign?: TextAlignEnum 401 | textDirection?: TextDirectionEnum 402 | textStyle: TextStyle 403 | } 404 | 405 | export interface ParagraphProps { 406 | style: ParagraphStyle 407 | maxWidth: number 408 | x: number 409 | y: number 410 | } 411 | 412 | const CkElements: { [key in CkElementType]: CkElementCreator } = { 413 | 'ck-text': createCkText, 414 | 'ck-line': createCkLine, 415 | 'ck-surface': createCkSurface, 416 | 'ck-canvas': createCkCanvas, 417 | 'ck-paragraph': createCkParagraph, 418 | 'ck-encoded-image': createCkEncodedImage, 419 | } 420 | 421 | export function createCkElement(type: CkElementType, props: CkElementProps, canvasKit: CanvasKit): CkElement { 422 | return CkElements[type](type, props, canvasKit) 423 | } 424 | 425 | declare global { 426 | namespace JSX { 427 | interface IntrinsicElements { 428 | 'ck-text': CkTextProps 429 | 'ck-canvas': CkCanvasProps 430 | 'ck-surface': CkSurfaceProps 431 | 'ck-line': CkLineProps 432 | 'ck-paragraph': CkParagraphProps 433 | 'ck-encoded-image': CkEncodedImageProps 434 | } 435 | } 436 | } 437 | -------------------------------------------------------------------------------- /react-canvaskit/src/index.tsx: -------------------------------------------------------------------------------- 1 | export * from './ReactCanvasKit' 2 | export * from './SkiaElementTypes' 3 | -------------------------------------------------------------------------------- /react-canvaskit/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "resolveJsonModule": true, 5 | "target": "es6", 6 | "module": "ES6", 7 | "lib": [ 8 | "es2015", 9 | "es2016", 10 | "es2017", 11 | "es2019", 12 | "esnext", 13 | "dom" 14 | ], 15 | "allowJs": true, 16 | "rootDir": "src", 17 | "strict": true, 18 | "inlineSourceMap": true, 19 | "inlineSources": true, 20 | "declaration": true, 21 | "allowSyntheticDefaultImports": true, 22 | "experimentalDecorators": true, 23 | "emitDecoratorMetadata": true, 24 | "declarationDir": "types", 25 | "outDir": "dist", 26 | "jsx": "react" 27 | }, 28 | "include": [ 29 | "src" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /react-canvaskit/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@cspotcode/source-map-consumer@0.8.0": 6 | version "0.8.0" 7 | resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" 8 | integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== 9 | 10 | "@cspotcode/source-map-support@0.7.0": 11 | version "0.7.0" 12 | resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5" 13 | integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA== 14 | dependencies: 15 | "@cspotcode/source-map-consumer" "0.8.0" 16 | 17 | "@electron/get@^1.0.1": 18 | version "1.13.1" 19 | resolved "https://registry.yarnpkg.com/@electron/get/-/get-1.13.1.tgz#42a0aa62fd1189638bd966e23effaebb16108368" 20 | integrity sha512-U5vkXDZ9DwXtkPqlB45tfYnnYBN8PePp1z/XDCupnSpdrxT8/ThCv9WCwPLf9oqiSGZTkH6dx2jDUPuoXpjkcA== 21 | dependencies: 22 | debug "^4.1.1" 23 | env-paths "^2.2.0" 24 | fs-extra "^8.1.0" 25 | got "^9.6.0" 26 | progress "^2.0.3" 27 | semver "^6.2.0" 28 | sumchecker "^3.0.1" 29 | optionalDependencies: 30 | global-agent "^3.0.0" 31 | global-tunnel-ng "^2.7.1" 32 | 33 | "@jest/types@^27.4.2": 34 | version "27.4.2" 35 | resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.4.2.tgz#96536ebd34da6392c2b7c7737d693885b5dd44a5" 36 | integrity sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg== 37 | dependencies: 38 | "@types/istanbul-lib-coverage" "^2.0.0" 39 | "@types/istanbul-reports" "^3.0.0" 40 | "@types/node" "*" 41 | "@types/yargs" "^16.0.0" 42 | chalk "^4.0.0" 43 | 44 | "@sindresorhus/is@^0.14.0": 45 | version "0.14.0" 46 | resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" 47 | integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== 48 | 49 | "@szmarczak/http-timer@^1.1.2": 50 | version "1.1.2" 51 | resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" 52 | integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== 53 | dependencies: 54 | defer-to-connect "^1.0.1" 55 | 56 | "@tsconfig/node10@^1.0.7": 57 | version "1.0.8" 58 | resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" 59 | integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== 60 | 61 | "@tsconfig/node12@^1.0.7": 62 | version "1.0.9" 63 | resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" 64 | integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== 65 | 66 | "@tsconfig/node14@^1.0.0": 67 | version "1.0.1" 68 | resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" 69 | integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== 70 | 71 | "@tsconfig/node16@^1.0.2": 72 | version "1.0.2" 73 | resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" 74 | integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== 75 | 76 | "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": 77 | version "2.0.4" 78 | resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" 79 | integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== 80 | 81 | "@types/istanbul-lib-report@*": 82 | version "3.0.0" 83 | resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" 84 | integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== 85 | dependencies: 86 | "@types/istanbul-lib-coverage" "*" 87 | 88 | "@types/istanbul-reports@^3.0.0": 89 | version "3.0.1" 90 | resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" 91 | integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== 92 | dependencies: 93 | "@types/istanbul-lib-report" "*" 94 | 95 | "@types/node@*": 96 | version "17.0.8" 97 | resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.8.tgz#50d680c8a8a78fe30abe6906453b21ad8ab0ad7b" 98 | integrity sha512-YofkM6fGv4gDJq78g4j0mMuGMkZVxZDgtU0JRdx6FgiJDG+0fY0GKVolOV8WqVmEhLCXkQRjwDdKyPxJp/uucg== 99 | 100 | "@types/node@^12.0.12": 101 | version "12.20.41" 102 | resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.41.tgz#81d7734c5257da9f04354bd9084a6ebbdd5198a5" 103 | integrity sha512-f6xOqucbDirG7LOzedpvzjP3UTmHttRou3Mosx3vL9wr9AIQGhcPgVnqa8ihpZYnxyM1rxeNCvTyukPKZtq10Q== 104 | 105 | "@types/node@^16.4.1": 106 | version "16.11.19" 107 | resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.19.tgz#1afa165146997b8286b6eabcb1c2d50729055169" 108 | integrity sha512-BPAcfDPoHlRQNKktbsbnpACGdypPFBuX4xQlsWDE7B8XXcfII+SpOLay3/qZmCLb39kV5S1RTYwXdkx2lwLYng== 109 | 110 | "@types/prop-types@*": 111 | version "15.7.4" 112 | resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" 113 | integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== 114 | 115 | "@types/react-reconciler@^0.26.3": 116 | version "0.26.4" 117 | resolved "https://registry.yarnpkg.com/@types/react-reconciler/-/react-reconciler-0.26.4.tgz#651404be172cf29b65cddf246d8d964b4e448399" 118 | integrity sha512-bdx4aIBkQRDAnzc23JBFeZmVpmfLJHfHikmQukEt9qs4bQtq9f+PDbNwhR9u74FkIUyIDz1I1qJ8OF6RwadKpw== 119 | dependencies: 120 | "@types/react" "*" 121 | 122 | "@types/react@*": 123 | version "17.0.38" 124 | resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.38.tgz#f24249fefd89357d5fa71f739a686b8d7c7202bd" 125 | integrity sha512-SI92X1IA+FMnP3qM5m4QReluXzhcmovhZnLNm3pyeQlooi02qI7sLiepEYqT678uNiyc25XfCqxREFpy3W7YhQ== 126 | dependencies: 127 | "@types/prop-types" "*" 128 | "@types/scheduler" "*" 129 | csstype "^3.0.2" 130 | 131 | "@types/scheduler@*": 132 | version "0.16.2" 133 | resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" 134 | integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== 135 | 136 | "@types/yargs-parser@*": 137 | version "20.2.1" 138 | resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" 139 | integrity sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw== 140 | 141 | "@types/yargs@^16.0.0": 142 | version "16.0.4" 143 | resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" 144 | integrity sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw== 145 | dependencies: 146 | "@types/yargs-parser" "*" 147 | 148 | acorn-walk@^8.1.1: 149 | version "8.2.0" 150 | resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" 151 | integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== 152 | 153 | acorn@^8.4.1: 154 | version "8.7.0" 155 | resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" 156 | integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== 157 | 158 | ansi-align@^2.0.0: 159 | version "2.0.0" 160 | resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f" 161 | integrity sha1-w2rsy6VjuJzrVW82kPCx2eNUf38= 162 | dependencies: 163 | string-width "^2.0.0" 164 | 165 | ansi-regex@^3.0.0: 166 | version "3.0.0" 167 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" 168 | integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= 169 | 170 | ansi-styles@^3.2.1: 171 | version "3.2.1" 172 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 173 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 174 | dependencies: 175 | color-convert "^1.9.0" 176 | 177 | ansi-styles@^4.1.0: 178 | version "4.3.0" 179 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 180 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 181 | dependencies: 182 | color-convert "^2.0.1" 183 | 184 | arg@^4.1.0: 185 | version "4.1.3" 186 | resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" 187 | integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== 188 | 189 | balanced-match@^1.0.0: 190 | version "1.0.2" 191 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 192 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 193 | 194 | boolean@^3.0.1: 195 | version "3.1.4" 196 | resolved "https://registry.yarnpkg.com/boolean/-/boolean-3.1.4.tgz#f51a2fb5838a99e06f9b6ec1edb674de67026435" 197 | integrity sha512-3hx0kwU3uzG6ReQ3pnaFQPSktpBw6RHN3/ivDKEuU8g1XSfafowyvDnadjv1xp8IZqhtSukxlwv9bF6FhX8m0w== 198 | 199 | boxen@^1.2.1: 200 | version "1.3.0" 201 | resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b" 202 | integrity sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw== 203 | dependencies: 204 | ansi-align "^2.0.0" 205 | camelcase "^4.0.0" 206 | chalk "^2.0.1" 207 | cli-boxes "^1.0.0" 208 | string-width "^2.0.0" 209 | term-size "^1.2.0" 210 | widest-line "^2.0.0" 211 | 212 | brace-expansion@^1.1.7: 213 | version "1.1.11" 214 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 215 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 216 | dependencies: 217 | balanced-match "^1.0.0" 218 | concat-map "0.0.1" 219 | 220 | bs-logger@0.x: 221 | version "0.2.6" 222 | resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" 223 | integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== 224 | dependencies: 225 | fast-json-stable-stringify "2.x" 226 | 227 | buffer-crc32@~0.2.3: 228 | version "0.2.13" 229 | resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" 230 | integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= 231 | 232 | buffer-from@^1.0.0: 233 | version "1.1.2" 234 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" 235 | integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== 236 | 237 | cacheable-request@^6.0.0: 238 | version "6.1.0" 239 | resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" 240 | integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== 241 | dependencies: 242 | clone-response "^1.0.2" 243 | get-stream "^5.1.0" 244 | http-cache-semantics "^4.0.0" 245 | keyv "^3.0.0" 246 | lowercase-keys "^2.0.0" 247 | normalize-url "^4.1.0" 248 | responselike "^1.0.2" 249 | 250 | camelcase@^4.0.0: 251 | version "4.1.0" 252 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" 253 | integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= 254 | 255 | canvaskit-wasm@0.32.0: 256 | version "0.32.0" 257 | resolved "https://registry.yarnpkg.com/canvaskit-wasm/-/canvaskit-wasm-0.32.0.tgz#4964e5fe9adca21eb0cdb3b7368a2b9cd9460e9a" 258 | integrity sha512-H3Por5oDOXLXje5j+7aPTUtHvfRpYFm4u073Xi2kSBfS3vZQmDoiLdwQthf00zTUBtOK1lX8+6qmBFHdfKdxRw== 259 | 260 | capture-stack-trace@^1.0.0: 261 | version "1.0.1" 262 | resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d" 263 | integrity sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw== 264 | 265 | chalk@^2.0.1: 266 | version "2.4.2" 267 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 268 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 269 | dependencies: 270 | ansi-styles "^3.2.1" 271 | escape-string-regexp "^1.0.5" 272 | supports-color "^5.3.0" 273 | 274 | chalk@^4.0.0: 275 | version "4.1.2" 276 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" 277 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== 278 | dependencies: 279 | ansi-styles "^4.1.0" 280 | supports-color "^7.1.0" 281 | 282 | ci-info@^1.5.0: 283 | version "1.6.0" 284 | resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" 285 | integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A== 286 | 287 | ci-info@^3.2.0: 288 | version "3.3.0" 289 | resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" 290 | integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== 291 | 292 | cli-boxes@^1.0.0: 293 | version "1.0.0" 294 | resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143" 295 | integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM= 296 | 297 | clone-response@^1.0.2: 298 | version "1.0.2" 299 | resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" 300 | integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= 301 | dependencies: 302 | mimic-response "^1.0.0" 303 | 304 | color-convert@^1.9.0: 305 | version "1.9.3" 306 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 307 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 308 | dependencies: 309 | color-name "1.1.3" 310 | 311 | color-convert@^2.0.1: 312 | version "2.0.1" 313 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 314 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 315 | dependencies: 316 | color-name "~1.1.4" 317 | 318 | color-name@1.1.3: 319 | version "1.1.3" 320 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 321 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 322 | 323 | color-name@~1.1.4: 324 | version "1.1.4" 325 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 326 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 327 | 328 | concat-map@0.0.1: 329 | version "0.0.1" 330 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 331 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 332 | 333 | concat-stream@^1.6.2: 334 | version "1.6.2" 335 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" 336 | integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== 337 | dependencies: 338 | buffer-from "^1.0.0" 339 | inherits "^2.0.3" 340 | readable-stream "^2.2.2" 341 | typedarray "^0.0.6" 342 | 343 | config-chain@^1.1.11: 344 | version "1.1.13" 345 | resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" 346 | integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== 347 | dependencies: 348 | ini "^1.3.4" 349 | proto-list "~1.2.1" 350 | 351 | configstore@^3.0.0: 352 | version "3.1.5" 353 | resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.5.tgz#e9af331fadc14dabd544d3e7e76dc446a09a530f" 354 | integrity sha512-nlOhI4+fdzoK5xmJ+NY+1gZK56bwEaWZr8fYuXohZ9Vkc1o3a4T/R3M+yE/w7x/ZVJ1zF8c+oaOvF0dztdUgmA== 355 | dependencies: 356 | dot-prop "^4.2.1" 357 | graceful-fs "^4.1.2" 358 | make-dir "^1.0.0" 359 | unique-string "^1.0.0" 360 | write-file-atomic "^2.0.0" 361 | xdg-basedir "^3.0.0" 362 | 363 | core-util-is@~1.0.0: 364 | version "1.0.3" 365 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" 366 | integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== 367 | 368 | create-error-class@^3.0.0: 369 | version "3.0.2" 370 | resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6" 371 | integrity sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y= 372 | dependencies: 373 | capture-stack-trace "^1.0.0" 374 | 375 | create-require@^1.1.0: 376 | version "1.1.1" 377 | resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" 378 | integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== 379 | 380 | cross-spawn@^5.0.1: 381 | version "5.1.0" 382 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" 383 | integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= 384 | dependencies: 385 | lru-cache "^4.0.1" 386 | shebang-command "^1.2.0" 387 | which "^1.2.9" 388 | 389 | crypto-random-string@^1.0.0: 390 | version "1.0.0" 391 | resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" 392 | integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4= 393 | 394 | csstype@^3.0.2: 395 | version "3.0.10" 396 | resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.10.tgz#2ad3a7bed70f35b965707c092e5f30b327c290e5" 397 | integrity sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA== 398 | 399 | debug@^2.6.9: 400 | version "2.6.9" 401 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 402 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 403 | dependencies: 404 | ms "2.0.0" 405 | 406 | debug@^4.1.0, debug@^4.1.1: 407 | version "4.3.3" 408 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" 409 | integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== 410 | dependencies: 411 | ms "2.1.2" 412 | 413 | decompress-response@^3.3.0: 414 | version "3.3.0" 415 | resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" 416 | integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= 417 | dependencies: 418 | mimic-response "^1.0.0" 419 | 420 | deep-extend@^0.6.0: 421 | version "0.6.0" 422 | resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" 423 | integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== 424 | 425 | defer-to-connect@^1.0.1: 426 | version "1.1.3" 427 | resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" 428 | integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== 429 | 430 | define-properties@^1.1.3: 431 | version "1.1.3" 432 | resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" 433 | integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== 434 | dependencies: 435 | object-keys "^1.0.12" 436 | 437 | detect-node@^2.0.4: 438 | version "2.1.0" 439 | resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" 440 | integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== 441 | 442 | diff@^4.0.1: 443 | version "4.0.2" 444 | resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" 445 | integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== 446 | 447 | dot-prop@^4.2.1: 448 | version "4.2.1" 449 | resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.1.tgz#45884194a71fc2cda71cbb4bceb3a4dd2f433ba4" 450 | integrity sha512-l0p4+mIuJIua0mhxGoh4a+iNL9bmeK5DvnSVQa6T0OhrVmaEa1XScX5Etc673FePCJOArq/4Pa2cLGODUWTPOQ== 451 | dependencies: 452 | is-obj "^1.0.0" 453 | 454 | duplexer3@^0.1.4: 455 | version "0.1.4" 456 | resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" 457 | integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= 458 | 459 | electron@^11.1.0: 460 | version "11.5.0" 461 | resolved "https://registry.yarnpkg.com/electron/-/electron-11.5.0.tgz#f1650543b9d8f2047d3807755bdb120153ed210f" 462 | integrity sha512-WjNDd6lGpxyiNjE3LhnFCAk/D9GIj1rU3GSDealVShhkkkPR3Vh4q8ErXGDl1OAO/faomVa10KoFPUN/pLbNxg== 463 | dependencies: 464 | "@electron/get" "^1.0.1" 465 | "@types/node" "^12.0.12" 466 | extract-zip "^1.0.3" 467 | 468 | encodeurl@^1.0.2: 469 | version "1.0.2" 470 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" 471 | integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= 472 | 473 | end-of-stream@^1.1.0: 474 | version "1.4.4" 475 | resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" 476 | integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== 477 | dependencies: 478 | once "^1.4.0" 479 | 480 | env-paths@^2.2.0: 481 | version "2.2.1" 482 | resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" 483 | integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== 484 | 485 | es6-error@^4.1.1: 486 | version "4.1.1" 487 | resolved "https://registry.yarnpkg.com/es6-error/-/es6-error-4.1.1.tgz#9e3af407459deed47e9a91f9b885a84eb05c561d" 488 | integrity sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg== 489 | 490 | escape-string-regexp@^1.0.5: 491 | version "1.0.5" 492 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 493 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 494 | 495 | escape-string-regexp@^4.0.0: 496 | version "4.0.0" 497 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" 498 | integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== 499 | 500 | execa@^0.7.0: 501 | version "0.7.0" 502 | resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" 503 | integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c= 504 | dependencies: 505 | cross-spawn "^5.0.1" 506 | get-stream "^3.0.0" 507 | is-stream "^1.1.0" 508 | npm-run-path "^2.0.0" 509 | p-finally "^1.0.0" 510 | signal-exit "^3.0.0" 511 | strip-eof "^1.0.0" 512 | 513 | extract-zip@^1.0.3: 514 | version "1.7.0" 515 | resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.7.0.tgz#556cc3ae9df7f452c493a0cfb51cc30277940927" 516 | integrity sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA== 517 | dependencies: 518 | concat-stream "^1.6.2" 519 | debug "^2.6.9" 520 | mkdirp "^0.5.4" 521 | yauzl "^2.10.0" 522 | 523 | fast-json-stable-stringify@2.x: 524 | version "2.1.0" 525 | resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" 526 | integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== 527 | 528 | fd-slicer@~1.1.0: 529 | version "1.1.0" 530 | resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" 531 | integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= 532 | dependencies: 533 | pend "~1.2.0" 534 | 535 | fs-extra@^8.1.0: 536 | version "8.1.0" 537 | resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" 538 | integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== 539 | dependencies: 540 | graceful-fs "^4.2.0" 541 | jsonfile "^4.0.0" 542 | universalify "^0.1.0" 543 | 544 | fs.realpath@^1.0.0: 545 | version "1.0.0" 546 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 547 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 548 | 549 | get-stream@^3.0.0: 550 | version "3.0.0" 551 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" 552 | integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= 553 | 554 | get-stream@^4.1.0: 555 | version "4.1.0" 556 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" 557 | integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== 558 | dependencies: 559 | pump "^3.0.0" 560 | 561 | get-stream@^5.1.0: 562 | version "5.2.0" 563 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" 564 | integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== 565 | dependencies: 566 | pump "^3.0.0" 567 | 568 | glob@^7.1.3: 569 | version "7.2.0" 570 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" 571 | integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== 572 | dependencies: 573 | fs.realpath "^1.0.0" 574 | inflight "^1.0.4" 575 | inherits "2" 576 | minimatch "^3.0.4" 577 | once "^1.3.0" 578 | path-is-absolute "^1.0.0" 579 | 580 | global-agent@^3.0.0: 581 | version "3.0.0" 582 | resolved "https://registry.yarnpkg.com/global-agent/-/global-agent-3.0.0.tgz#ae7cd31bd3583b93c5a16437a1afe27cc33a1ab6" 583 | integrity sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q== 584 | dependencies: 585 | boolean "^3.0.1" 586 | es6-error "^4.1.1" 587 | matcher "^3.0.0" 588 | roarr "^2.15.3" 589 | semver "^7.3.2" 590 | serialize-error "^7.0.1" 591 | 592 | global-dirs@^0.1.0: 593 | version "0.1.1" 594 | resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" 595 | integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU= 596 | dependencies: 597 | ini "^1.3.4" 598 | 599 | global-tunnel-ng@^2.7.1: 600 | version "2.7.1" 601 | resolved "https://registry.yarnpkg.com/global-tunnel-ng/-/global-tunnel-ng-2.7.1.tgz#d03b5102dfde3a69914f5ee7d86761ca35d57d8f" 602 | integrity sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg== 603 | dependencies: 604 | encodeurl "^1.0.2" 605 | lodash "^4.17.10" 606 | npm-conf "^1.1.3" 607 | tunnel "^0.0.6" 608 | 609 | globalthis@^1.0.1: 610 | version "1.0.2" 611 | resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.2.tgz#2a235d34f4d8036219f7e34929b5de9e18166b8b" 612 | integrity sha512-ZQnSFO1la8P7auIOQECnm0sSuoMeaSq0EEdXMBFF2QJO4uNcwbyhSgG3MruWNbFTqCLmxVwGOl7LZ9kASvHdeQ== 613 | dependencies: 614 | define-properties "^1.1.3" 615 | 616 | got@^6.7.1: 617 | version "6.7.1" 618 | resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" 619 | integrity sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA= 620 | dependencies: 621 | create-error-class "^3.0.0" 622 | duplexer3 "^0.1.4" 623 | get-stream "^3.0.0" 624 | is-redirect "^1.0.0" 625 | is-retry-allowed "^1.0.0" 626 | is-stream "^1.0.0" 627 | lowercase-keys "^1.0.0" 628 | safe-buffer "^5.0.1" 629 | timed-out "^4.0.0" 630 | unzip-response "^2.0.1" 631 | url-parse-lax "^1.0.0" 632 | 633 | got@^9.6.0: 634 | version "9.6.0" 635 | resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" 636 | integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== 637 | dependencies: 638 | "@sindresorhus/is" "^0.14.0" 639 | "@szmarczak/http-timer" "^1.1.2" 640 | cacheable-request "^6.0.0" 641 | decompress-response "^3.3.0" 642 | duplexer3 "^0.1.4" 643 | get-stream "^4.1.0" 644 | lowercase-keys "^1.0.1" 645 | mimic-response "^1.0.1" 646 | p-cancelable "^1.0.0" 647 | to-readable-stream "^1.0.0" 648 | url-parse-lax "^3.0.0" 649 | 650 | graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: 651 | version "4.2.9" 652 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" 653 | integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== 654 | 655 | has-flag@^3.0.0: 656 | version "3.0.0" 657 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 658 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 659 | 660 | has-flag@^4.0.0: 661 | version "4.0.0" 662 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 663 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 664 | 665 | http-cache-semantics@^4.0.0: 666 | version "4.1.0" 667 | resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" 668 | integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== 669 | 670 | import-lazy@^2.1.0: 671 | version "2.1.0" 672 | resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" 673 | integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= 674 | 675 | imurmurhash@^0.1.4: 676 | version "0.1.4" 677 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 678 | integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= 679 | 680 | inflight@^1.0.4: 681 | version "1.0.6" 682 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 683 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 684 | dependencies: 685 | once "^1.3.0" 686 | wrappy "1" 687 | 688 | inherits@2, inherits@^2.0.3, inherits@~2.0.3: 689 | version "2.0.4" 690 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 691 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 692 | 693 | ini@^1.3.4, ini@~1.3.0: 694 | version "1.3.8" 695 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" 696 | integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== 697 | 698 | ip@^1.1.4: 699 | version "1.1.5" 700 | resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" 701 | integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= 702 | 703 | is-ci@^1.0.10: 704 | version "1.2.1" 705 | resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c" 706 | integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg== 707 | dependencies: 708 | ci-info "^1.5.0" 709 | 710 | is-fullwidth-code-point@^2.0.0: 711 | version "2.0.0" 712 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 713 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= 714 | 715 | is-installed-globally@^0.1.0: 716 | version "0.1.0" 717 | resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80" 718 | integrity sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA= 719 | dependencies: 720 | global-dirs "^0.1.0" 721 | is-path-inside "^1.0.0" 722 | 723 | is-npm@^1.0.0: 724 | version "1.0.0" 725 | resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4" 726 | integrity sha1-8vtjpl5JBbQGyGBydloaTceTufQ= 727 | 728 | is-obj@^1.0.0: 729 | version "1.0.1" 730 | resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" 731 | integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= 732 | 733 | is-path-inside@^1.0.0: 734 | version "1.0.1" 735 | resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" 736 | integrity sha1-jvW33lBDej/cprToZe96pVy0gDY= 737 | dependencies: 738 | path-is-inside "^1.0.1" 739 | 740 | is-redirect@^1.0.0: 741 | version "1.0.0" 742 | resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24" 743 | integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ= 744 | 745 | is-retry-allowed@^1.0.0: 746 | version "1.2.0" 747 | resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" 748 | integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== 749 | 750 | is-stream@^1.0.0, is-stream@^1.1.0: 751 | version "1.1.0" 752 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" 753 | integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= 754 | 755 | isarray@~1.0.0: 756 | version "1.0.0" 757 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 758 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= 759 | 760 | isexe@^2.0.0: 761 | version "2.0.0" 762 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 763 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= 764 | 765 | jest-util@^27.0.0: 766 | version "27.4.2" 767 | resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.4.2.tgz#ed95b05b1adfd761e2cda47e0144c6a58e05a621" 768 | integrity sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA== 769 | dependencies: 770 | "@jest/types" "^27.4.2" 771 | "@types/node" "*" 772 | chalk "^4.0.0" 773 | ci-info "^3.2.0" 774 | graceful-fs "^4.2.4" 775 | picomatch "^2.2.3" 776 | 777 | "js-tokens@^3.0.0 || ^4.0.0": 778 | version "4.0.0" 779 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 780 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 781 | 782 | json-buffer@3.0.0: 783 | version "3.0.0" 784 | resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" 785 | integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= 786 | 787 | json-stringify-safe@^5.0.1: 788 | version "5.0.1" 789 | resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" 790 | integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= 791 | 792 | json5@2.x: 793 | version "2.2.0" 794 | resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" 795 | integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== 796 | dependencies: 797 | minimist "^1.2.5" 798 | 799 | jsonfile@^4.0.0: 800 | version "4.0.0" 801 | resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" 802 | integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= 803 | optionalDependencies: 804 | graceful-fs "^4.1.6" 805 | 806 | keyv@^3.0.0: 807 | version "3.1.0" 808 | resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" 809 | integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== 810 | dependencies: 811 | json-buffer "3.0.0" 812 | 813 | latest-version@^3.0.0: 814 | version "3.1.0" 815 | resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15" 816 | integrity sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU= 817 | dependencies: 818 | package-json "^4.0.0" 819 | 820 | lodash.memoize@4.x: 821 | version "4.1.2" 822 | resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" 823 | integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= 824 | 825 | lodash@^4.17.10: 826 | version "4.17.21" 827 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" 828 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 829 | 830 | loose-envify@^1.1.0: 831 | version "1.4.0" 832 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" 833 | integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== 834 | dependencies: 835 | js-tokens "^3.0.0 || ^4.0.0" 836 | 837 | lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: 838 | version "1.0.1" 839 | resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" 840 | integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== 841 | 842 | lowercase-keys@^2.0.0: 843 | version "2.0.0" 844 | resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" 845 | integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== 846 | 847 | lru-cache@^4.0.1: 848 | version "4.1.5" 849 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" 850 | integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== 851 | dependencies: 852 | pseudomap "^1.0.2" 853 | yallist "^2.1.2" 854 | 855 | lru-cache@^6.0.0: 856 | version "6.0.0" 857 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" 858 | integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== 859 | dependencies: 860 | yallist "^4.0.0" 861 | 862 | make-dir@^1.0.0: 863 | version "1.3.0" 864 | resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" 865 | integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== 866 | dependencies: 867 | pify "^3.0.0" 868 | 869 | make-error@1.x, make-error@^1.1.1: 870 | version "1.3.6" 871 | resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" 872 | integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== 873 | 874 | matcher@^3.0.0: 875 | version "3.0.0" 876 | resolved "https://registry.yarnpkg.com/matcher/-/matcher-3.0.0.tgz#bd9060f4c5b70aa8041ccc6f80368760994f30ca" 877 | integrity sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng== 878 | dependencies: 879 | escape-string-regexp "^4.0.0" 880 | 881 | mimic-response@^1.0.0, mimic-response@^1.0.1: 882 | version "1.0.1" 883 | resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" 884 | integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== 885 | 886 | minimatch@^3.0.4: 887 | version "3.0.4" 888 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 889 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 890 | dependencies: 891 | brace-expansion "^1.1.7" 892 | 893 | minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5: 894 | version "1.2.5" 895 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" 896 | integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== 897 | 898 | mkdirp@^0.5.4: 899 | version "0.5.5" 900 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" 901 | integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== 902 | dependencies: 903 | minimist "^1.2.5" 904 | 905 | ms@2.0.0: 906 | version "2.0.0" 907 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 908 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 909 | 910 | ms@2.1.2: 911 | version "2.1.2" 912 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 913 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 914 | 915 | normalize-url@^4.1.0: 916 | version "4.5.1" 917 | resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" 918 | integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== 919 | 920 | npm-conf@^1.1.3: 921 | version "1.1.3" 922 | resolved "https://registry.yarnpkg.com/npm-conf/-/npm-conf-1.1.3.tgz#256cc47bd0e218c259c4e9550bf413bc2192aff9" 923 | integrity sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw== 924 | dependencies: 925 | config-chain "^1.1.11" 926 | pify "^3.0.0" 927 | 928 | npm-run-path@^2.0.0: 929 | version "2.0.2" 930 | resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" 931 | integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= 932 | dependencies: 933 | path-key "^2.0.0" 934 | 935 | object-assign@^4.1.1: 936 | version "4.1.1" 937 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 938 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= 939 | 940 | object-keys@^1.0.12: 941 | version "1.1.1" 942 | resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" 943 | integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== 944 | 945 | once@^1.3.0, once@^1.3.1, once@^1.4.0: 946 | version "1.4.0" 947 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 948 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 949 | dependencies: 950 | wrappy "1" 951 | 952 | p-cancelable@^1.0.0: 953 | version "1.1.0" 954 | resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" 955 | integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== 956 | 957 | p-finally@^1.0.0: 958 | version "1.0.0" 959 | resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" 960 | integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= 961 | 962 | package-json@^4.0.0: 963 | version "4.0.1" 964 | resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed" 965 | integrity sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0= 966 | dependencies: 967 | got "^6.7.1" 968 | registry-auth-token "^3.0.1" 969 | registry-url "^3.0.3" 970 | semver "^5.1.0" 971 | 972 | path-is-absolute@^1.0.0: 973 | version "1.0.1" 974 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 975 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 976 | 977 | path-is-inside@^1.0.1: 978 | version "1.0.2" 979 | resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" 980 | integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM= 981 | 982 | path-key@^2.0.0: 983 | version "2.0.1" 984 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" 985 | integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= 986 | 987 | pend@~1.2.0: 988 | version "1.2.0" 989 | resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" 990 | integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= 991 | 992 | picomatch@^2.2.3: 993 | version "2.3.1" 994 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" 995 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== 996 | 997 | pify@^3.0.0: 998 | version "3.0.0" 999 | resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" 1000 | integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= 1001 | 1002 | prepend-http@^1.0.1: 1003 | version "1.0.4" 1004 | resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" 1005 | integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= 1006 | 1007 | prepend-http@^2.0.0: 1008 | version "2.0.0" 1009 | resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" 1010 | integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= 1011 | 1012 | prettier@^2.5.1: 1013 | version "2.5.1" 1014 | resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" 1015 | integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== 1016 | 1017 | process-nextick-args@~2.0.0: 1018 | version "2.0.1" 1019 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" 1020 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== 1021 | 1022 | progress@^2.0.3: 1023 | version "2.0.3" 1024 | resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" 1025 | integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== 1026 | 1027 | proto-list@~1.2.1: 1028 | version "1.2.4" 1029 | resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" 1030 | integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= 1031 | 1032 | pseudomap@^1.0.2: 1033 | version "1.0.2" 1034 | resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" 1035 | integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= 1036 | 1037 | pump@^3.0.0: 1038 | version "3.0.0" 1039 | resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" 1040 | integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== 1041 | dependencies: 1042 | end-of-stream "^1.1.0" 1043 | once "^1.3.1" 1044 | 1045 | rc@^1.0.1, rc@^1.1.6: 1046 | version "1.2.8" 1047 | resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" 1048 | integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== 1049 | dependencies: 1050 | deep-extend "^0.6.0" 1051 | ini "~1.3.0" 1052 | minimist "^1.2.0" 1053 | strip-json-comments "~2.0.1" 1054 | 1055 | react-devtools-core@4.22.1: 1056 | version "4.22.1" 1057 | resolved "https://registry.yarnpkg.com/react-devtools-core/-/react-devtools-core-4.22.1.tgz#b276d42f860bedc373c9b3c0f5f96734318dd453" 1058 | integrity sha512-pvpNDHE7p0FtcCmIWGazoY8LLVfBI9sw0Kf10kdHhPI9Tzt3OG/qEt16GrAbE0keuna5WzX3r1qPKVjqOqsuUg== 1059 | dependencies: 1060 | shell-quote "^1.6.1" 1061 | ws "^7" 1062 | 1063 | react-devtools@^4.14.0: 1064 | version "4.22.1" 1065 | resolved "https://registry.yarnpkg.com/react-devtools/-/react-devtools-4.22.1.tgz#d0e1e22b34d6c9c6c4dc8b1a7159a86774fd8b15" 1066 | integrity sha512-NrjS3av6mrcnTmxPJCaanNZgYwhp3YYQLFwm7gTxRouQF6abKYo8uZ4RdONIDFDmwiB0zg6mM83RTMjRSJgGiA== 1067 | dependencies: 1068 | cross-spawn "^5.0.1" 1069 | electron "^11.1.0" 1070 | ip "^1.1.4" 1071 | minimist "^1.2.3" 1072 | react-devtools-core "4.22.1" 1073 | update-notifier "^2.1.0" 1074 | 1075 | react-reconciler@0.26.2: 1076 | version "0.26.2" 1077 | resolved "https://registry.yarnpkg.com/react-reconciler/-/react-reconciler-0.26.2.tgz#bbad0e2d1309423f76cf3c3309ac6c96e05e9d91" 1078 | integrity sha512-nK6kgY28HwrMNwDnMui3dvm3rCFjZrcGiuwLc5COUipBK5hWHLOxMJhSnSomirqWwjPBJKV1QcbkI0VJr7Gl1Q== 1079 | dependencies: 1080 | loose-envify "^1.1.0" 1081 | object-assign "^4.1.1" 1082 | scheduler "^0.20.2" 1083 | 1084 | readable-stream@^2.2.2: 1085 | version "2.3.7" 1086 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" 1087 | integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== 1088 | dependencies: 1089 | core-util-is "~1.0.0" 1090 | inherits "~2.0.3" 1091 | isarray "~1.0.0" 1092 | process-nextick-args "~2.0.0" 1093 | safe-buffer "~5.1.1" 1094 | string_decoder "~1.1.1" 1095 | util-deprecate "~1.0.1" 1096 | 1097 | registry-auth-token@^3.0.1: 1098 | version "3.4.0" 1099 | resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e" 1100 | integrity sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A== 1101 | dependencies: 1102 | rc "^1.1.6" 1103 | safe-buffer "^5.0.1" 1104 | 1105 | registry-url@^3.0.3: 1106 | version "3.1.0" 1107 | resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942" 1108 | integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI= 1109 | dependencies: 1110 | rc "^1.0.1" 1111 | 1112 | responselike@^1.0.2: 1113 | version "1.0.2" 1114 | resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" 1115 | integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= 1116 | dependencies: 1117 | lowercase-keys "^1.0.0" 1118 | 1119 | rimraf@^3.0.2: 1120 | version "3.0.2" 1121 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" 1122 | integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== 1123 | dependencies: 1124 | glob "^7.1.3" 1125 | 1126 | roarr@^2.15.3: 1127 | version "2.15.4" 1128 | resolved "https://registry.yarnpkg.com/roarr/-/roarr-2.15.4.tgz#f5fe795b7b838ccfe35dc608e0282b9eba2e7afd" 1129 | integrity sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A== 1130 | dependencies: 1131 | boolean "^3.0.1" 1132 | detect-node "^2.0.4" 1133 | globalthis "^1.0.1" 1134 | json-stringify-safe "^5.0.1" 1135 | semver-compare "^1.0.0" 1136 | sprintf-js "^1.1.2" 1137 | 1138 | safe-buffer@^5.0.1: 1139 | version "5.2.1" 1140 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 1141 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 1142 | 1143 | safe-buffer@~5.1.0, safe-buffer@~5.1.1: 1144 | version "5.1.2" 1145 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 1146 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 1147 | 1148 | scheduler@^0.20.2: 1149 | version "0.20.2" 1150 | resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" 1151 | integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== 1152 | dependencies: 1153 | loose-envify "^1.1.0" 1154 | object-assign "^4.1.1" 1155 | 1156 | semver-compare@^1.0.0: 1157 | version "1.0.0" 1158 | resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" 1159 | integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= 1160 | 1161 | semver-diff@^2.0.0: 1162 | version "2.1.0" 1163 | resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" 1164 | integrity sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY= 1165 | dependencies: 1166 | semver "^5.0.3" 1167 | 1168 | semver@7.x, semver@^7.3.2: 1169 | version "7.3.5" 1170 | resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" 1171 | integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== 1172 | dependencies: 1173 | lru-cache "^6.0.0" 1174 | 1175 | semver@^5.0.3, semver@^5.1.0: 1176 | version "5.7.1" 1177 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 1178 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 1179 | 1180 | semver@^6.2.0: 1181 | version "6.3.0" 1182 | resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" 1183 | integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== 1184 | 1185 | serialize-error@^7.0.1: 1186 | version "7.0.1" 1187 | resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-7.0.1.tgz#f1360b0447f61ffb483ec4157c737fab7d778e18" 1188 | integrity sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw== 1189 | dependencies: 1190 | type-fest "^0.13.1" 1191 | 1192 | shebang-command@^1.2.0: 1193 | version "1.2.0" 1194 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" 1195 | integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= 1196 | dependencies: 1197 | shebang-regex "^1.0.0" 1198 | 1199 | shebang-regex@^1.0.0: 1200 | version "1.0.0" 1201 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" 1202 | integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= 1203 | 1204 | shell-quote@^1.6.1: 1205 | version "1.7.3" 1206 | resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" 1207 | integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== 1208 | 1209 | signal-exit@^3.0.0, signal-exit@^3.0.2: 1210 | version "3.0.6" 1211 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" 1212 | integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== 1213 | 1214 | sprintf-js@^1.1.2: 1215 | version "1.1.2" 1216 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" 1217 | integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== 1218 | 1219 | string-width@^2.0.0, string-width@^2.1.1: 1220 | version "2.1.1" 1221 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" 1222 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== 1223 | dependencies: 1224 | is-fullwidth-code-point "^2.0.0" 1225 | strip-ansi "^4.0.0" 1226 | 1227 | string_decoder@~1.1.1: 1228 | version "1.1.1" 1229 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" 1230 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== 1231 | dependencies: 1232 | safe-buffer "~5.1.0" 1233 | 1234 | strip-ansi@^4.0.0: 1235 | version "4.0.0" 1236 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" 1237 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= 1238 | dependencies: 1239 | ansi-regex "^3.0.0" 1240 | 1241 | strip-eof@^1.0.0: 1242 | version "1.0.0" 1243 | resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" 1244 | integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= 1245 | 1246 | strip-json-comments@~2.0.1: 1247 | version "2.0.1" 1248 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 1249 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= 1250 | 1251 | sumchecker@^3.0.1: 1252 | version "3.0.1" 1253 | resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-3.0.1.tgz#6377e996795abb0b6d348e9b3e1dfb24345a8e42" 1254 | integrity sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg== 1255 | dependencies: 1256 | debug "^4.1.0" 1257 | 1258 | supports-color@^5.3.0: 1259 | version "5.5.0" 1260 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 1261 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 1262 | dependencies: 1263 | has-flag "^3.0.0" 1264 | 1265 | supports-color@^7.1.0: 1266 | version "7.2.0" 1267 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" 1268 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== 1269 | dependencies: 1270 | has-flag "^4.0.0" 1271 | 1272 | term-size@^1.2.0: 1273 | version "1.2.0" 1274 | resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69" 1275 | integrity sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk= 1276 | dependencies: 1277 | execa "^0.7.0" 1278 | 1279 | timed-out@^4.0.0: 1280 | version "4.0.1" 1281 | resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" 1282 | integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= 1283 | 1284 | to-readable-stream@^1.0.0: 1285 | version "1.0.0" 1286 | resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" 1287 | integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== 1288 | 1289 | ts-jest@^27.1.2: 1290 | version "27.1.2" 1291 | resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-27.1.2.tgz#5991d6eb3fd8e1a8d4b8f6de3ec0a3cc567f3151" 1292 | integrity sha512-eSOiJOWq6Hhs6Khzk5wKC5sgWIXgXqOCiIl1+3lfnearu58Hj4QpE5tUhQcA3xtZrELbcvAGCsd6HB8OsaVaTA== 1293 | dependencies: 1294 | bs-logger "0.x" 1295 | fast-json-stable-stringify "2.x" 1296 | jest-util "^27.0.0" 1297 | json5 "2.x" 1298 | lodash.memoize "4.x" 1299 | make-error "1.x" 1300 | semver "7.x" 1301 | yargs-parser "20.x" 1302 | 1303 | ts-node@^10.1.0: 1304 | version "10.4.0" 1305 | resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.4.0.tgz#680f88945885f4e6cf450e7f0d6223dd404895f7" 1306 | integrity sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A== 1307 | dependencies: 1308 | "@cspotcode/source-map-support" "0.7.0" 1309 | "@tsconfig/node10" "^1.0.7" 1310 | "@tsconfig/node12" "^1.0.7" 1311 | "@tsconfig/node14" "^1.0.0" 1312 | "@tsconfig/node16" "^1.0.2" 1313 | acorn "^8.4.1" 1314 | acorn-walk "^8.1.1" 1315 | arg "^4.1.0" 1316 | create-require "^1.1.0" 1317 | diff "^4.0.1" 1318 | make-error "^1.1.1" 1319 | yn "3.1.1" 1320 | 1321 | tunnel@^0.0.6: 1322 | version "0.0.6" 1323 | resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" 1324 | integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== 1325 | 1326 | type-fest@^0.13.1: 1327 | version "0.13.1" 1328 | resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.13.1.tgz#0172cb5bce80b0bd542ea348db50c7e21834d934" 1329 | integrity sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg== 1330 | 1331 | typedarray@^0.0.6: 1332 | version "0.0.6" 1333 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" 1334 | integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= 1335 | 1336 | typescript@^4.3.5: 1337 | version "4.5.4" 1338 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.4.tgz#a17d3a0263bf5c8723b9c52f43c5084edf13c2e8" 1339 | integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg== 1340 | 1341 | unique-string@^1.0.0: 1342 | version "1.0.0" 1343 | resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a" 1344 | integrity sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo= 1345 | dependencies: 1346 | crypto-random-string "^1.0.0" 1347 | 1348 | universalify@^0.1.0: 1349 | version "0.1.2" 1350 | resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" 1351 | integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== 1352 | 1353 | unzip-response@^2.0.1: 1354 | version "2.0.1" 1355 | resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97" 1356 | integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c= 1357 | 1358 | update-notifier@^2.1.0: 1359 | version "2.5.0" 1360 | resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6" 1361 | integrity sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw== 1362 | dependencies: 1363 | boxen "^1.2.1" 1364 | chalk "^2.0.1" 1365 | configstore "^3.0.0" 1366 | import-lazy "^2.1.0" 1367 | is-ci "^1.0.10" 1368 | is-installed-globally "^0.1.0" 1369 | is-npm "^1.0.0" 1370 | latest-version "^3.0.0" 1371 | semver-diff "^2.0.0" 1372 | xdg-basedir "^3.0.0" 1373 | 1374 | url-parse-lax@^1.0.0: 1375 | version "1.0.0" 1376 | resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" 1377 | integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= 1378 | dependencies: 1379 | prepend-http "^1.0.1" 1380 | 1381 | url-parse-lax@^3.0.0: 1382 | version "3.0.0" 1383 | resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" 1384 | integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= 1385 | dependencies: 1386 | prepend-http "^2.0.0" 1387 | 1388 | util-deprecate@~1.0.1: 1389 | version "1.0.2" 1390 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1391 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= 1392 | 1393 | which@^1.2.9: 1394 | version "1.3.1" 1395 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" 1396 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== 1397 | dependencies: 1398 | isexe "^2.0.0" 1399 | 1400 | widest-line@^2.0.0: 1401 | version "2.0.1" 1402 | resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc" 1403 | integrity sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA== 1404 | dependencies: 1405 | string-width "^2.1.1" 1406 | 1407 | wrappy@1: 1408 | version "1.0.2" 1409 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1410 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 1411 | 1412 | write-file-atomic@^2.0.0: 1413 | version "2.4.3" 1414 | resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" 1415 | integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ== 1416 | dependencies: 1417 | graceful-fs "^4.1.11" 1418 | imurmurhash "^0.1.4" 1419 | signal-exit "^3.0.2" 1420 | 1421 | ws@^7: 1422 | version "7.5.6" 1423 | resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b" 1424 | integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA== 1425 | 1426 | xdg-basedir@^3.0.0: 1427 | version "3.0.0" 1428 | resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" 1429 | integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= 1430 | 1431 | yallist@^2.1.2: 1432 | version "2.1.2" 1433 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" 1434 | integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= 1435 | 1436 | yallist@^4.0.0: 1437 | version "4.0.0" 1438 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" 1439 | integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== 1440 | 1441 | yargs-parser@20.x: 1442 | version "20.2.9" 1443 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" 1444 | integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== 1445 | 1446 | yauzl@^2.10.0: 1447 | version "2.10.0" 1448 | resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" 1449 | integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= 1450 | dependencies: 1451 | buffer-crc32 "~0.2.3" 1452 | fd-slicer "~1.1.0" 1453 | 1454 | yn@3.1.1: 1455 | version "3.1.1" 1456 | resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" 1457 | integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== 1458 | --------------------------------------------------------------------------------