├── .prettierignore
├── templates
├── widget-with-ui
│ ├── ui-src
│ │ ├── App.css
│ │ ├── vite-env.d.ts
│ │ ├── main.tsx
│ │ ├── index.html
│ │ ├── index.css
│ │ ├── tsconfig.json
│ │ └── App.tsx
│ ├── manifest.json
│ ├── widget-src
│ │ ├── tsconfig.json
│ │ └── code.tsx
│ ├── vite.config.ts
│ ├── package.json
│ └── README.md
└── widget-without-ui
│ ├── manifest.json
│ ├── widget-src
│ ├── tsconfig.json
│ └── code.tsx
│ ├── package.json
│ └── README.md
├── .gitignore
├── .github
└── workflows
│ └── main.yml
├── test-usage.sh
├── package.json
├── cli.js
├── README.md
└── create-widget.js
/.prettierignore:
--------------------------------------------------------------------------------
1 | *.json
2 |
--------------------------------------------------------------------------------
/templates/widget-with-ui/ui-src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | padding: 20px;
3 | }
4 |
--------------------------------------------------------------------------------
/templates/widget-with-ui/ui-src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/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-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-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/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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/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/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/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 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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-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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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-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-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/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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # @figma/create-widget
2 |
3 | [](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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------