├── .github └── workflows │ └── main.yml ├── .gitignore ├── .prettierignore ├── README.md ├── cli.js ├── create-widget.js ├── package-lock.json ├── package.json ├── templates ├── widget-with-ui │ ├── README.md │ ├── manifest.json │ ├── package.json │ ├── ui-src │ │ ├── App.css │ │ ├── App.tsx │ │ ├── index.css │ │ ├── index.html │ │ ├── main.tsx │ │ ├── tsconfig.json │ │ └── vite-env.d.ts │ ├── vite.config.ts │ └── widget-src │ │ ├── code.tsx │ │ └── tsconfig.json └── widget-without-ui │ ├── README.md │ ├── manifest.json │ ├── package.json │ └── widget-src │ ├── code.tsx │ └── tsconfig.json └── test-usage.sh /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | workflow_dispatch: 10 | 11 | jobs: 12 | basic-tests: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Setup Node.js environment 17 | uses: actions/setup-node@v2.1.4 18 | - uses: bahmutov/npm-install@v1 19 | - name: Install Dependencies 20 | if: steps.cache.outputs.cache-hit != 'true' 21 | run: npm ci 22 | - name: prettier 23 | run: npm run format:check 24 | - run: ./test-usage.sh 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .git 2 | 3 | # Node 4 | *.log 5 | *.log.* 6 | node_modules 7 | 8 | # JetBrains IDE 9 | .idea 10 | scopes 11 | 12 | # Sublime IDE 13 | *.sublime-project 14 | *.sublime-workspace 15 | 16 | # vscode IDE 17 | .vscode 18 | 19 | # OSX 20 | .DS_Store 21 | 22 | test/ 23 | test-artifacts/ 24 | templates/*/package-lock.json 25 | 26 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | *.json 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # @figma/create-widget 2 | 3 | [![npm](https://img.shields.io/npm/v/@figma/create-widget?logo=npm&cacheSeconds=1800)](https://www.npmjs.com/package/@figma/create-widget) 4 | 5 | Create new [Figma & FigJam widgets](https://figma.com/widget-docs) with a single command. 6 | 7 | ```bash 8 | npm init @figma/widget 9 | ``` 10 | 11 | ## Widget Organization 12 | 13 | The created widgets use: 14 | 15 | - [esbuild](https://esbuild.github.io/) for bundling 16 | - [vite](https://vitejs.dev/) and [react](https://reactjs.org/) if the iframe option is specified 17 | - [typescript](https://www.typescriptlang.org/) for typechecking 18 | 19 | | file/folder | description | 20 | | ------------- | -------------------------------------------------------------------------------- | 21 | | manifest.json | The widget's [manifest.json](https://www.figma.com/widget-docs/widget-manifest/) | 22 | | widget-src/ | Contains the widget code | 23 | | ui-src/ | Contains the iframe code | 24 | 25 | ## Getting Started 26 | 27 | After running `npm init @figma/widget`, follow the provided prompts. 28 | 29 | ### `npm run dev` 30 | 31 | This is the only command you need to run in development. It will start the following processes for you: 32 | 33 | - bundling (both widget and iframe code) 34 | - typechecking (both widget and iframe code) 35 | - vite dev server (for iframe development) 36 | 37 | ### `npm run build` 38 | 39 | This runs bundling with minification turned on. You should run this command before releasing your widget. 40 | 41 | ### `npm run test` 42 | 43 | This runs typechecking and makes sure that your widget builds without errors. 44 | 45 | ## Credit 46 | 47 | Credit to https://github.com/yuanqing/create-figma-plugin for providing a way to `npm init` widgets and plugins before this repository ever existed. 48 | -------------------------------------------------------------------------------- /cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import sade from "sade"; 3 | 4 | import { createWidget } from "./create-widget.js"; 5 | 6 | const description = ` 7 | Create a FigJam widget with a single command 8 | 9 | Examples 10 | $ npm init @figma/widget 11 | $ npm init @figma/widget -n Counter 12 | $ npm init @figma/widget -n Counter -p counter-widget --iframe=Y --editor-type figma,figjam 13 | `; 14 | 15 | sade("create-widget", true) 16 | .describe(description) 17 | .option("-n, --name", 'Name of your widget; defaults to "Widget"') 18 | .option( 19 | "-p, --package-name", 20 | 'Name of the folder containing your widget; defaults to "-widget"' 21 | ) 22 | .option( 23 | "-e, --editor-type", 24 | 'Editor type of widget; enter [figma | figjam | figma,figjam]; defaults to "figjam"' 25 | ) 26 | .option("-i, --iframe", "Whether the widget uses an iframe") 27 | .action(async function (options) { 28 | await createWidget({ options }); 29 | }) 30 | .parse(process.argv); 31 | -------------------------------------------------------------------------------- /create-widget.js: -------------------------------------------------------------------------------- 1 | import fs from "fs-extra"; 2 | import path from "path"; 3 | import cp from "child_process"; 4 | 5 | import { fileURLToPath } from "url"; 6 | import inquirer from "inquirer"; 7 | import { globby } from "globby"; 8 | import isUtf8 from "is-utf8"; 9 | import mustache from "mustache"; 10 | 11 | const __dirname = path.dirname(fileURLToPath(import.meta.url)); 12 | 13 | const INITIAL_PROMPT = `This tool will create a FigJam widget project using a template that serves as a starting point for building your widget. 14 | 15 | See the generated README.md for more information on how to use this template and get started building your widget. 16 | 17 | You can find the API reference for widgets here: https://www.figma.com/widget-docs/api/api-reference/ 18 | 19 | Press ^C at any time to quit.\n`; 20 | 21 | function makeid(length) { 22 | var result = ""; 23 | var characters = 24 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 25 | var charactersLength = characters.length; 26 | for (var i = 0; i < length; i++) { 27 | result += characters.charAt(Math.floor(Math.random() * charactersLength)); 28 | } 29 | return result; 30 | } 31 | 32 | function randomWidgetId() { 33 | return "widget-id-" + makeid(10); 34 | } 35 | 36 | export async function replaceTemplatizedValues(directory, values) { 37 | const filePaths = await globby("**/*", { 38 | cwd: directory, 39 | dot: true, 40 | }); 41 | await Promise.all( 42 | filePaths.map(async function (filePath) { 43 | const absolutePath = path.join(directory, filePath); 44 | const buffer = await fs.readFile(absolutePath); 45 | const fileContents = isUtf8(buffer) 46 | ? mustache.render(buffer.toString(), values) 47 | : buffer; 48 | await fs.outputFile(absolutePath, fileContents); 49 | }) 50 | ); 51 | } 52 | 53 | async function installDependencies(cwd, widgetname, destinationPath) { 54 | await new (function (resolve, reject) { 55 | const command = "npm install"; 56 | cp.exec(command, { cwd }, function (error) { 57 | if (error) { 58 | reject(error); 59 | return; 60 | } 61 | path.resolve(); 62 | 63 | console.log(); 64 | console.log(` 65 | Your widget has been created! 66 | 67 | 68 | Run the following commands to get started building your widget: 69 | 70 | cd ${destinationPath} 71 | npm run dev 72 | 73 | 74 | Import your widget into FigJam to start testing it: 75 | 76 | 1. Open a FigJam file using the Figma Desktop app to import your widget. 77 | 2. Right click > Widgets > Development > Import widget from manifest… and import the manifest.json file in your widget directory. 78 | 3. Insert your your widget: "Right click > Widgets > Development > ${widgetname}" 79 | `); 80 | }); 81 | })(); 82 | } 83 | 84 | async function copyTemplateFiles(pluginDirectoryPath, shouldAddUI) { 85 | const templateName = shouldAddUI ? "widget-with-ui" : "widget-without-ui"; 86 | const templateDirectory = path.resolve( 87 | __dirname, 88 | "..", 89 | "create-widget", 90 | "templates", 91 | templateName 92 | ); 93 | await fs.copy(templateDirectory, pluginDirectoryPath); 94 | } 95 | 96 | export async function createWidget(input) { 97 | try { 98 | console.log(INITIAL_PROMPT); 99 | let widgetName = input.options.name; 100 | if (widgetName === undefined) { 101 | const result = await inquirer.prompt([ 102 | { 103 | message: 104 | 'Enter the name of your widget: (empty defaults to "Widget")', 105 | name: "widgetName", 106 | type: "input", 107 | }, 108 | ]); 109 | widgetName = result.widgetName ? result.widgetName : "Widget"; 110 | } 111 | 112 | let destinationPath = input.options["package-name"]; 113 | if (destinationPath === undefined) { 114 | const defaultDestinationPath = `${widgetName.toLowerCase()}-widget`; 115 | const result = await inquirer.prompt([ 116 | { 117 | message: `Enter the folder name for your widget: (empty defaults to "${defaultDestinationPath}")`, 118 | name: "destinationPath", 119 | type: "input", 120 | }, 121 | ]); 122 | destinationPath = result.destinationPath 123 | ? result.destinationPath 124 | : defaultDestinationPath; 125 | } 126 | 127 | let directoryPath = path.join(process.cwd(), destinationPath); 128 | while ((await fs.pathExists(directoryPath)) === true) { 129 | throw new Error( 130 | `${destinationPath} already exists. Please choose a different destination folder name.` 131 | ); 132 | } 133 | 134 | let rawEditorType = input.options["editor-type"]; 135 | let editorType; 136 | if (rawEditorType === undefined) { 137 | const result = await inquirer.prompt([ 138 | { 139 | choices: ["figma", "figjam", "figma,figjam"], 140 | message: `Select the editor type(s) name for your widget:")`, 141 | name: "editorType", 142 | type: "list", 143 | }, 144 | ]); 145 | rawEditorType = result.editorType || "figjam"; 146 | editorType = rawEditorType 147 | .split(",") 148 | .map((e) => `\"${e}\"`) 149 | .join(","); 150 | console.log(editorType); 151 | } 152 | 153 | let shouldAddUI = input.options.iframe; 154 | if (shouldAddUI === undefined) { 155 | const result = await inquirer.prompt([ 156 | { 157 | choices: ["Y", "N"], 158 | message: "Are you building a widget with an iframe?", 159 | name: "shouldAddIframe", 160 | type: "list", 161 | }, 162 | ]); 163 | shouldAddUI = result.shouldAddIframe; 164 | } 165 | shouldAddUI = shouldAddUI === "Y"; 166 | 167 | console.log(``); 168 | console.log( 169 | `Creating widget for ${rawEditorType} ${ 170 | shouldAddUI ? "with ui" : "without ui" 171 | }...` 172 | ); 173 | console.log(`Copying template into "${destinationPath}"...`); 174 | 175 | await copyTemplateFiles(directoryPath, shouldAddUI); 176 | await replaceTemplatizedValues(directoryPath, { 177 | widgetName, 178 | widgetId: randomWidgetId(), 179 | widgetEditorType: editorType, 180 | packageName: widgetName.toLowerCase(), 181 | }); 182 | 183 | console.log("Installing dependencies..."); 184 | await installDependencies(directoryPath, widgetName, destinationPath); 185 | } catch (error) { 186 | console.log(error.message); 187 | process.exit(1); 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@figma/create-widget", 3 | "version": "1.0.3", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@nodelib/fs.scandir": { 8 | "version": "2.1.5", 9 | "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", 10 | "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", 11 | "requires": { 12 | "@nodelib/fs.stat": "2.0.5", 13 | "run-parallel": "^1.1.9" 14 | } 15 | }, 16 | "@nodelib/fs.stat": { 17 | "version": "2.0.5", 18 | "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", 19 | "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" 20 | }, 21 | "@nodelib/fs.walk": { 22 | "version": "1.2.8", 23 | "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", 24 | "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", 25 | "requires": { 26 | "@nodelib/fs.scandir": "2.1.5", 27 | "fastq": "^1.6.0" 28 | } 29 | }, 30 | "@sindresorhus/is": { 31 | "version": "4.2.0", 32 | "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.2.0.tgz", 33 | "integrity": "sha512-VkE3KLBmJwcCaVARtQpfuKcKv8gcBmUubrfHGF84dXuuW6jgsRYxPtzcIhPyK9WAPpRt2/xY6zkD9MnRaJzSyw==" 34 | }, 35 | "@szmarczak/http-timer": { 36 | "version": "4.0.6", 37 | "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", 38 | "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", 39 | "requires": { 40 | "defer-to-connect": "^2.0.0" 41 | } 42 | }, 43 | "@types/cacheable-request": { 44 | "version": "6.0.2", 45 | "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.2.tgz", 46 | "integrity": "sha512-B3xVo+dlKM6nnKTcmm5ZtY/OL8bOAOd2Olee9M1zft65ox50OzjEHW91sDiU9j6cvW8Ejg1/Qkf4xd2kugApUA==", 47 | "requires": { 48 | "@types/http-cache-semantics": "*", 49 | "@types/keyv": "*", 50 | "@types/node": "*", 51 | "@types/responselike": "*" 52 | } 53 | }, 54 | "@types/http-cache-semantics": { 55 | "version": "4.0.1", 56 | "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", 57 | "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" 58 | }, 59 | "@types/keyv": { 60 | "version": "3.1.3", 61 | "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.3.tgz", 62 | "integrity": "sha512-FXCJgyyN3ivVgRoml4h94G/p3kY+u/B86La+QptcqJaWtBWtmc6TtkNfS40n9bIvyLteHh7zXOtgbobORKPbDg==", 63 | "requires": { 64 | "@types/node": "*" 65 | } 66 | }, 67 | "@types/node": { 68 | "version": "16.7.13", 69 | "resolved": "https://registry.npmjs.org/@types/node/-/node-16.7.13.tgz", 70 | "integrity": "sha512-pLUPDn+YG3FYEt/pHI74HmnJOWzeR+tOIQzUx93pi9M7D8OE7PSLr97HboXwk5F+JS+TLtWuzCOW97AHjmOXXA==" 71 | }, 72 | "@types/responselike": { 73 | "version": "1.0.0", 74 | "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz", 75 | "integrity": "sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==", 76 | "requires": { 77 | "@types/node": "*" 78 | } 79 | }, 80 | "ansi-escapes": { 81 | "version": "4.3.2", 82 | "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", 83 | "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", 84 | "requires": { 85 | "type-fest": "^0.21.3" 86 | } 87 | }, 88 | "ansi-regex": { 89 | "version": "5.0.1", 90 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", 91 | "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" 92 | }, 93 | "ansi-styles": { 94 | "version": "4.3.0", 95 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", 96 | "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", 97 | "requires": { 98 | "color-convert": "^2.0.1" 99 | } 100 | }, 101 | "array-union": { 102 | "version": "3.0.1", 103 | "resolved": "https://registry.npmjs.org/array-union/-/array-union-3.0.1.tgz", 104 | "integrity": "sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==" 105 | }, 106 | "base64-js": { 107 | "version": "1.5.1", 108 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 109 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" 110 | }, 111 | "bl": { 112 | "version": "4.1.0", 113 | "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", 114 | "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", 115 | "requires": { 116 | "buffer": "^5.5.0", 117 | "inherits": "^2.0.4", 118 | "readable-stream": "^3.4.0" 119 | } 120 | }, 121 | "braces": { 122 | "version": "3.0.2", 123 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", 124 | "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", 125 | "requires": { 126 | "fill-range": "^7.0.1" 127 | } 128 | }, 129 | "buffer": { 130 | "version": "5.7.1", 131 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", 132 | "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", 133 | "requires": { 134 | "base64-js": "^1.3.1", 135 | "ieee754": "^1.1.13" 136 | } 137 | }, 138 | "cacheable-lookup": { 139 | "version": "5.0.4", 140 | "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", 141 | "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==" 142 | }, 143 | "cacheable-request": { 144 | "version": "7.0.2", 145 | "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz", 146 | "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==", 147 | "requires": { 148 | "clone-response": "^1.0.2", 149 | "get-stream": "^5.1.0", 150 | "http-cache-semantics": "^4.0.0", 151 | "keyv": "^4.0.0", 152 | "lowercase-keys": "^2.0.0", 153 | "normalize-url": "^6.0.1", 154 | "responselike": "^2.0.0" 155 | } 156 | }, 157 | "chalk": { 158 | "version": "4.1.2", 159 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", 160 | "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", 161 | "requires": { 162 | "ansi-styles": "^4.1.0", 163 | "supports-color": "^7.1.0" 164 | } 165 | }, 166 | "chardet": { 167 | "version": "0.7.0", 168 | "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", 169 | "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" 170 | }, 171 | "cli-cursor": { 172 | "version": "3.1.0", 173 | "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", 174 | "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", 175 | "requires": { 176 | "restore-cursor": "^3.1.0" 177 | } 178 | }, 179 | "cli-spinners": { 180 | "version": "2.6.1", 181 | "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", 182 | "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==" 183 | }, 184 | "cli-width": { 185 | "version": "3.0.0", 186 | "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", 187 | "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==" 188 | }, 189 | "clone": { 190 | "version": "1.0.4", 191 | "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", 192 | "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" 193 | }, 194 | "clone-response": { 195 | "version": "1.0.2", 196 | "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", 197 | "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", 198 | "requires": { 199 | "mimic-response": "^1.0.0" 200 | } 201 | }, 202 | "color-convert": { 203 | "version": "2.0.1", 204 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", 205 | "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", 206 | "requires": { 207 | "color-name": "~1.1.4" 208 | } 209 | }, 210 | "color-name": { 211 | "version": "1.1.4", 212 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", 213 | "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" 214 | }, 215 | "decompress-response": { 216 | "version": "6.0.0", 217 | "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", 218 | "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", 219 | "requires": { 220 | "mimic-response": "^3.1.0" 221 | }, 222 | "dependencies": { 223 | "mimic-response": { 224 | "version": "3.1.0", 225 | "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", 226 | "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" 227 | } 228 | } 229 | }, 230 | "deep-extend": { 231 | "version": "0.6.0", 232 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 233 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" 234 | }, 235 | "defaults": { 236 | "version": "1.0.3", 237 | "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", 238 | "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", 239 | "requires": { 240 | "clone": "^1.0.2" 241 | } 242 | }, 243 | "defer-to-connect": { 244 | "version": "2.0.1", 245 | "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", 246 | "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==" 247 | }, 248 | "dir-glob": { 249 | "version": "3.0.1", 250 | "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", 251 | "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", 252 | "requires": { 253 | "path-type": "^4.0.0" 254 | } 255 | }, 256 | "emoji-regex": { 257 | "version": "8.0.0", 258 | "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", 259 | "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" 260 | }, 261 | "end-of-stream": { 262 | "version": "1.4.4", 263 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 264 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 265 | "requires": { 266 | "once": "^1.4.0" 267 | } 268 | }, 269 | "escape-string-regexp": { 270 | "version": "1.0.5", 271 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 272 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" 273 | }, 274 | "external-editor": { 275 | "version": "3.1.0", 276 | "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", 277 | "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", 278 | "requires": { 279 | "chardet": "^0.7.0", 280 | "iconv-lite": "^0.4.24", 281 | "tmp": "^0.0.33" 282 | } 283 | }, 284 | "fast-glob": { 285 | "version": "3.2.7", 286 | "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", 287 | "integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==", 288 | "requires": { 289 | "@nodelib/fs.stat": "^2.0.2", 290 | "@nodelib/fs.walk": "^1.2.3", 291 | "glob-parent": "^5.1.2", 292 | "merge2": "^1.3.0", 293 | "micromatch": "^4.0.4" 294 | } 295 | }, 296 | "fastq": { 297 | "version": "1.13.0", 298 | "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", 299 | "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", 300 | "requires": { 301 | "reusify": "^1.0.4" 302 | } 303 | }, 304 | "figures": { 305 | "version": "3.2.0", 306 | "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", 307 | "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", 308 | "requires": { 309 | "escape-string-regexp": "^1.0.5" 310 | } 311 | }, 312 | "fill-range": { 313 | "version": "7.0.1", 314 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", 315 | "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", 316 | "requires": { 317 | "to-regex-range": "^5.0.1" 318 | } 319 | }, 320 | "fs-extra": { 321 | "version": "10.0.0", 322 | "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz", 323 | "integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==", 324 | "requires": { 325 | "graceful-fs": "^4.2.0", 326 | "jsonfile": "^6.0.1", 327 | "universalify": "^2.0.0" 328 | } 329 | }, 330 | "get-stream": { 331 | "version": "5.2.0", 332 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", 333 | "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", 334 | "requires": { 335 | "pump": "^3.0.0" 336 | } 337 | }, 338 | "glob-parent": { 339 | "version": "5.1.2", 340 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", 341 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", 342 | "requires": { 343 | "is-glob": "^4.0.1" 344 | } 345 | }, 346 | "globby": { 347 | "version": "12.0.2", 348 | "resolved": "https://registry.npmjs.org/globby/-/globby-12.0.2.tgz", 349 | "integrity": "sha512-lAsmb/5Lww4r7MM9nCCliDZVIKbZTavrsunAsHLr9oHthrZP1qi7/gAnHOsUs9bLvEt2vKVJhHmxuL7QbDuPdQ==", 350 | "requires": { 351 | "array-union": "^3.0.1", 352 | "dir-glob": "^3.0.1", 353 | "fast-glob": "^3.2.7", 354 | "ignore": "^5.1.8", 355 | "merge2": "^1.4.1", 356 | "slash": "^4.0.0" 357 | } 358 | }, 359 | "got": { 360 | "version": "11.8.3", 361 | "resolved": "https://registry.npmjs.org/got/-/got-11.8.3.tgz", 362 | "integrity": "sha512-7gtQ5KiPh1RtGS9/Jbv1ofDpBFuq42gyfEib+ejaRBJuj/3tQFeR5+gw57e4ipaU8c/rCjvX6fkQz2lyDlGAOg==", 363 | "requires": { 364 | "@sindresorhus/is": "^4.0.0", 365 | "@szmarczak/http-timer": "^4.0.5", 366 | "@types/cacheable-request": "^6.0.1", 367 | "@types/responselike": "^1.0.0", 368 | "cacheable-lookup": "^5.0.3", 369 | "cacheable-request": "^7.0.2", 370 | "decompress-response": "^6.0.0", 371 | "http2-wrapper": "^1.0.0-beta.5.2", 372 | "lowercase-keys": "^2.0.0", 373 | "p-cancelable": "^2.0.0", 374 | "responselike": "^2.0.0" 375 | } 376 | }, 377 | "graceful-fs": { 378 | "version": "4.2.8", 379 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", 380 | "integrity": "sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==" 381 | }, 382 | "has-flag": { 383 | "version": "4.0.0", 384 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", 385 | "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" 386 | }, 387 | "http-cache-semantics": { 388 | "version": "4.1.0", 389 | "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", 390 | "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==" 391 | }, 392 | "http2-wrapper": { 393 | "version": "1.0.3", 394 | "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", 395 | "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", 396 | "requires": { 397 | "quick-lru": "^5.1.1", 398 | "resolve-alpn": "^1.0.0" 399 | } 400 | }, 401 | "iconv-lite": { 402 | "version": "0.4.24", 403 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 404 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 405 | "requires": { 406 | "safer-buffer": ">= 2.1.2 < 3" 407 | } 408 | }, 409 | "ieee754": { 410 | "version": "1.2.1", 411 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 412 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" 413 | }, 414 | "ignore": { 415 | "version": "5.1.9", 416 | "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz", 417 | "integrity": "sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==" 418 | }, 419 | "inherits": { 420 | "version": "2.0.4", 421 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 422 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 423 | }, 424 | "ini": { 425 | "version": "1.3.8", 426 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", 427 | "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" 428 | }, 429 | "inquirer": { 430 | "version": "8.2.0", 431 | "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.0.tgz", 432 | "integrity": "sha512-0crLweprevJ02tTuA6ThpoAERAGyVILC4sS74uib58Xf/zSr1/ZWtmm7D5CI+bSQEaA04f0K7idaHpQbSWgiVQ==", 433 | "requires": { 434 | "ansi-escapes": "^4.2.1", 435 | "chalk": "^4.1.1", 436 | "cli-cursor": "^3.1.0", 437 | "cli-width": "^3.0.0", 438 | "external-editor": "^3.0.3", 439 | "figures": "^3.0.0", 440 | "lodash": "^4.17.21", 441 | "mute-stream": "0.0.8", 442 | "ora": "^5.4.1", 443 | "run-async": "^2.4.0", 444 | "rxjs": "^7.2.0", 445 | "string-width": "^4.1.0", 446 | "strip-ansi": "^6.0.0", 447 | "through": "^2.3.6" 448 | } 449 | }, 450 | "is-extglob": { 451 | "version": "2.1.1", 452 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", 453 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" 454 | }, 455 | "is-fullwidth-code-point": { 456 | "version": "3.0.0", 457 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", 458 | "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" 459 | }, 460 | "is-glob": { 461 | "version": "4.0.3", 462 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", 463 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", 464 | "requires": { 465 | "is-extglob": "^2.1.1" 466 | } 467 | }, 468 | "is-interactive": { 469 | "version": "1.0.0", 470 | "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", 471 | "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==" 472 | }, 473 | "is-number": { 474 | "version": "7.0.0", 475 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", 476 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" 477 | }, 478 | "is-unicode-supported": { 479 | "version": "0.1.0", 480 | "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", 481 | "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" 482 | }, 483 | "is-utf8": { 484 | "version": "0.2.1", 485 | "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", 486 | "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" 487 | }, 488 | "json-buffer": { 489 | "version": "3.0.1", 490 | "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", 491 | "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" 492 | }, 493 | "jsonfile": { 494 | "version": "6.1.0", 495 | "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", 496 | "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", 497 | "requires": { 498 | "graceful-fs": "^4.1.6", 499 | "universalify": "^2.0.0" 500 | } 501 | }, 502 | "keyv": { 503 | "version": "4.0.4", 504 | "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.0.4.tgz", 505 | "integrity": "sha512-vqNHbAc8BBsxk+7QBYLW0Y219rWcClspR6WSeoHYKG5mnsSoOH+BL1pWq02DDCVdvvuUny5rkBlzMRzoqc+GIg==", 506 | "requires": { 507 | "json-buffer": "3.0.1" 508 | } 509 | }, 510 | "lodash": { 511 | "version": "4.17.21", 512 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 513 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" 514 | }, 515 | "log-symbols": { 516 | "version": "4.1.0", 517 | "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", 518 | "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", 519 | "requires": { 520 | "chalk": "^4.1.0", 521 | "is-unicode-supported": "^0.1.0" 522 | } 523 | }, 524 | "lowercase-keys": { 525 | "version": "2.0.0", 526 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", 527 | "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" 528 | }, 529 | "lru-cache": { 530 | "version": "6.0.0", 531 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 532 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 533 | "requires": { 534 | "yallist": "^4.0.0" 535 | } 536 | }, 537 | "merge2": { 538 | "version": "1.4.1", 539 | "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", 540 | "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" 541 | }, 542 | "micromatch": { 543 | "version": "4.0.4", 544 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", 545 | "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", 546 | "requires": { 547 | "braces": "^3.0.1", 548 | "picomatch": "^2.2.3" 549 | } 550 | }, 551 | "mimic-fn": { 552 | "version": "2.1.0", 553 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", 554 | "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" 555 | }, 556 | "mimic-response": { 557 | "version": "1.0.1", 558 | "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", 559 | "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" 560 | }, 561 | "minimist": { 562 | "version": "1.2.5", 563 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", 564 | "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" 565 | }, 566 | "mri": { 567 | "version": "1.2.0", 568 | "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", 569 | "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==" 570 | }, 571 | "mustache": { 572 | "version": "4.2.0", 573 | "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", 574 | "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==" 575 | }, 576 | "mute-stream": { 577 | "version": "0.0.8", 578 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", 579 | "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" 580 | }, 581 | "normalize-url": { 582 | "version": "6.1.0", 583 | "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", 584 | "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==" 585 | }, 586 | "once": { 587 | "version": "1.4.0", 588 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 589 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 590 | "requires": { 591 | "wrappy": "1" 592 | } 593 | }, 594 | "onetime": { 595 | "version": "5.1.2", 596 | "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", 597 | "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", 598 | "requires": { 599 | "mimic-fn": "^2.1.0" 600 | } 601 | }, 602 | "ora": { 603 | "version": "5.4.1", 604 | "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", 605 | "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", 606 | "requires": { 607 | "bl": "^4.1.0", 608 | "chalk": "^4.1.0", 609 | "cli-cursor": "^3.1.0", 610 | "cli-spinners": "^2.5.0", 611 | "is-interactive": "^1.0.0", 612 | "is-unicode-supported": "^0.1.0", 613 | "log-symbols": "^4.1.0", 614 | "strip-ansi": "^6.0.0", 615 | "wcwidth": "^1.0.1" 616 | } 617 | }, 618 | "os-tmpdir": { 619 | "version": "1.0.2", 620 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 621 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" 622 | }, 623 | "p-cancelable": { 624 | "version": "2.1.1", 625 | "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", 626 | "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==" 627 | }, 628 | "package-json": { 629 | "version": "7.0.0", 630 | "resolved": "https://registry.npmjs.org/package-json/-/package-json-7.0.0.tgz", 631 | "integrity": "sha512-CHJqc94AA8YfSLHGQT3DbvSIuE12NLFekpM4n7LRrAd3dOJtA911+4xe9q6nC3/jcKraq7nNS9VxgtT0KC+diA==", 632 | "requires": { 633 | "got": "^11.8.2", 634 | "registry-auth-token": "^4.0.0", 635 | "registry-url": "^5.0.0", 636 | "semver": "^7.3.5" 637 | }, 638 | "dependencies": { 639 | "semver": { 640 | "version": "7.3.5", 641 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", 642 | "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", 643 | "requires": { 644 | "lru-cache": "^6.0.0" 645 | } 646 | } 647 | } 648 | }, 649 | "path-type": { 650 | "version": "4.0.0", 651 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", 652 | "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" 653 | }, 654 | "picomatch": { 655 | "version": "2.3.0", 656 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", 657 | "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" 658 | }, 659 | "prettier": { 660 | "version": "2.5.1", 661 | "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz", 662 | "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", 663 | "dev": true 664 | }, 665 | "pump": { 666 | "version": "3.0.0", 667 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 668 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 669 | "requires": { 670 | "end-of-stream": "^1.1.0", 671 | "once": "^1.3.1" 672 | } 673 | }, 674 | "punycode": { 675 | "version": "1.3.2", 676 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", 677 | "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" 678 | }, 679 | "querystring": { 680 | "version": "0.2.0", 681 | "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", 682 | "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" 683 | }, 684 | "queue-microtask": { 685 | "version": "1.2.3", 686 | "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", 687 | "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" 688 | }, 689 | "quick-lru": { 690 | "version": "5.1.1", 691 | "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", 692 | "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==" 693 | }, 694 | "rc": { 695 | "version": "1.2.8", 696 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", 697 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", 698 | "requires": { 699 | "deep-extend": "^0.6.0", 700 | "ini": "~1.3.0", 701 | "minimist": "^1.2.0", 702 | "strip-json-comments": "~2.0.1" 703 | } 704 | }, 705 | "readable-stream": { 706 | "version": "3.6.0", 707 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", 708 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", 709 | "requires": { 710 | "inherits": "^2.0.3", 711 | "string_decoder": "^1.1.1", 712 | "util-deprecate": "^1.0.1" 713 | } 714 | }, 715 | "registry-auth-token": { 716 | "version": "4.2.1", 717 | "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.1.tgz", 718 | "integrity": "sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==", 719 | "requires": { 720 | "rc": "^1.2.8" 721 | } 722 | }, 723 | "registry-url": { 724 | "version": "5.1.0", 725 | "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", 726 | "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", 727 | "requires": { 728 | "rc": "^1.2.8" 729 | } 730 | }, 731 | "resolve-alpn": { 732 | "version": "1.2.1", 733 | "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", 734 | "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" 735 | }, 736 | "responselike": { 737 | "version": "2.0.0", 738 | "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.0.tgz", 739 | "integrity": "sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==", 740 | "requires": { 741 | "lowercase-keys": "^2.0.0" 742 | } 743 | }, 744 | "restore-cursor": { 745 | "version": "3.1.0", 746 | "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", 747 | "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", 748 | "requires": { 749 | "onetime": "^5.1.0", 750 | "signal-exit": "^3.0.2" 751 | } 752 | }, 753 | "reusify": { 754 | "version": "1.0.4", 755 | "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", 756 | "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" 757 | }, 758 | "run-async": { 759 | "version": "2.4.1", 760 | "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", 761 | "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==" 762 | }, 763 | "run-parallel": { 764 | "version": "1.2.0", 765 | "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", 766 | "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", 767 | "requires": { 768 | "queue-microtask": "^1.2.2" 769 | } 770 | }, 771 | "rxjs": { 772 | "version": "7.4.0", 773 | "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.4.0.tgz", 774 | "integrity": "sha512-7SQDi7xeTMCJpqViXh8gL/lebcwlp3d831F05+9B44A4B0WfsEwUQHR64gsH1kvJ+Ep/J9K2+n1hVl1CsGN23w==", 775 | "requires": { 776 | "tslib": "~2.1.0" 777 | } 778 | }, 779 | "sade": { 780 | "version": "1.7.4", 781 | "resolved": "https://registry.npmjs.org/sade/-/sade-1.7.4.tgz", 782 | "integrity": "sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA==", 783 | "requires": { 784 | "mri": "^1.1.0" 785 | } 786 | }, 787 | "safe-buffer": { 788 | "version": "5.2.1", 789 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 790 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 791 | }, 792 | "safer-buffer": { 793 | "version": "2.1.2", 794 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 795 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 796 | }, 797 | "signal-exit": { 798 | "version": "3.0.6", 799 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", 800 | "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==" 801 | }, 802 | "slash": { 803 | "version": "4.0.0", 804 | "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", 805 | "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==" 806 | }, 807 | "string-width": { 808 | "version": "4.2.3", 809 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", 810 | "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", 811 | "requires": { 812 | "emoji-regex": "^8.0.0", 813 | "is-fullwidth-code-point": "^3.0.0", 814 | "strip-ansi": "^6.0.1" 815 | } 816 | }, 817 | "string_decoder": { 818 | "version": "1.3.0", 819 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 820 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 821 | "requires": { 822 | "safe-buffer": "~5.2.0" 823 | } 824 | }, 825 | "strip-ansi": { 826 | "version": "6.0.1", 827 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", 828 | "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", 829 | "requires": { 830 | "ansi-regex": "^5.0.1" 831 | } 832 | }, 833 | "strip-json-comments": { 834 | "version": "2.0.1", 835 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 836 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" 837 | }, 838 | "supports-color": { 839 | "version": "7.2.0", 840 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", 841 | "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", 842 | "requires": { 843 | "has-flag": "^4.0.0" 844 | } 845 | }, 846 | "through": { 847 | "version": "2.3.8", 848 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 849 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" 850 | }, 851 | "tmp": { 852 | "version": "0.0.33", 853 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", 854 | "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", 855 | "requires": { 856 | "os-tmpdir": "~1.0.2" 857 | } 858 | }, 859 | "to-regex-range": { 860 | "version": "5.0.1", 861 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", 862 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", 863 | "requires": { 864 | "is-number": "^7.0.0" 865 | } 866 | }, 867 | "tslib": { 868 | "version": "2.1.0", 869 | "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", 870 | "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" 871 | }, 872 | "type-fest": { 873 | "version": "0.21.3", 874 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", 875 | "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" 876 | }, 877 | "universalify": { 878 | "version": "2.0.0", 879 | "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", 880 | "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==" 881 | }, 882 | "url": { 883 | "version": "0.11.0", 884 | "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", 885 | "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", 886 | "requires": { 887 | "punycode": "1.3.2", 888 | "querystring": "0.2.0" 889 | } 890 | }, 891 | "util-deprecate": { 892 | "version": "1.0.2", 893 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 894 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 895 | }, 896 | "wcwidth": { 897 | "version": "1.0.1", 898 | "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", 899 | "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", 900 | "requires": { 901 | "defaults": "^1.0.3" 902 | } 903 | }, 904 | "wrappy": { 905 | "version": "1.0.2", 906 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 907 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" 908 | }, 909 | "yallist": { 910 | "version": "4.0.0", 911 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 912 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" 913 | } 914 | } 915 | } 916 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@figma/create-widget", 3 | "repository": "git@github.com:figma/create-widget.git", 4 | "version": "1.0.7", 5 | "description": "Create a widget from figma widget templates", 6 | "type": "module", 7 | "bin": { 8 | "create-widget": "./cli.js" 9 | }, 10 | "scripts": { 11 | "format": "prettier --write .", 12 | "format:check": "prettier --check .", 13 | "test": "rm -rf test-artifacts/ && mkdir -p test-artifacts && cd test-artifacts && node ../cli.js" 14 | }, 15 | "author": "Figma", 16 | "license": "MIT License", 17 | "dependencies": { 18 | "fs-extra": "^10.0.0", 19 | "package-json": "^7.0.0", 20 | "url": "^0.11.0", 21 | "inquirer": "^8.2.0", 22 | "sade": "^1.7.4", 23 | "globby": "^12.0.2", 24 | "is-utf8": "^0.2.1", 25 | "mustache": "^4.2.0" 26 | }, 27 | "devDependencies": { 28 | "prettier": "^2.5.1" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /templates/widget-with-ui/README.md: -------------------------------------------------------------------------------- 1 | # @figma/create-widget 2 | 3 | This repo was created by @figma/create-widget 4 | 5 | ## Getting started 6 | 7 | Run the following command to start building your widget 8 | 9 | ```bash 10 | npm run dev 11 | ``` 12 | 13 | 1. Log in to your account and open the Figma desktop app 14 | 2. You can open any existing FigJam document or create a new one. 15 | 3. Go to Menu > Widgets > Development > "Import widget from manifest..." 16 | 4. Select the manifest.json in this folder 17 | 18 | ## Organization 19 | 20 | This widget uses: 21 | 22 | - [esbuild](https://esbuild.github.io/) for bundling 23 | - [vite](https://vitejs.dev/) and [react](https://reactjs.org/) for the iframe 24 | - [typescript](https://www.typescriptlang.org/) for typechecking 25 | 26 | | file/folder | description | 27 | | ------------- | -------------------------------------------------------------------------------- | 28 | | manifest.json | The widget's [manifest.json](https://www.figma.com/widget-docs/widget-manifest/) | 29 | | widget-src/ | Contains the widget code | 30 | | ui-src/ | Contains the iframe code | 31 | 32 | ### `npm run dev` 33 | 34 | This is the only command you need to run in development. It will start the following processes for you: 35 | 36 | - bundling (both widget and iframe code) 37 | - typechecking (both widget and iframe code) 38 | - vite dev server (for iframe development) 39 | 40 | ### `npm run build` 41 | 42 | This runs bundling with minification turned on. You should run this command before releasing your widget. 43 | 44 | ### `npm run test` 45 | 46 | This runs typechecking and makes sure that your widget builds without errors. 47 | -------------------------------------------------------------------------------- /templates/widget-with-ui/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "{{widgetName}}", 3 | "id": "{{widgetId}}", 4 | "api": "1.0.0", 5 | "editorType": [{{{widgetEditorType}}}], 6 | "permissions": [], 7 | "containsWidget": true, 8 | "main": "dist/code.js", 9 | "ui": "dist/index.html", 10 | "widgetApi": "1.0.0" 11 | } 12 | -------------------------------------------------------------------------------- /templates/widget-with-ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "{{packageName}}", 3 | "version": "1.0.0", 4 | "description": "{{widgetName}}", 5 | "scripts": { 6 | "test": "npm run tsc && npm run build", 7 | "format": "prettier --write .", 8 | "tsc": "npm run tsc:main && npm run tsc:ui", 9 | "tsc:main": "tsc --noEmit -p widget-src", 10 | "tsc:ui": "tsc --noEmit -p ui-src", 11 | "tsc:watch": "concurrently -n widget,iframe \"npm run tsc:main -- --watch --preserveWatchOutput\" \"npm run tsc:ui -- --watch --preserveWatchOutput\"", 12 | "build": "npm run build:ui && npm run build:main -- --minify", 13 | "build:main": "esbuild widget-src/code.tsx --bundle --outfile=dist/code.js", 14 | "build:ui": "npx vite build --minify esbuild --emptyOutDir=false", 15 | "build:watch": "concurrently -n widget,iframe \"npm run build:main -- --watch\" \"npm run build:ui -- --watch\"", 16 | "dev": "concurrently -n tsc,build,vite 'npm:tsc:watch' 'npm:build:watch' 'vite'" 17 | }, 18 | "author": "Figma", 19 | "license": "MIT License", 20 | "dependencies": { 21 | "react": "^17.0.0", 22 | "react-dom": "^17.0.0" 23 | }, 24 | "devDependencies": { 25 | "@figma/plugin-typings": "*", 26 | "@figma/widget-typings": "*", 27 | "@types/react": "^17.0.0", 28 | "@types/react-dom": "^17.0.0", 29 | "@vitejs/plugin-react-refresh": "^1.3.1", 30 | "concurrently": "^6.3.0", 31 | "esbuild": "^0.13.5", 32 | "prettier": "^2.3.2", 33 | "typescript": "^4.4.2", 34 | "vite": "^2.5.2", 35 | "vite-plugin-singlefile": "^0.5.1" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /templates/widget-with-ui/ui-src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | padding: 20px; 3 | } 4 | -------------------------------------------------------------------------------- /templates/widget-with-ui/ui-src/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | import "./App.css"; 3 | 4 | function App() { 5 | useEffect(() => { 6 | if (typeof parent !== undefined) { 7 | parent?.postMessage?.({ pluginMessage: "hello" }, "*"); 8 | } 9 | }, []); 10 | 11 | return ( 12 |
13 |

Hello

14 | 21 |
22 | ); 23 | } 24 | 25 | export default App; 26 | -------------------------------------------------------------------------------- /templates/widget-with-ui/ui-src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", 4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /templates/widget-with-ui/ui-src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Widget Template 7 | 8 | 9 |
10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /templates/widget-with-ui/ui-src/main.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import "./index.css"; 4 | import App from "./App"; 5 | 6 | ReactDOM.render(, document.getElementById("root")); 7 | -------------------------------------------------------------------------------- /templates/widget-with-ui/ui-src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "useDefineForClassFields": true, 5 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 6 | "allowJs": false, 7 | "skipLibCheck": false, 8 | "esModuleInterop": false, 9 | "allowSyntheticDefaultImports": true, 10 | "strict": true, 11 | "forceConsistentCasingInFileNames": true, 12 | "module": "ESNext", 13 | "moduleResolution": "Node", 14 | "resolveJsonModule": true, 15 | "isolatedModules": true, 16 | "noEmit": true, 17 | "jsx": "react" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /templates/widget-with-ui/ui-src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /templates/widget-with-ui/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import reactRefresh from "@vitejs/plugin-react-refresh"; 3 | import { viteSingleFile } from "vite-plugin-singlefile"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | root: "./ui-src", 8 | plugins: [reactRefresh(), viteSingleFile()], 9 | build: { 10 | target: "esnext", 11 | assetsInlineLimit: 100000000, 12 | chunkSizeWarningLimit: 100000000, 13 | cssCodeSplit: false, 14 | brotliSize: false, 15 | outDir: "../dist", 16 | rollupOptions: { 17 | inlineDynamicImports: true, 18 | output: { 19 | manualChunks: () => "everything.js", 20 | }, 21 | }, 22 | }, 23 | }); 24 | -------------------------------------------------------------------------------- /templates/widget-with-ui/widget-src/code.tsx: -------------------------------------------------------------------------------- 1 | const { widget } = figma; 2 | const { AutoLayout, Ellipse, Frame, Image, Rectangle, SVG, Text } = widget; 3 | 4 | function Widget() { 5 | return ( 6 | { 16 | await new Promise((resolve) => { 17 | figma.showUI(__html__); 18 | figma.ui.on("message", (msg) => { 19 | if (msg === "hello") { 20 | figma.notify("Hello Widgets"); 21 | } 22 | if (msg === "close") { 23 | figma.closePlugin(); 24 | } 25 | }); 26 | }); 27 | }} 28 | > 29 | 30 | Click Me 31 | 32 | 33 | ); 34 | } 35 | widget.register(Widget); 36 | -------------------------------------------------------------------------------- /templates/widget-with-ui/widget-src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "jsx": "react", 4 | "jsxFactory": "figma.widget.h", 5 | "jsxFragmentFactory": "figma.widget.Fragment", 6 | "target": "es6", 7 | "lib": ["es6"], 8 | "strict": true, 9 | "typeRoots": ["../node_modules/@figma"] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /templates/widget-without-ui/README.md: -------------------------------------------------------------------------------- 1 | # @figma/create-widget 2 | 3 | This repo was created by @figma/create-widget 4 | 5 | ## Getting started with widget development 6 | 7 | Run the following command to start building your widget 8 | 9 | ```bash 10 | npm run dev 11 | ``` 12 | 13 | 1. Log in to your account and open the Figma desktop app 14 | 2. You can open any existing FigJam document or create a new one. 15 | 3. Go to Menu > Widgets > Development > "Import widget from manifest..." 16 | 4. Select the manifest.json in this folder 17 | 18 | ## Organization 19 | 20 | This widget uses: 21 | 22 | - [esbuild](https://esbuild.github.io/) for bundling 23 | - [typescript](https://www.typescriptlang.org/) for typechecking 24 | 25 | | file/folder | description | 26 | | ------------- | -------------------------------------------------------------------------------- | 27 | | manifest.json | The widget's [manifest.json](https://www.figma.com/widget-docs/widget-manifest/) | 28 | | widget-src/ | Contains the widget code | 29 | 30 | ### `npm run dev` 31 | 32 | This is the only command you need to run in development. It will start the following processes for you: 33 | 34 | - bundling 35 | - typechecking 36 | 37 | ### `npm run build` 38 | 39 | This runs bundling with minification turned on. You should run this command before releasing your widget. 40 | 41 | ### `npm run test` 42 | 43 | This runs typechecking and makes sure that your widget builds without errors. 44 | -------------------------------------------------------------------------------- /templates/widget-without-ui/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "{{widgetName}}", 3 | "id": "{{widgetId}}", 4 | "api": "1.0.0", 5 | "editorType": [{{{widgetEditorType}}}], 6 | "permissions": [], 7 | "containsWidget": true, 8 | "main": "dist/code.js", 9 | "widgetApi": "1.0.0" 10 | } 11 | -------------------------------------------------------------------------------- /templates/widget-without-ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "{{packageName}}", 3 | "version": "1.0.0", 4 | "description": "{{widgetName}}", 5 | "scripts": { 6 | "test": "npm run tsc && npm run build", 7 | "format": "prettier --write .", 8 | "tsc": "tsc --noEmit -p widget-src", 9 | "build": "npm run bundle -- --minify", 10 | "bundle": "esbuild widget-src/code.tsx --bundle --outfile=dist/code.js", 11 | "dev": "concurrently -n tsc,build 'npm run tsc -- --preserveWatchOutput --watch' 'npm run bundle -- --watch'" 12 | }, 13 | "author": "Figma", 14 | "license": "MIT License", 15 | "dependencies": {}, 16 | "devDependencies": { 17 | "@figma/plugin-typings": "*", 18 | "@figma/widget-typings": "*", 19 | "concurrently": "^6.3.0", 20 | "esbuild": "^0.13.5", 21 | "prettier": "^2.3.2", 22 | "typescript": "^4.4.2" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /templates/widget-without-ui/widget-src/code.tsx: -------------------------------------------------------------------------------- 1 | const { widget } = figma; 2 | const { AutoLayout, Ellipse, Frame, Image, Rectangle, SVG, Text } = widget; 3 | 4 | function Widget() { 5 | return ( 6 | 16 | 17 | Hello Widgets 18 | 19 | 20 | ); 21 | } 22 | widget.register(Widget); 23 | -------------------------------------------------------------------------------- /templates/widget-without-ui/widget-src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "jsx": "react", 4 | "jsxFactory": "figma.widget.h", 5 | "jsxFragmentFactory": "figma.widget.Fragment", 6 | "target": "es6", 7 | "lib": ["es6"], 8 | "strict": true, 9 | "typeRoots": ["../node_modules/@figma"] 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test-usage.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -xueo pipefail 4 | 5 | rm -rf test-artifacts 6 | mkdir -p test-artifacts 7 | pushd test-artifacts 8 | 9 | # Without iframe 10 | node ../cli -n CounterNoUI -p counter-no-ui-widget --iframe=N --editortype --editor-type figma,figjam 11 | pushd counter-no-ui-widget 12 | 13 | if [ -d "ui-src/" ]; then 14 | echo "ERROR: Should not have ui-src folder in no-ui test case" 15 | exit 1 16 | fi 17 | 18 | npm run test 19 | popd 20 | 21 | # With iframe 22 | node ../cli -n CounterWithUI -p counter-with-ui-widget --iframe=Y --editor-type figjam 23 | pushd counter-with-ui-widget 24 | npm run test 25 | popd 26 | 27 | popd 28 | --------------------------------------------------------------------------------