├── .gitignore ├── LICENSE ├── README.md ├── manifest.json ├── package-lock.json ├── package.json ├── scripts ├── README.md ├── build.js ├── dev.js └── util.js ├── src ├── plugin │ └── run.ts └── ui │ ├── index.css │ ├── main.tsx │ ├── ui.css │ ├── ui.html │ └── ui.tsx └── tsconfig.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Sebastian Flajszer 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 | # Figma Design plugin template with UI & Browser APIs 2 | 3 | This is a template for writing Figma Design plugins with UI & browser APIs. It uses typescript, react for ui and esbuild for bundling. 4 | 5 | ## Getting started 6 | 7 | ### Manifest.json 8 | 9 | First you need to update the `manifest.json`. Idk if there is a simpler way than generating the basic plugin template in figma by going to `plugin > development > new plugin` and then creating `figma design plugin > with ui & browser APIs`. Then you have to save the folder figma generated somewhere and take everything from `manifest.json` inside it, excluding `main` and `ui` options, and put it inside of this repo's `manifest.json`. 10 | 11 | Now you can remove the plugin created by figma (the folder you saved in the step above), and add a new plugin providing `manifest.json` from THIS repo. To remove invalid plugins go to `plugin > development > manage plugins in development`. To add go to `plugin > development > import plugin from manifest`. 12 | 13 | ### Running 14 | 15 | Install dependencies 16 | 17 | ``` 18 | npm i 19 | ``` 20 | 21 | To just build your plugin run 22 | 23 | ``` 24 | npm run build 25 | ``` 26 | 27 | To start development mode (rebuild on change) run 28 | 29 | ``` 30 | npm run dev 31 | ``` 32 | 33 | Do not delete `src/plugin/run.ts`, `src/ui/main.tsx` and `src/ui/ui.html` files because they are needed during build step! 34 | 35 | ## Useful resources 36 | 37 | Figma plugin API provides css variables for colors used in figma design. You can learn more about it in ["CSS Variables and Theming" section of docs](https://www.figma.com/plugin-docs/css-variables) 38 | 39 | To keep your plugin clean you probably should stick to figma's design system that can be found [here](https://www.figma.com/file/Gj9iMcTbFbHrFq1ZWbDBuyc9/UI2%3A-Figma's-Design-System?node-id=0%3A11724). 40 | 41 | There are other solutions like [figma-plugin-ds](https://github.com/thomas-lowry/figma-plugin-ds) that provide ready css styling for things like labels / inputs but you'll have to install it yourself if you decide to use it. 42 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./build/plugin.js", 3 | "ui": "./build/ui.html" 4 | } 5 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "plugin-template", 3 | "version": "1.0.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "plugin-template", 9 | "version": "1.0.0", 10 | "license": "MIT", 11 | "dependencies": { 12 | "react": "^18.2.0", 13 | "react-dom": "^18.2.0" 14 | }, 15 | "devDependencies": { 16 | "@figma/plugin-typings": "^1.50.0", 17 | "@types/node": "^18.7.6", 18 | "@types/react": "^18.0.17", 19 | "@types/react-dom": "^18.0.6", 20 | "esbuild": "^0.15.5", 21 | "html-minifier": "^4.0.0", 22 | "typescript": "^4.7.4" 23 | } 24 | }, 25 | "node_modules/@esbuild/linux-loong64": { 26 | "version": "0.15.5", 27 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.5.tgz", 28 | "integrity": "sha512-UHkDFCfSGTuXq08oQltXxSZmH1TXyWsL+4QhZDWvvLl6mEJQqk3u7/wq1LjhrrAXYIllaTtRSzUXl4Olkf2J8A==", 29 | "cpu": [ 30 | "loong64" 31 | ], 32 | "dev": true, 33 | "optional": true, 34 | "os": [ 35 | "linux" 36 | ], 37 | "engines": { 38 | "node": ">=12" 39 | } 40 | }, 41 | "node_modules/@figma/plugin-typings": { 42 | "version": "1.50.0", 43 | "resolved": "https://registry.npmjs.org/@figma/plugin-typings/-/plugin-typings-1.50.0.tgz", 44 | "integrity": "sha512-ue1He4XimFEjY7eS7x6tBY6pyMp7zfVOjgStFioqKUxPPIz0gCFLmFUjR5g6fMrYJCqAMP5/Mjwq4Ks0vpe2sA==", 45 | "dev": true 46 | }, 47 | "node_modules/@types/node": { 48 | "version": "18.7.6", 49 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.6.tgz", 50 | "integrity": "sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A==", 51 | "dev": true 52 | }, 53 | "node_modules/@types/prop-types": { 54 | "version": "15.7.5", 55 | "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", 56 | "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", 57 | "dev": true 58 | }, 59 | "node_modules/@types/react": { 60 | "version": "18.0.17", 61 | "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.17.tgz", 62 | "integrity": "sha512-38ETy4tL+rn4uQQi7mB81G7V1g0u2ryquNmsVIOKUAEIDK+3CUjZ6rSRpdvS99dNBnkLFL83qfmtLacGOTIhwQ==", 63 | "dev": true, 64 | "dependencies": { 65 | "@types/prop-types": "*", 66 | "@types/scheduler": "*", 67 | "csstype": "^3.0.2" 68 | } 69 | }, 70 | "node_modules/@types/react-dom": { 71 | "version": "18.0.6", 72 | "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.6.tgz", 73 | "integrity": "sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==", 74 | "dev": true, 75 | "dependencies": { 76 | "@types/react": "*" 77 | } 78 | }, 79 | "node_modules/@types/scheduler": { 80 | "version": "0.16.2", 81 | "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", 82 | "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", 83 | "dev": true 84 | }, 85 | "node_modules/camel-case": { 86 | "version": "3.0.0", 87 | "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", 88 | "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", 89 | "dev": true, 90 | "dependencies": { 91 | "no-case": "^2.2.0", 92 | "upper-case": "^1.1.1" 93 | } 94 | }, 95 | "node_modules/clean-css": { 96 | "version": "4.2.4", 97 | "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", 98 | "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", 99 | "dev": true, 100 | "dependencies": { 101 | "source-map": "~0.6.0" 102 | }, 103 | "engines": { 104 | "node": ">= 4.0" 105 | } 106 | }, 107 | "node_modules/commander": { 108 | "version": "2.20.3", 109 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 110 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", 111 | "dev": true 112 | }, 113 | "node_modules/csstype": { 114 | "version": "3.1.0", 115 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", 116 | "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==", 117 | "dev": true 118 | }, 119 | "node_modules/esbuild": { 120 | "version": "0.15.5", 121 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.5.tgz", 122 | "integrity": "sha512-VSf6S1QVqvxfIsSKb3UKr3VhUCis7wgDbtF4Vd9z84UJr05/Sp2fRKmzC+CSPG/dNAPPJZ0BTBLTT1Fhd6N9Gg==", 123 | "dev": true, 124 | "hasInstallScript": true, 125 | "bin": { 126 | "esbuild": "bin/esbuild" 127 | }, 128 | "engines": { 129 | "node": ">=12" 130 | }, 131 | "optionalDependencies": { 132 | "@esbuild/linux-loong64": "0.15.5", 133 | "esbuild-android-64": "0.15.5", 134 | "esbuild-android-arm64": "0.15.5", 135 | "esbuild-darwin-64": "0.15.5", 136 | "esbuild-darwin-arm64": "0.15.5", 137 | "esbuild-freebsd-64": "0.15.5", 138 | "esbuild-freebsd-arm64": "0.15.5", 139 | "esbuild-linux-32": "0.15.5", 140 | "esbuild-linux-64": "0.15.5", 141 | "esbuild-linux-arm": "0.15.5", 142 | "esbuild-linux-arm64": "0.15.5", 143 | "esbuild-linux-mips64le": "0.15.5", 144 | "esbuild-linux-ppc64le": "0.15.5", 145 | "esbuild-linux-riscv64": "0.15.5", 146 | "esbuild-linux-s390x": "0.15.5", 147 | "esbuild-netbsd-64": "0.15.5", 148 | "esbuild-openbsd-64": "0.15.5", 149 | "esbuild-sunos-64": "0.15.5", 150 | "esbuild-windows-32": "0.15.5", 151 | "esbuild-windows-64": "0.15.5", 152 | "esbuild-windows-arm64": "0.15.5" 153 | } 154 | }, 155 | "node_modules/esbuild-android-64": { 156 | "version": "0.15.5", 157 | "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.5.tgz", 158 | "integrity": "sha512-dYPPkiGNskvZqmIK29OPxolyY3tp+c47+Fsc2WYSOVjEPWNCHNyqhtFqQadcXMJDQt8eN0NMDukbyQgFcHquXg==", 159 | "cpu": [ 160 | "x64" 161 | ], 162 | "dev": true, 163 | "optional": true, 164 | "os": [ 165 | "android" 166 | ], 167 | "engines": { 168 | "node": ">=12" 169 | } 170 | }, 171 | "node_modules/esbuild-android-arm64": { 172 | "version": "0.15.5", 173 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.5.tgz", 174 | "integrity": "sha512-YyEkaQl08ze3cBzI/4Cm1S+rVh8HMOpCdq8B78JLbNFHhzi4NixVN93xDrHZLztlocEYqi45rHHCgA8kZFidFg==", 175 | "cpu": [ 176 | "arm64" 177 | ], 178 | "dev": true, 179 | "optional": true, 180 | "os": [ 181 | "android" 182 | ], 183 | "engines": { 184 | "node": ">=12" 185 | } 186 | }, 187 | "node_modules/esbuild-darwin-64": { 188 | "version": "0.15.5", 189 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.5.tgz", 190 | "integrity": "sha512-Cr0iIqnWKx3ZTvDUAzG0H/u9dWjLE4c2gTtRLz4pqOBGjfjqdcZSfAObFzKTInLLSmD0ZV1I/mshhPoYSBMMCQ==", 191 | "cpu": [ 192 | "x64" 193 | ], 194 | "dev": true, 195 | "optional": true, 196 | "os": [ 197 | "darwin" 198 | ], 199 | "engines": { 200 | "node": ">=12" 201 | } 202 | }, 203 | "node_modules/esbuild-darwin-arm64": { 204 | "version": "0.15.5", 205 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.5.tgz", 206 | "integrity": "sha512-WIfQkocGtFrz7vCu44ypY5YmiFXpsxvz2xqwe688jFfSVCnUsCn2qkEVDo7gT8EpsLOz1J/OmqjExePL1dr1Kg==", 207 | "cpu": [ 208 | "arm64" 209 | ], 210 | "dev": true, 211 | "optional": true, 212 | "os": [ 213 | "darwin" 214 | ], 215 | "engines": { 216 | "node": ">=12" 217 | } 218 | }, 219 | "node_modules/esbuild-freebsd-64": { 220 | "version": "0.15.5", 221 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.5.tgz", 222 | "integrity": "sha512-M5/EfzV2RsMd/wqwR18CELcenZ8+fFxQAAEO7TJKDmP3knhWSbD72ILzrXFMMwshlPAS1ShCZ90jsxkm+8FlaA==", 223 | "cpu": [ 224 | "x64" 225 | ], 226 | "dev": true, 227 | "optional": true, 228 | "os": [ 229 | "freebsd" 230 | ], 231 | "engines": { 232 | "node": ">=12" 233 | } 234 | }, 235 | "node_modules/esbuild-freebsd-arm64": { 236 | "version": "0.15.5", 237 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.5.tgz", 238 | "integrity": "sha512-2JQQ5Qs9J0440F/n/aUBNvY6lTo4XP/4lt1TwDfHuo0DY3w5++anw+jTjfouLzbJmFFiwmX7SmUhMnysocx96w==", 239 | "cpu": [ 240 | "arm64" 241 | ], 242 | "dev": true, 243 | "optional": true, 244 | "os": [ 245 | "freebsd" 246 | ], 247 | "engines": { 248 | "node": ">=12" 249 | } 250 | }, 251 | "node_modules/esbuild-linux-32": { 252 | "version": "0.15.5", 253 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.5.tgz", 254 | "integrity": "sha512-gO9vNnIN0FTUGjvTFucIXtBSr1Woymmx/aHQtuU+2OllGU6YFLs99960UD4Dib1kFovVgs59MTXwpFdVoSMZoQ==", 255 | "cpu": [ 256 | "ia32" 257 | ], 258 | "dev": true, 259 | "optional": true, 260 | "os": [ 261 | "linux" 262 | ], 263 | "engines": { 264 | "node": ">=12" 265 | } 266 | }, 267 | "node_modules/esbuild-linux-64": { 268 | "version": "0.15.5", 269 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.5.tgz", 270 | "integrity": "sha512-ne0GFdNLsm4veXbTnYAWjbx3shpNKZJUd6XpNbKNUZaNllDZfYQt0/zRqOg0sc7O8GQ+PjSMv9IpIEULXVTVmg==", 271 | "cpu": [ 272 | "x64" 273 | ], 274 | "dev": true, 275 | "optional": true, 276 | "os": [ 277 | "linux" 278 | ], 279 | "engines": { 280 | "node": ">=12" 281 | } 282 | }, 283 | "node_modules/esbuild-linux-arm": { 284 | "version": "0.15.5", 285 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.5.tgz", 286 | "integrity": "sha512-wvAoHEN+gJ/22gnvhZnS/+2H14HyAxM07m59RSLn3iXrQsdS518jnEWRBnJz3fR6BJa+VUTo0NxYjGaNt7RA7Q==", 287 | "cpu": [ 288 | "arm" 289 | ], 290 | "dev": true, 291 | "optional": true, 292 | "os": [ 293 | "linux" 294 | ], 295 | "engines": { 296 | "node": ">=12" 297 | } 298 | }, 299 | "node_modules/esbuild-linux-arm64": { 300 | "version": "0.15.5", 301 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.5.tgz", 302 | "integrity": "sha512-7EgFyP2zjO065XTfdCxiXVEk+f83RQ1JsryN1X/VSX2li9rnHAt2swRbpoz5Vlrl6qjHrCmq5b6yxD13z6RheA==", 303 | "cpu": [ 304 | "arm64" 305 | ], 306 | "dev": true, 307 | "optional": true, 308 | "os": [ 309 | "linux" 310 | ], 311 | "engines": { 312 | "node": ">=12" 313 | } 314 | }, 315 | "node_modules/esbuild-linux-mips64le": { 316 | "version": "0.15.5", 317 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.5.tgz", 318 | "integrity": "sha512-KdnSkHxWrJ6Y40ABu+ipTZeRhFtc8dowGyFsZY5prsmMSr1ZTG9zQawguN4/tunJ0wy3+kD54GaGwdcpwWAvZQ==", 319 | "cpu": [ 320 | "mips64el" 321 | ], 322 | "dev": true, 323 | "optional": true, 324 | "os": [ 325 | "linux" 326 | ], 327 | "engines": { 328 | "node": ">=12" 329 | } 330 | }, 331 | "node_modules/esbuild-linux-ppc64le": { 332 | "version": "0.15.5", 333 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.5.tgz", 334 | "integrity": "sha512-QdRHGeZ2ykl5P0KRmfGBZIHmqcwIsUKWmmpZTOq573jRWwmpfRmS7xOhmDHBj9pxv+6qRMH8tLr2fe+ZKQvCYw==", 335 | "cpu": [ 336 | "ppc64" 337 | ], 338 | "dev": true, 339 | "optional": true, 340 | "os": [ 341 | "linux" 342 | ], 343 | "engines": { 344 | "node": ">=12" 345 | } 346 | }, 347 | "node_modules/esbuild-linux-riscv64": { 348 | "version": "0.15.5", 349 | "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.5.tgz", 350 | "integrity": "sha512-p+WE6RX+jNILsf+exR29DwgV6B73khEQV0qWUbzxaycxawZ8NE0wA6HnnTxbiw5f4Gx9sJDUBemh9v49lKOORA==", 351 | "cpu": [ 352 | "riscv64" 353 | ], 354 | "dev": true, 355 | "optional": true, 356 | "os": [ 357 | "linux" 358 | ], 359 | "engines": { 360 | "node": ">=12" 361 | } 362 | }, 363 | "node_modules/esbuild-linux-s390x": { 364 | "version": "0.15.5", 365 | "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.5.tgz", 366 | "integrity": "sha512-J2ngOB4cNzmqLHh6TYMM/ips8aoZIuzxJnDdWutBw5482jGXiOzsPoEF4j2WJ2mGnm7FBCO4StGcwzOgic70JQ==", 367 | "cpu": [ 368 | "s390x" 369 | ], 370 | "dev": true, 371 | "optional": true, 372 | "os": [ 373 | "linux" 374 | ], 375 | "engines": { 376 | "node": ">=12" 377 | } 378 | }, 379 | "node_modules/esbuild-netbsd-64": { 380 | "version": "0.15.5", 381 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.5.tgz", 382 | "integrity": "sha512-MmKUYGDizYjFia0Rwt8oOgmiFH7zaYlsoQ3tIOfPxOqLssAsEgG0MUdRDm5lliqjiuoog8LyDu9srQk5YwWF3w==", 383 | "cpu": [ 384 | "x64" 385 | ], 386 | "dev": true, 387 | "optional": true, 388 | "os": [ 389 | "netbsd" 390 | ], 391 | "engines": { 392 | "node": ">=12" 393 | } 394 | }, 395 | "node_modules/esbuild-openbsd-64": { 396 | "version": "0.15.5", 397 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.5.tgz", 398 | "integrity": "sha512-2mMFfkLk3oPWfopA9Plj4hyhqHNuGyp5KQyTT9Rc8hFd8wAn5ZrbJg+gNcLMo2yzf8Uiu0RT6G9B15YN9WQyMA==", 399 | "cpu": [ 400 | "x64" 401 | ], 402 | "dev": true, 403 | "optional": true, 404 | "os": [ 405 | "openbsd" 406 | ], 407 | "engines": { 408 | "node": ">=12" 409 | } 410 | }, 411 | "node_modules/esbuild-sunos-64": { 412 | "version": "0.15.5", 413 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.5.tgz", 414 | "integrity": "sha512-2sIzhMUfLNoD+rdmV6AacilCHSxZIoGAU2oT7XmJ0lXcZWnCvCtObvO6D4puxX9YRE97GodciRGDLBaiC6x1SA==", 415 | "cpu": [ 416 | "x64" 417 | ], 418 | "dev": true, 419 | "optional": true, 420 | "os": [ 421 | "sunos" 422 | ], 423 | "engines": { 424 | "node": ">=12" 425 | } 426 | }, 427 | "node_modules/esbuild-windows-32": { 428 | "version": "0.15.5", 429 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.5.tgz", 430 | "integrity": "sha512-e+duNED9UBop7Vnlap6XKedA/53lIi12xv2ebeNS4gFmu7aKyTrok7DPIZyU5w/ftHD4MUDs5PJUkQPP9xJRzg==", 431 | "cpu": [ 432 | "ia32" 433 | ], 434 | "dev": true, 435 | "optional": true, 436 | "os": [ 437 | "win32" 438 | ], 439 | "engines": { 440 | "node": ">=12" 441 | } 442 | }, 443 | "node_modules/esbuild-windows-64": { 444 | "version": "0.15.5", 445 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.5.tgz", 446 | "integrity": "sha512-v+PjvNtSASHOjPDMIai9Yi+aP+Vwox+3WVdg2JB8N9aivJ7lyhp4NVU+J0MV2OkWFPnVO8AE/7xH+72ibUUEnw==", 447 | "cpu": [ 448 | "x64" 449 | ], 450 | "dev": true, 451 | "optional": true, 452 | "os": [ 453 | "win32" 454 | ], 455 | "engines": { 456 | "node": ">=12" 457 | } 458 | }, 459 | "node_modules/esbuild-windows-arm64": { 460 | "version": "0.15.5", 461 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.5.tgz", 462 | "integrity": "sha512-Yz8w/D8CUPYstvVQujByu6mlf48lKmXkq6bkeSZZxTA626efQOJb26aDGLzmFWx6eg/FwrXgt6SZs9V8Pwy/aA==", 463 | "cpu": [ 464 | "arm64" 465 | ], 466 | "dev": true, 467 | "optional": true, 468 | "os": [ 469 | "win32" 470 | ], 471 | "engines": { 472 | "node": ">=12" 473 | } 474 | }, 475 | "node_modules/he": { 476 | "version": "1.2.0", 477 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 478 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 479 | "dev": true, 480 | "bin": { 481 | "he": "bin/he" 482 | } 483 | }, 484 | "node_modules/html-minifier": { 485 | "version": "4.0.0", 486 | "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz", 487 | "integrity": "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==", 488 | "dev": true, 489 | "dependencies": { 490 | "camel-case": "^3.0.0", 491 | "clean-css": "^4.2.1", 492 | "commander": "^2.19.0", 493 | "he": "^1.2.0", 494 | "param-case": "^2.1.1", 495 | "relateurl": "^0.2.7", 496 | "uglify-js": "^3.5.1" 497 | }, 498 | "bin": { 499 | "html-minifier": "cli.js" 500 | }, 501 | "engines": { 502 | "node": ">=6" 503 | } 504 | }, 505 | "node_modules/js-tokens": { 506 | "version": "4.0.0", 507 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 508 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" 509 | }, 510 | "node_modules/loose-envify": { 511 | "version": "1.4.0", 512 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", 513 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", 514 | "dependencies": { 515 | "js-tokens": "^3.0.0 || ^4.0.0" 516 | }, 517 | "bin": { 518 | "loose-envify": "cli.js" 519 | } 520 | }, 521 | "node_modules/lower-case": { 522 | "version": "1.1.4", 523 | "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", 524 | "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", 525 | "dev": true 526 | }, 527 | "node_modules/no-case": { 528 | "version": "2.3.2", 529 | "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", 530 | "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", 531 | "dev": true, 532 | "dependencies": { 533 | "lower-case": "^1.1.1" 534 | } 535 | }, 536 | "node_modules/param-case": { 537 | "version": "2.1.1", 538 | "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", 539 | "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", 540 | "dev": true, 541 | "dependencies": { 542 | "no-case": "^2.2.0" 543 | } 544 | }, 545 | "node_modules/react": { 546 | "version": "18.2.0", 547 | "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", 548 | "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", 549 | "dependencies": { 550 | "loose-envify": "^1.1.0" 551 | }, 552 | "engines": { 553 | "node": ">=0.10.0" 554 | } 555 | }, 556 | "node_modules/react-dom": { 557 | "version": "18.2.0", 558 | "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", 559 | "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", 560 | "dependencies": { 561 | "loose-envify": "^1.1.0", 562 | "scheduler": "^0.23.0" 563 | }, 564 | "peerDependencies": { 565 | "react": "^18.2.0" 566 | } 567 | }, 568 | "node_modules/relateurl": { 569 | "version": "0.2.7", 570 | "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", 571 | "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", 572 | "dev": true, 573 | "engines": { 574 | "node": ">= 0.10" 575 | } 576 | }, 577 | "node_modules/scheduler": { 578 | "version": "0.23.0", 579 | "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", 580 | "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", 581 | "dependencies": { 582 | "loose-envify": "^1.1.0" 583 | } 584 | }, 585 | "node_modules/source-map": { 586 | "version": "0.6.1", 587 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 588 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 589 | "dev": true, 590 | "engines": { 591 | "node": ">=0.10.0" 592 | } 593 | }, 594 | "node_modules/typescript": { 595 | "version": "4.7.4", 596 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", 597 | "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", 598 | "dev": true, 599 | "bin": { 600 | "tsc": "bin/tsc", 601 | "tsserver": "bin/tsserver" 602 | }, 603 | "engines": { 604 | "node": ">=4.2.0" 605 | } 606 | }, 607 | "node_modules/uglify-js": { 608 | "version": "3.17.0", 609 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.0.tgz", 610 | "integrity": "sha512-aTeNPVmgIMPpm1cxXr2Q/nEbvkmV8yq66F3om7X3P/cvOXQ0TMQ64Wk63iyT1gPlmdmGzjGpyLh1f3y8MZWXGg==", 611 | "dev": true, 612 | "bin": { 613 | "uglifyjs": "bin/uglifyjs" 614 | }, 615 | "engines": { 616 | "node": ">=0.8.0" 617 | } 618 | }, 619 | "node_modules/upper-case": { 620 | "version": "1.1.3", 621 | "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", 622 | "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==", 623 | "dev": true 624 | } 625 | }, 626 | "dependencies": { 627 | "@esbuild/linux-loong64": { 628 | "version": "0.15.5", 629 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.5.tgz", 630 | "integrity": "sha512-UHkDFCfSGTuXq08oQltXxSZmH1TXyWsL+4QhZDWvvLl6mEJQqk3u7/wq1LjhrrAXYIllaTtRSzUXl4Olkf2J8A==", 631 | "dev": true, 632 | "optional": true 633 | }, 634 | "@figma/plugin-typings": { 635 | "version": "1.50.0", 636 | "resolved": "https://registry.npmjs.org/@figma/plugin-typings/-/plugin-typings-1.50.0.tgz", 637 | "integrity": "sha512-ue1He4XimFEjY7eS7x6tBY6pyMp7zfVOjgStFioqKUxPPIz0gCFLmFUjR5g6fMrYJCqAMP5/Mjwq4Ks0vpe2sA==", 638 | "dev": true 639 | }, 640 | "@types/node": { 641 | "version": "18.7.6", 642 | "resolved": "https://registry.npmjs.org/@types/node/-/node-18.7.6.tgz", 643 | "integrity": "sha512-EdxgKRXgYsNITy5mjjXjVE/CS8YENSdhiagGrLqjG0pvA2owgJ6i4l7wy/PFZGC0B1/H20lWKN7ONVDNYDZm7A==", 644 | "dev": true 645 | }, 646 | "@types/prop-types": { 647 | "version": "15.7.5", 648 | "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", 649 | "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", 650 | "dev": true 651 | }, 652 | "@types/react": { 653 | "version": "18.0.17", 654 | "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.17.tgz", 655 | "integrity": "sha512-38ETy4tL+rn4uQQi7mB81G7V1g0u2ryquNmsVIOKUAEIDK+3CUjZ6rSRpdvS99dNBnkLFL83qfmtLacGOTIhwQ==", 656 | "dev": true, 657 | "requires": { 658 | "@types/prop-types": "*", 659 | "@types/scheduler": "*", 660 | "csstype": "^3.0.2" 661 | } 662 | }, 663 | "@types/react-dom": { 664 | "version": "18.0.6", 665 | "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.6.tgz", 666 | "integrity": "sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==", 667 | "dev": true, 668 | "requires": { 669 | "@types/react": "*" 670 | } 671 | }, 672 | "@types/scheduler": { 673 | "version": "0.16.2", 674 | "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", 675 | "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", 676 | "dev": true 677 | }, 678 | "camel-case": { 679 | "version": "3.0.0", 680 | "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", 681 | "integrity": "sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w==", 682 | "dev": true, 683 | "requires": { 684 | "no-case": "^2.2.0", 685 | "upper-case": "^1.1.1" 686 | } 687 | }, 688 | "clean-css": { 689 | "version": "4.2.4", 690 | "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.4.tgz", 691 | "integrity": "sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A==", 692 | "dev": true, 693 | "requires": { 694 | "source-map": "~0.6.0" 695 | } 696 | }, 697 | "commander": { 698 | "version": "2.20.3", 699 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", 700 | "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", 701 | "dev": true 702 | }, 703 | "csstype": { 704 | "version": "3.1.0", 705 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz", 706 | "integrity": "sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==", 707 | "dev": true 708 | }, 709 | "esbuild": { 710 | "version": "0.15.5", 711 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.5.tgz", 712 | "integrity": "sha512-VSf6S1QVqvxfIsSKb3UKr3VhUCis7wgDbtF4Vd9z84UJr05/Sp2fRKmzC+CSPG/dNAPPJZ0BTBLTT1Fhd6N9Gg==", 713 | "dev": true, 714 | "requires": { 715 | "@esbuild/linux-loong64": "0.15.5", 716 | "esbuild-android-64": "0.15.5", 717 | "esbuild-android-arm64": "0.15.5", 718 | "esbuild-darwin-64": "0.15.5", 719 | "esbuild-darwin-arm64": "0.15.5", 720 | "esbuild-freebsd-64": "0.15.5", 721 | "esbuild-freebsd-arm64": "0.15.5", 722 | "esbuild-linux-32": "0.15.5", 723 | "esbuild-linux-64": "0.15.5", 724 | "esbuild-linux-arm": "0.15.5", 725 | "esbuild-linux-arm64": "0.15.5", 726 | "esbuild-linux-mips64le": "0.15.5", 727 | "esbuild-linux-ppc64le": "0.15.5", 728 | "esbuild-linux-riscv64": "0.15.5", 729 | "esbuild-linux-s390x": "0.15.5", 730 | "esbuild-netbsd-64": "0.15.5", 731 | "esbuild-openbsd-64": "0.15.5", 732 | "esbuild-sunos-64": "0.15.5", 733 | "esbuild-windows-32": "0.15.5", 734 | "esbuild-windows-64": "0.15.5", 735 | "esbuild-windows-arm64": "0.15.5" 736 | } 737 | }, 738 | "esbuild-android-64": { 739 | "version": "0.15.5", 740 | "resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.5.tgz", 741 | "integrity": "sha512-dYPPkiGNskvZqmIK29OPxolyY3tp+c47+Fsc2WYSOVjEPWNCHNyqhtFqQadcXMJDQt8eN0NMDukbyQgFcHquXg==", 742 | "dev": true, 743 | "optional": true 744 | }, 745 | "esbuild-android-arm64": { 746 | "version": "0.15.5", 747 | "resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.5.tgz", 748 | "integrity": "sha512-YyEkaQl08ze3cBzI/4Cm1S+rVh8HMOpCdq8B78JLbNFHhzi4NixVN93xDrHZLztlocEYqi45rHHCgA8kZFidFg==", 749 | "dev": true, 750 | "optional": true 751 | }, 752 | "esbuild-darwin-64": { 753 | "version": "0.15.5", 754 | "resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.5.tgz", 755 | "integrity": "sha512-Cr0iIqnWKx3ZTvDUAzG0H/u9dWjLE4c2gTtRLz4pqOBGjfjqdcZSfAObFzKTInLLSmD0ZV1I/mshhPoYSBMMCQ==", 756 | "dev": true, 757 | "optional": true 758 | }, 759 | "esbuild-darwin-arm64": { 760 | "version": "0.15.5", 761 | "resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.5.tgz", 762 | "integrity": "sha512-WIfQkocGtFrz7vCu44ypY5YmiFXpsxvz2xqwe688jFfSVCnUsCn2qkEVDo7gT8EpsLOz1J/OmqjExePL1dr1Kg==", 763 | "dev": true, 764 | "optional": true 765 | }, 766 | "esbuild-freebsd-64": { 767 | "version": "0.15.5", 768 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.5.tgz", 769 | "integrity": "sha512-M5/EfzV2RsMd/wqwR18CELcenZ8+fFxQAAEO7TJKDmP3knhWSbD72ILzrXFMMwshlPAS1ShCZ90jsxkm+8FlaA==", 770 | "dev": true, 771 | "optional": true 772 | }, 773 | "esbuild-freebsd-arm64": { 774 | "version": "0.15.5", 775 | "resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.5.tgz", 776 | "integrity": "sha512-2JQQ5Qs9J0440F/n/aUBNvY6lTo4XP/4lt1TwDfHuo0DY3w5++anw+jTjfouLzbJmFFiwmX7SmUhMnysocx96w==", 777 | "dev": true, 778 | "optional": true 779 | }, 780 | "esbuild-linux-32": { 781 | "version": "0.15.5", 782 | "resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.5.tgz", 783 | "integrity": "sha512-gO9vNnIN0FTUGjvTFucIXtBSr1Woymmx/aHQtuU+2OllGU6YFLs99960UD4Dib1kFovVgs59MTXwpFdVoSMZoQ==", 784 | "dev": true, 785 | "optional": true 786 | }, 787 | "esbuild-linux-64": { 788 | "version": "0.15.5", 789 | "resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.5.tgz", 790 | "integrity": "sha512-ne0GFdNLsm4veXbTnYAWjbx3shpNKZJUd6XpNbKNUZaNllDZfYQt0/zRqOg0sc7O8GQ+PjSMv9IpIEULXVTVmg==", 791 | "dev": true, 792 | "optional": true 793 | }, 794 | "esbuild-linux-arm": { 795 | "version": "0.15.5", 796 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.5.tgz", 797 | "integrity": "sha512-wvAoHEN+gJ/22gnvhZnS/+2H14HyAxM07m59RSLn3iXrQsdS518jnEWRBnJz3fR6BJa+VUTo0NxYjGaNt7RA7Q==", 798 | "dev": true, 799 | "optional": true 800 | }, 801 | "esbuild-linux-arm64": { 802 | "version": "0.15.5", 803 | "resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.5.tgz", 804 | "integrity": "sha512-7EgFyP2zjO065XTfdCxiXVEk+f83RQ1JsryN1X/VSX2li9rnHAt2swRbpoz5Vlrl6qjHrCmq5b6yxD13z6RheA==", 805 | "dev": true, 806 | "optional": true 807 | }, 808 | "esbuild-linux-mips64le": { 809 | "version": "0.15.5", 810 | "resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.5.tgz", 811 | "integrity": "sha512-KdnSkHxWrJ6Y40ABu+ipTZeRhFtc8dowGyFsZY5prsmMSr1ZTG9zQawguN4/tunJ0wy3+kD54GaGwdcpwWAvZQ==", 812 | "dev": true, 813 | "optional": true 814 | }, 815 | "esbuild-linux-ppc64le": { 816 | "version": "0.15.5", 817 | "resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.5.tgz", 818 | "integrity": "sha512-QdRHGeZ2ykl5P0KRmfGBZIHmqcwIsUKWmmpZTOq573jRWwmpfRmS7xOhmDHBj9pxv+6qRMH8tLr2fe+ZKQvCYw==", 819 | "dev": true, 820 | "optional": true 821 | }, 822 | "esbuild-linux-riscv64": { 823 | "version": "0.15.5", 824 | "resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.5.tgz", 825 | "integrity": "sha512-p+WE6RX+jNILsf+exR29DwgV6B73khEQV0qWUbzxaycxawZ8NE0wA6HnnTxbiw5f4Gx9sJDUBemh9v49lKOORA==", 826 | "dev": true, 827 | "optional": true 828 | }, 829 | "esbuild-linux-s390x": { 830 | "version": "0.15.5", 831 | "resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.5.tgz", 832 | "integrity": "sha512-J2ngOB4cNzmqLHh6TYMM/ips8aoZIuzxJnDdWutBw5482jGXiOzsPoEF4j2WJ2mGnm7FBCO4StGcwzOgic70JQ==", 833 | "dev": true, 834 | "optional": true 835 | }, 836 | "esbuild-netbsd-64": { 837 | "version": "0.15.5", 838 | "resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.5.tgz", 839 | "integrity": "sha512-MmKUYGDizYjFia0Rwt8oOgmiFH7zaYlsoQ3tIOfPxOqLssAsEgG0MUdRDm5lliqjiuoog8LyDu9srQk5YwWF3w==", 840 | "dev": true, 841 | "optional": true 842 | }, 843 | "esbuild-openbsd-64": { 844 | "version": "0.15.5", 845 | "resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.5.tgz", 846 | "integrity": "sha512-2mMFfkLk3oPWfopA9Plj4hyhqHNuGyp5KQyTT9Rc8hFd8wAn5ZrbJg+gNcLMo2yzf8Uiu0RT6G9B15YN9WQyMA==", 847 | "dev": true, 848 | "optional": true 849 | }, 850 | "esbuild-sunos-64": { 851 | "version": "0.15.5", 852 | "resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.5.tgz", 853 | "integrity": "sha512-2sIzhMUfLNoD+rdmV6AacilCHSxZIoGAU2oT7XmJ0lXcZWnCvCtObvO6D4puxX9YRE97GodciRGDLBaiC6x1SA==", 854 | "dev": true, 855 | "optional": true 856 | }, 857 | "esbuild-windows-32": { 858 | "version": "0.15.5", 859 | "resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.5.tgz", 860 | "integrity": "sha512-e+duNED9UBop7Vnlap6XKedA/53lIi12xv2ebeNS4gFmu7aKyTrok7DPIZyU5w/ftHD4MUDs5PJUkQPP9xJRzg==", 861 | "dev": true, 862 | "optional": true 863 | }, 864 | "esbuild-windows-64": { 865 | "version": "0.15.5", 866 | "resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.5.tgz", 867 | "integrity": "sha512-v+PjvNtSASHOjPDMIai9Yi+aP+Vwox+3WVdg2JB8N9aivJ7lyhp4NVU+J0MV2OkWFPnVO8AE/7xH+72ibUUEnw==", 868 | "dev": true, 869 | "optional": true 870 | }, 871 | "esbuild-windows-arm64": { 872 | "version": "0.15.5", 873 | "resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.5.tgz", 874 | "integrity": "sha512-Yz8w/D8CUPYstvVQujByu6mlf48lKmXkq6bkeSZZxTA626efQOJb26aDGLzmFWx6eg/FwrXgt6SZs9V8Pwy/aA==", 875 | "dev": true, 876 | "optional": true 877 | }, 878 | "he": { 879 | "version": "1.2.0", 880 | "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", 881 | "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", 882 | "dev": true 883 | }, 884 | "html-minifier": { 885 | "version": "4.0.0", 886 | "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-4.0.0.tgz", 887 | "integrity": "sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig==", 888 | "dev": true, 889 | "requires": { 890 | "camel-case": "^3.0.0", 891 | "clean-css": "^4.2.1", 892 | "commander": "^2.19.0", 893 | "he": "^1.2.0", 894 | "param-case": "^2.1.1", 895 | "relateurl": "^0.2.7", 896 | "uglify-js": "^3.5.1" 897 | } 898 | }, 899 | "js-tokens": { 900 | "version": "4.0.0", 901 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 902 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" 903 | }, 904 | "loose-envify": { 905 | "version": "1.4.0", 906 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", 907 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", 908 | "requires": { 909 | "js-tokens": "^3.0.0 || ^4.0.0" 910 | } 911 | }, 912 | "lower-case": { 913 | "version": "1.1.4", 914 | "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", 915 | "integrity": "sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA==", 916 | "dev": true 917 | }, 918 | "no-case": { 919 | "version": "2.3.2", 920 | "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", 921 | "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", 922 | "dev": true, 923 | "requires": { 924 | "lower-case": "^1.1.1" 925 | } 926 | }, 927 | "param-case": { 928 | "version": "2.1.1", 929 | "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", 930 | "integrity": "sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w==", 931 | "dev": true, 932 | "requires": { 933 | "no-case": "^2.2.0" 934 | } 935 | }, 936 | "react": { 937 | "version": "18.2.0", 938 | "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", 939 | "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", 940 | "requires": { 941 | "loose-envify": "^1.1.0" 942 | } 943 | }, 944 | "react-dom": { 945 | "version": "18.2.0", 946 | "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", 947 | "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", 948 | "requires": { 949 | "loose-envify": "^1.1.0", 950 | "scheduler": "^0.23.0" 951 | } 952 | }, 953 | "relateurl": { 954 | "version": "0.2.7", 955 | "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", 956 | "integrity": "sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==", 957 | "dev": true 958 | }, 959 | "scheduler": { 960 | "version": "0.23.0", 961 | "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", 962 | "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", 963 | "requires": { 964 | "loose-envify": "^1.1.0" 965 | } 966 | }, 967 | "source-map": { 968 | "version": "0.6.1", 969 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 970 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 971 | "dev": true 972 | }, 973 | "typescript": { 974 | "version": "4.7.4", 975 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", 976 | "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", 977 | "dev": true 978 | }, 979 | "uglify-js": { 980 | "version": "3.17.0", 981 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.0.tgz", 982 | "integrity": "sha512-aTeNPVmgIMPpm1cxXr2Q/nEbvkmV8yq66F3om7X3P/cvOXQ0TMQ64Wk63iyT1gPlmdmGzjGpyLh1f3y8MZWXGg==", 983 | "dev": true 984 | }, 985 | "upper-case": { 986 | "version": "1.1.3", 987 | "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", 988 | "integrity": "sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA==", 989 | "dev": true 990 | } 991 | } 992 | } 993 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "plugin-template", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "node ./scripts/build.js", 8 | "dev": "node ./scripts/dev.js" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "MIT", 13 | "devDependencies": { 14 | "@figma/plugin-typings": "^1.50.0", 15 | "@types/node": "^18.7.6", 16 | "@types/react": "^18.0.17", 17 | "@types/react-dom": "^18.0.6", 18 | "esbuild": "^0.15.5", 19 | "html-minifier": "^4.0.0", 20 | "typescript": "^4.7.4" 21 | }, 22 | "dependencies": { 23 | "react": "^18.2.0", 24 | "react-dom": "^18.2.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /scripts/README.md: -------------------------------------------------------------------------------- 1 | This folder contains utility scripts that are used for bundling. 2 | -------------------------------------------------------------------------------- /scripts/build.js: -------------------------------------------------------------------------------- 1 | const { buildPlugin, buildUi } = require("./util"); 2 | 3 | buildPlugin(); 4 | buildUi(); 5 | -------------------------------------------------------------------------------- /scripts/dev.js: -------------------------------------------------------------------------------- 1 | const { buildPlugin, buildUi } = require("./util"); 2 | 3 | buildPlugin(true); 4 | buildUi(true); 5 | -------------------------------------------------------------------------------- /scripts/util.js: -------------------------------------------------------------------------------- 1 | const esbuild = require("esbuild"); 2 | const { minify } = require("html-minifier"); 3 | const fs = require("fs/promises"); 4 | 5 | /** 6 | * buildPlugin builds figma plugin core. 7 | * @param {boolean} watch 8 | */ 9 | const buildPlugin = async (watch = false) => { 10 | await esbuild.build({ 11 | entryPoints: ["./src/plugin/run.ts"], 12 | bundle: true, 13 | minify: true, 14 | outfile: "./build/plugin.js", 15 | logLevel: "info", 16 | watch, 17 | }); 18 | }; 19 | 20 | /** 21 | * htmlOutput puts css and js bundles produced by esbuild into html single file. 22 | * @param {esbuild.BuildResult} buildResult 23 | */ 24 | const htmlOutput = async (buildResult) => { 25 | const jsBundle = buildResult.outputFiles.find((file) => 26 | file.path.endsWith(".js") 27 | ); 28 | 29 | const cssBundle = buildResult.outputFiles.find((file) => 30 | file.path.endsWith(".css") 31 | ); 32 | 33 | let html = (await fs.readFile("./src/ui/ui.html")).toString(); 34 | const headClosing = html.indexOf(""); 35 | const bodyClosing = html.indexOf("
15 | 16 | 25 |");
36 |
37 | html =
38 | html.slice(0, headClosing) +
39 | `` +
40 | html.slice(headClosing, bodyClosing) +
41 | `` +
42 | html.slice(bodyClosing);
43 |
44 | await fs.writeFile(
45 | "./build/ui.html",
46 | minify(html, {
47 | removeComments: true,
48 | collapseWhitespace: true,
49 | })
50 | );
51 | };
52 |
53 | /**
54 | * buildUi builds figma plugin ui.
55 | * @param {boolean} watch
56 | */
57 | const buildUi = async (watch = false) => {
58 | const result = await esbuild.build({
59 | entryPoints: ["./src/ui/main.tsx"],
60 | jsx: "automatic",
61 | bundle: true,
62 | minify: true,
63 | write: false,
64 | outdir: "./build",
65 | logLevel: "info",
66 | watch,
67 | });
68 |
69 | await htmlOutput(result);
70 | };
71 |
72 | module.exports = {
73 | buildPlugin,
74 | buildUi,
75 | };
76 |
--------------------------------------------------------------------------------
/src/plugin/run.ts:
--------------------------------------------------------------------------------
1 | figma.showUI(__html__, { themeColors: true });
2 |
3 | figma.ui.onmessage = (msg) => {
4 | if (msg.type === "create-rectangles") {
5 | const nodes = [];
6 |
7 | for (let i = 0; i < msg.count; i++) {
8 | const rect = figma.createRectangle();
9 | rect.x = i * 150;
10 | rect.fills = [{ type: "SOLID", color: { r: 1, g: 0.5, b: 0 } }];
11 | nodes.push(rect);
12 | }
13 |
14 | figma.currentPage.selection = nodes;
15 | figma.viewport.scrollAndZoomIntoView(nodes);
16 | }
17 |
18 | figma.closePlugin();
19 | };
20 |
--------------------------------------------------------------------------------
/src/ui/index.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | font-family: "Inter", sans-serif;
5 | }
6 |
7 | *,
8 | *::after,
9 | *::before {
10 | box-sizing: border-box;
11 | }
12 |
--------------------------------------------------------------------------------
/src/ui/main.tsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom/client";
3 | import "./index.css";
4 |
5 | import { Ui } from "./ui";
6 |
7 | ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
8 |
4 | 5 | 6 | 7 | 8 | 12 |
13 | 14 |
26 |