├── .gitignore ├── .prettierrc ├── tsconfig.json ├── .github └── workflows │ └── test.yml ├── package.json ├── LICENSE ├── README.md ├── index.d.ts ├── test-usage.sh ├── plugin-api.d.ts └── plugin-api-standalone.d.ts /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | test-artifacts 4 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "tabWidth": 2, 4 | "semi": false, 5 | "singleQuote": true, 6 | "printWidth": 100, 7 | "arrowParens": "always" 8 | } 9 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | // Figma plugins run in an environment with es6 but no browser symbols. 5 | "lib": ["es6"], 6 | "noEmit": true, 7 | "strict": true, 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: [push] 3 | jobs: 4 | test-typings-compile: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - name: Check out repository code 8 | uses: actions/checkout@v2 9 | - run: npm install typescript 10 | - run: npm test 11 | - run: npm run prettier:check 12 | 13 | test-usage-script: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Check out repository code 17 | uses: actions/checkout@v2 18 | - run: ./test-usage.sh 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@figma/plugin-typings", 3 | "version": "1.110.0", 4 | "description": "Typings for the Figma Plugin API", 5 | "main": "", 6 | "scripts": { 7 | "prettier": "npm run prettier-path -- '**/*.{ts,js}'", 8 | "prettier:check": "npm run prettier-path:check -- '**/*.{ts,js}'", 9 | "prettier-path": "prettier --write", 10 | "prettier-path:check": "prettier --check", 11 | "test": "tsc" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/figma/plugin-typings.git" 16 | }, 17 | "keywords": [ 18 | "figma", 19 | "plugin", 20 | "typings" 21 | ], 22 | "author": "Figma", 23 | "license": "MIT License", 24 | "bugs": { 25 | "url": "https://github.com/figma/plugin-typings/issues" 26 | }, 27 | "homepage": "https://github.com/figma/plugin-typings#readme", 28 | "devDependencies": { 29 | "prettier": "^2.6.1" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Figma, Inc. 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 Plugin API typings 2 | [![npm](https://img.shields.io/npm/v/@figma/plugin-typings?logo=npm&cacheSeconds=1800)](https://www.npmjs.com/package/@figma/plugin-typings) 3 | 4 | This repository contains the typings for the Figma Plugin API. 5 | 6 | ## Usage 7 | 8 | 1. Installation 9 | ```sh 10 | npm i --save-dev @figma/plugin-typings 11 | # or 12 | yarn add -D @figma/plugin-typings 13 | ``` 14 | 15 | 2. Configure _tsconfig.json_ 16 | ```js 17 | { 18 | "compilerOptions": { 19 | "typeRoots": [ 20 | "./node_modules/@types", 21 | "./node_modules/@figma" 22 | ] 23 | } 24 | } 25 | ``` 26 | The configuration above is needed for the TypeScript compiler to use type definitions found in both `./node_modules/@types` and `./node_modules/@figma`. Normally, most external type definitions are from DefinitelyTyped and are installed in `/@types`, which included by TypeScript by default. Since we host the plugin typings separately, they are installed outside in `/@figma` instead. 27 | 28 | Types should become globally available without needing to use import statements. We do it this way because the plugin API is part of the host environment, as opposed to being a package that a plugin includes. 29 | 30 | 31 | ## About 32 | 33 | Plugin API releases have the format "Version X, Update Y". Equivalent tags are created in this repository as `v.`. Note that not all API releases include API changes, some are just bug fixes. Therefore, some typings versions are skipped. 34 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | declare global { 4 | // Global variable with Figma's plugin API. 5 | const figma: PluginAPI 6 | const __html__: string 7 | const __uiFiles__: { 8 | [key: string]: string 9 | } 10 | const console: Console 11 | 12 | // The plugin environment exposes the browser console API, 13 | // so expected calls like console.log() still work. 14 | interface Console { 15 | log(message?: any, ...optionalParams: any[]): void 16 | error(message?: any, ...optionalParams: any[]): void 17 | assert(condition?: boolean, message?: string, ...data: any[]): void 18 | info(message?: any, ...optionalParams: any[]): void 19 | warn(message?: any, ...optionalParams: any[]): void 20 | clear(): void 21 | } 22 | function setTimeout(callback: Function, timeout: number): number 23 | function clearTimeout(handle: number): void 24 | function setInterval(callback: Function, timeout: number): number 25 | function clearInterval(handle: number): void 26 | 27 | const fetch: (url: string, init?: FetchOptions) => Promise 28 | 29 | interface FetchOptions { 30 | method?: string 31 | headers?: { [name: string]: string } 32 | /** 33 | * @deprecated use headers instead 34 | */ 35 | headersObject?: { [name: string]: string } 36 | body?: Uint8Array | string 37 | credentials?: string 38 | cache?: string 39 | redirect?: string 40 | referrer?: string 41 | integrity?: string 42 | } 43 | 44 | interface FetchResponse { 45 | headersObject: { [name: string]: string } 46 | ok: boolean 47 | redirected: boolean 48 | status: number 49 | statusText: string 50 | type: string 51 | url: string 52 | arrayBuffer(): Promise 53 | text(): Promise 54 | json(): Promise 55 | } 56 | } // declare global 57 | 58 | export {} 59 | -------------------------------------------------------------------------------- /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 | echo "Running test 1 (include types in typeRoots so all types are available ambiently)" 10 | mkdir test-1 11 | pushd test-1 12 | 13 | cat > package.json << EOF 14 | {} 15 | EOF 16 | 17 | cat > tsconfig.json << EOF 18 | { 19 | "compilerOptions": { 20 | "target": "es6", 21 | "lib": ["es6"], 22 | "strict": true, 23 | "typeRoots": [ 24 | "./node_modules/@types", 25 | "./node_modules/@figma" 26 | ] 27 | } 28 | } 29 | EOF 30 | 31 | cat > code.ts << EOF 32 | /** 33 | * Test file to make sure that plugin-typings work as expected. 34 | */ 35 | function main() { 36 | // figma globals is there 37 | if (figma.command && figma.editorType) { 38 | // console.log works 39 | console.log(figma.root, figma.currentPage) 40 | 41 | // setTimeout works 42 | setTimeout(() => { 43 | figma.currentPage.selection = []; 44 | }, 100) 45 | 46 | // setInterval works too 47 | clearTimeout(setInterval(() => { 48 | figma.ui.onmessage = msg => {} 49 | }, 100)) 50 | } 51 | } 52 | 53 | function testErrorFn(): void { 54 | // @ts-expect-error 55 | if (figma.NON_EXISTENT_ATTR) { 56 | } 57 | } 58 | 59 | // Node types are available as globals 60 | function testFn1(node: SceneNode): node is FrameNode { 61 | return node.type === 'FRAME' 62 | } 63 | 64 | // Paint types are available as globals too 65 | function testFn(paint: SolidPaint | GradientPaint | ImagePaint | null): boolean { 66 | return !!paint 67 | } 68 | 69 | function testNotify() { 70 | figma.notify("normal") 71 | figma.notify("error", {error: true}) 72 | figma.notify("timeout", {timeout: 10000}) 73 | figma.notify("Infinity", {timeout: Infinity}) 74 | 75 | figma.notify("button", {button: { 76 | text: "button", 77 | action: () => { 78 | return false 79 | } 80 | }}) 81 | 82 | figma.notify("button", { 83 | button: { 84 | text: "button", 85 | action: () => {}, 86 | } 87 | }) 88 | 89 | figma.notify("onDequeue", { 90 | onDequeue: (reason: NotifyDequeueReason) => { 91 | switch (reason) { 92 | case 'timeout': 93 | break; 94 | case 'dismiss': 95 | break; 96 | case 'action_button_click': 97 | break; 98 | default: 99 | function assertNever(x: never): never { 100 | throw new Error("Unexpected object: " + x); 101 | } 102 | assertNever(reason); 103 | break; 104 | } 105 | } 106 | }) 107 | } 108 | 109 | function testCodegen() { 110 | figma.codegen.on("generate", async () => { 111 | return [ 112 | { 113 | language: "TYPESCRIPT", 114 | code: JSON.stringify(figma.codegen.preferences.unit), 115 | title: "Code snippet 1" 116 | }, 117 | { 118 | language: "JAVASCRIPT", 119 | code: JSON.stringify(figma.codegen.preferences.scaleFactor), 120 | title: "Code snippet 2" 121 | }, 122 | { 123 | language: "JAVASCRIPT", 124 | code: JSON.stringify(figma.codegen.preferences.customSettings), 125 | title: "Code snippet 3" 126 | } 127 | ] 128 | }) 129 | } 130 | 131 | function testFindAllWithCriteria() { 132 | const nodes = figma.root.findAllWithCriteria({ types: ["TEXT"] }); 133 | console.log(nodes.map(n => { 134 | return [n.id, n.characters] 135 | })) 136 | 137 | const frame = figma.createFrame() 138 | const nodes2 = frame.findAllWithCriteria({ sharedPluginData: { namespace: 'foo' } }) 139 | console.log(nodes2[0].id) 140 | } 141 | 142 | function testParameters() { 143 | figma.on('run', async ({ command, parameters }) => { 144 | console.log(command, parameters) 145 | }) 146 | } 147 | 148 | EOF 149 | 150 | npm install typescript 151 | npm install ../../ 152 | npx tsc --noEmit 153 | 154 | popd 155 | 156 | echo "Running test 2 (import and use types selectively)" 157 | mkdir test-2 158 | pushd test-2 159 | 160 | cat > package.json << EOF 161 | {} 162 | EOF 163 | 164 | cat > tsconfig.json << EOF 165 | { 166 | "compilerOptions": { 167 | "moduleResolution": "bundler", 168 | "target": "es6", 169 | "lib": ["es6"], 170 | "strict": true, 171 | "typeRoots": [] 172 | } 173 | } 174 | EOF 175 | 176 | cat > code.ts << EOF 177 | /** 178 | * Test file to test plugin-api-standalone.d.ts 179 | */ 180 | import { SceneNode, FrameNode, GradientPaint } from "@figma/plugin-typings/plugin-api-standalone" 181 | 182 | function isFrameNode(x: SceneNode): x is FrameNode { 183 | return x.type === "FRAME" 184 | } 185 | 186 | const gradient: GradientPaint = { 187 | type: "GRADIENT_LINEAR", 188 | gradientTransform: [[0, 0 ,0], [0, 0 ,0]], 189 | gradientStops: [ 190 | { 191 | position: 0, 192 | color: { r: 1, g: 1, b: 1, a: 1 } 193 | } 194 | ] 195 | } 196 | 197 | // @ts-expect-error No ambient types 198 | type VectorAlias = Vector 199 | EOF 200 | 201 | npm install typescript 202 | npm install ../../ 203 | npx tsc --noEmit 204 | 205 | popd 206 | -------------------------------------------------------------------------------- /plugin-api.d.ts: -------------------------------------------------------------------------------- 1 | /* plugin-typings are auto-generated. Do not update them directly. See plugin-docs/ for instructions. */ 2 | declare type ArgFreeEventType = 3 | | 'selectionchange' 4 | | 'currentpagechange' 5 | | 'close' 6 | | 'timerstart' 7 | | 'timerstop' 8 | | 'timerpause' 9 | | 'timerresume' 10 | | 'timeradjust' 11 | | 'timerdone' 12 | interface PluginAPI { 13 | readonly apiVersion: '1.0.0' 14 | readonly command: string 15 | readonly editorType: 'figma' | 'figjam' | 'dev' | 'slides' 16 | readonly mode: 'default' | 'textreview' | 'inspect' | 'codegen' | 'linkpreview' | 'auth' 17 | readonly pluginId?: string 18 | readonly widgetId?: string 19 | readonly fileKey: string | undefined 20 | skipInvisibleInstanceChildren: boolean 21 | readonly timer?: TimerAPI 22 | readonly viewport: ViewportAPI 23 | readonly currentUser: User | null 24 | readonly activeUsers: ActiveUser[] 25 | readonly textreview?: TextReviewAPI 26 | readonly codegen: CodegenAPI 27 | readonly vscode?: VSCodeAPI 28 | readonly devResources?: DevResourcesAPI 29 | readonly payments?: PaymentsAPI 30 | closePlugin(message?: string): void 31 | notify(message: string, options?: NotificationOptions): NotificationHandler 32 | commitUndo(): void 33 | triggerUndo(): void 34 | saveVersionHistoryAsync(title: string, description?: string): Promise 35 | openExternal(url: string): void 36 | showUI(html: string, options?: ShowUIOptions): void 37 | readonly ui: UIAPI 38 | readonly util: UtilAPI 39 | readonly constants: ConstantsAPI 40 | readonly clientStorage: ClientStorageAPI 41 | readonly parameters: ParametersAPI 42 | getNodeByIdAsync(id: string): Promise 43 | getNodeById(id: string): BaseNode | null 44 | getStyleByIdAsync(id: string): Promise 45 | getStyleById(id: string): BaseStyle | null 46 | readonly variables: VariablesAPI 47 | readonly teamLibrary: TeamLibraryAPI 48 | readonly annotations: AnnotationsAPI 49 | readonly root: DocumentNode 50 | currentPage: PageNode 51 | setCurrentPageAsync(page: PageNode): Promise 52 | on(type: ArgFreeEventType, callback: () => void): void 53 | on(type: 'run', callback: (event: RunEvent) => void): void 54 | on(type: 'drop', callback: (event: DropEvent) => boolean): void 55 | on(type: 'documentchange', callback: (event: DocumentChangeEvent) => void): void 56 | on(type: 'slidesviewchange', callback: (event: SlidesViewChangeEvent) => void): void 57 | on( 58 | type: 'textreview', 59 | callback: (event: TextReviewEvent) => Promise | TextReviewRange[], 60 | ): void 61 | on(type: 'stylechange', callback: (event: StyleChangeEvent) => void): void 62 | once(type: ArgFreeEventType, callback: () => void): void 63 | once(type: 'run', callback: (event: RunEvent) => void): void 64 | once(type: 'drop', callback: (event: DropEvent) => boolean): void 65 | once(type: 'documentchange', callback: (event: DocumentChangeEvent) => void): void 66 | once(type: 'slidesviewchange', callback: (event: SlidesViewChangeEvent) => void): void 67 | once( 68 | type: 'textreview', 69 | callback: (event: TextReviewEvent) => Promise | TextReviewRange[], 70 | ): void 71 | once(type: 'stylechange', callback: (event: StyleChangeEvent) => void): void 72 | off(type: ArgFreeEventType, callback: () => void): void 73 | off(type: 'run', callback: (event: RunEvent) => void): void 74 | off(type: 'drop', callback: (event: DropEvent) => boolean): void 75 | off(type: 'documentchange', callback: (event: DocumentChangeEvent) => void): void 76 | off(type: 'slidesviewchange', callback: (event: SlidesViewChangeEvent) => void): void 77 | off( 78 | type: 'textreview', 79 | callback: (event: TextReviewEvent) => Promise | TextReviewRange[], 80 | ): void 81 | off(type: 'stylechange', callback: (event: StyleChangeEvent) => void): void 82 | readonly mixed: unique symbol 83 | createRectangle(): RectangleNode 84 | createLine(): LineNode 85 | createEllipse(): EllipseNode 86 | createPolygon(): PolygonNode 87 | createStar(): StarNode 88 | createVector(): VectorNode 89 | createText(): TextNode 90 | createFrame(): FrameNode 91 | createComponent(): ComponentNode 92 | createComponentFromNode(node: SceneNode): ComponentNode 93 | createPage(): PageNode 94 | createPageDivider(dividerName?: string): PageNode 95 | createSlice(): SliceNode 96 | createSlide(row?: number, col?: number): SlideNode 97 | createSlideRow(row?: number): SlideRowNode 98 | createSticky(): StickyNode 99 | createConnector(): ConnectorNode 100 | createShapeWithText(): ShapeWithTextNode 101 | createCodeBlock(): CodeBlockNode 102 | createSection(): SectionNode 103 | createTable(numRows?: number, numColumns?: number): TableNode 104 | createNodeFromJSXAsync(jsx: any): Promise 105 | createBooleanOperation(): BooleanOperationNode 106 | createPaintStyle(): PaintStyle 107 | createTextStyle(): TextStyle 108 | createEffectStyle(): EffectStyle 109 | createGridStyle(): GridStyle 110 | getLocalPaintStylesAsync(): Promise 111 | getLocalPaintStyles(): PaintStyle[] 112 | getLocalTextStylesAsync(): Promise 113 | getLocalTextStyles(): TextStyle[] 114 | getLocalEffectStylesAsync(): Promise 115 | getLocalEffectStyles(): EffectStyle[] 116 | getLocalGridStylesAsync(): Promise 117 | getLocalGridStyles(): GridStyle[] 118 | getSelectionColors(): null | { 119 | paints: Paint[] 120 | styles: PaintStyle[] 121 | } 122 | moveLocalPaintStyleAfter(targetNode: PaintStyle, reference: PaintStyle | null): void 123 | moveLocalTextStyleAfter(targetNode: TextStyle, reference: TextStyle | null): void 124 | moveLocalEffectStyleAfter(targetNode: EffectStyle, reference: EffectStyle | null): void 125 | moveLocalGridStyleAfter(targetNode: GridStyle, reference: GridStyle | null): void 126 | moveLocalPaintFolderAfter(targetFolder: string, reference: string | null): void 127 | moveLocalTextFolderAfter(targetFolder: string, reference: string | null): void 128 | moveLocalEffectFolderAfter(targetFolder: string, reference: string | null): void 129 | moveLocalGridFolderAfter(targetFolder: string, reference: string | null): void 130 | importComponentByKeyAsync(key: string): Promise 131 | importComponentSetByKeyAsync(key: string): Promise 132 | importStyleByKeyAsync(key: string): Promise 133 | listAvailableFontsAsync(): Promise 134 | loadFontAsync(fontName: FontName): Promise 135 | readonly hasMissingFont: boolean 136 | createNodeFromSvg(svg: string): FrameNode 137 | createImage(data: Uint8Array): Image 138 | createImageAsync(src: string): Promise 139 | getImageByHash(hash: string): Image | null 140 | createVideoAsync(data: Uint8Array): Promise