├── .gitignore ├── LICENSE ├── README.md ├── code.ts ├── manifest.json ├── package.json ├── pnpm-lock.yaml ├── tsconfig.json └── ui.html /.gitignore: -------------------------------------------------------------------------------- 1 | # Node 2 | *.log 3 | *.log.* 4 | node_modules 5 | 6 | out/ 7 | dist/ 8 | code.js 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Figma to Lit 2 | 3 | This is a example plugin for Figma DevMode that exports a component to Lit Web Components. 4 | 5 | There is an option to export single or multiple components. 6 | -------------------------------------------------------------------------------- /code.ts: -------------------------------------------------------------------------------- 1 | import { camelCase, paramCase, pascalCase, snakeCase } from "change-case"; 2 | // @ts-ignore 3 | import Mustache from 'mustache'; 4 | 5 | figma.codegen.on("generate", async (event) => { 6 | const args = await createTemplate(event.node); 7 | return [ 8 | { 9 | language: "TYPESCRIPT", 10 | code: renderTemplate(args, true), 11 | title: "Lit (TS)", 12 | }, 13 | { 14 | language: "JAVASCRIPT", 15 | code: renderTemplate(args, false), 16 | title: "Lit (JS)", 17 | }, 18 | ]; 19 | }); 20 | 21 | const names = new Map(); 22 | 23 | function uniqueName(node: SceneNode | Variable) { 24 | for (const [key, value] of names) { 25 | if (value.id === node.id) { 26 | return key; 27 | } 28 | } 29 | function getName() { 30 | let target = node.name; 31 | if (target.includes('#')) { 32 | target = target.split('#')[0]; 33 | } 34 | return pascalCase(target); 35 | } 36 | let target = getName(); 37 | let count = 0; 38 | while (true) { 39 | if (!names.has(target)) { 40 | names.set(target, node); 41 | break; 42 | } 43 | target = `${getName()}${++count}`; 44 | } 45 | console.log(node, target); 46 | return target; 47 | } 48 | 49 | function normalize(str: string) { 50 | const regex = /[^\w\s\d]/g; 51 | return str.replace(regex, ''); 52 | } 53 | 54 | function className(str: string) { 55 | // Convert raw name to PascalCase 56 | let result = normalize(str); 57 | if (/^\d/.test(str)) { 58 | result = `X ${result}`; 59 | } 60 | if (!result.endsWith("Element")) { 61 | result += " Element"; 62 | } 63 | return pascalCase(result); 64 | } 65 | 66 | function tagName(str: string) { 67 | // Convert raw name to kebab-case 68 | let result = normalize(str.trim()); 69 | if (/^\d/.test(str)) { 70 | result = `x-${result}`; 71 | } 72 | result = paramCase(result); 73 | if (!result.endsWith("-element")) { 74 | result += "-element"; 75 | } 76 | return paramCase(result); 77 | } 78 | 79 | function propertyName(str: string) { 80 | let result = normalize(str); 81 | if (/^\d/.test(str)) { 82 | result = `x-${result}`; 83 | } 84 | return camelCase(result); 85 | } 86 | 87 | const litTSTemplate = ` 88 | import {html, css, LitElement} from 'lit'; 89 | import {customElement, property} from 'lit/decorators.js'; 90 | 91 | {{#components}} 92 | @customElement('{{tag}}') 93 | export class {{name}} extends LitElement { 94 | static styles = css\` 95 | {{#styles}} 96 | .{{selector}} { 97 | {{#attributes}} 98 | {{key}}: {{value}}; 99 | {{/attributes}} 100 | } 101 | {{/styles}} 102 | \`; 103 | 104 | {{#properties}} 105 | @property({type: {{type}}}) {{name}} = {{value}}; 106 | {{/properties}} 107 | 108 | {{#events}} 109 | {{name}}(e: {{type}}) { 110 | console.log('{{name}} {{type}}', e); 111 | } 112 | {{/events}} 113 | 114 | render() { 115 | return html\` 116 | {{#xml}}{{node}}{{/xml}} 117 | \`; 118 | } 119 | } 120 | 121 | {{/components}} 122 | `.trim(); 123 | 124 | const litJSTemplate = ` 125 | import {html, css, LitElement} from 'lit'; 126 | 127 | {{#components}} 128 | export class {{name}} extends LitElement { 129 | static styles = css\` 130 | {{#styles}} 131 | .{{selector}} { 132 | {{#attributes}} 133 | {{key}}: {{value}}; 134 | {{/attributes}} 135 | } 136 | {{/styles}} 137 | \`; 138 | 139 | static properties = { 140 | {{#properties}} 141 | {{name}}: {type: {{type}}}, 142 | {{/properties}} 143 | }; 144 | 145 | constructor() { 146 | super(); 147 | {{#properties}} 148 | this.{{name}} = {{value}}; 149 | {{/properties}} 150 | } 151 | 152 | {{#events}} 153 | {{name}}(e: {{type}}) { 154 | console.log('{{name}} {{type}}', e); 155 | } 156 | {{/events}} 157 | 158 | render() { 159 | return html\` 160 | {{#xml}}{{node}}{{/xml}} 161 | \`; 162 | } 163 | } 164 | customElements.define('{{tag}}', {{name}}); 165 | {{/components}} 166 | `.trim(); 167 | 168 | interface LitTemplate { 169 | components: LitComponent[]; 170 | } 171 | 172 | interface LitComponent { 173 | tag: string; 174 | name: string; 175 | styles: LitStyle[]; 176 | properties: LitProperty[]; 177 | events: LitEvent[]; 178 | node: LitNode; 179 | } 180 | 181 | interface LitStyle { 182 | selector: string; 183 | attributes: LitStyleAttribute[]; 184 | } 185 | 186 | interface LitStyleAttribute { 187 | key: string; 188 | value: string; 189 | } 190 | 191 | interface LitEvent { 192 | type: string; 193 | name: string; 194 | } 195 | 196 | interface LitProperty { 197 | type: string; 198 | name: string; 199 | value: string; 200 | } 201 | 202 | interface LitNode { 203 | tag: string; 204 | attributes: LitStyleAttribute[] | null; 205 | children: LitNode[] | string[] | null; 206 | component: boolean; 207 | node: SceneNode, 208 | } 209 | 210 | async function createTemplate(node: SceneNode): Promise { 211 | const components: LitComponent[] = []; 212 | 213 | async function addComponent(target: SceneNode) { 214 | // const globalAttrs = getNodeProperties(target, { recursive: true }); 215 | if (isComponent(target) || target === node) { 216 | const styles: LitStyle[] = []; 217 | const events: LitEvent[] = []; 218 | const properties: LitProperty[] = []; 219 | 220 | async function addStyle(child: SceneNode) { 221 | if (isComponent(child) && target !== child) return; 222 | 223 | const css = await child.getCSSAsync(); 224 | styles.push({ 225 | selector: tagName(uniqueName(child)), 226 | attributes: Object.entries(css).map((([key, value]) => ({ key, value }))) 227 | }); 228 | 229 | if ('children' in child) { 230 | for (const item of child.children) { 231 | await addStyle(item); 232 | } 233 | } 234 | } 235 | 236 | await addStyle(target); 237 | 238 | const attrs = getNodeProperties(target, { recursive: true }); 239 | for (const [key, value] of Object.entries({ ...attrs })) { 240 | properties.push({ 241 | type: 'String', 242 | name: propertyName(key), 243 | value: typeof value === 'string' ? `'${value}'` : value, 244 | }); 245 | } 246 | 247 | function addEvents(child: SceneNode) { 248 | if ('reactions' in child) { 249 | const reactions = child.reactions; 250 | for (const item of reactions) { 251 | if (item.trigger) { 252 | const type = item.trigger.type; 253 | if (type === 'ON_CLICK') { 254 | const eventName = propertyName(`${snakeCase(uniqueName(child))}-${type}`); 255 | events.push({ 256 | name: eventName, 257 | type: 'Event', 258 | }); 259 | } 260 | } 261 | } 262 | } 263 | if ('children' in child) { 264 | for (const item of child.children) { 265 | if (!isComponent(item)) { 266 | addEvents(item); 267 | } 268 | } 269 | } 270 | } 271 | 272 | addEvents(target); 273 | 274 | const component: LitComponent = { 275 | node: nodeTree(target), 276 | name: className(uniqueName(target)), 277 | tag: tagName(uniqueName(target)), 278 | styles, 279 | events, 280 | properties, 281 | }; 282 | components.push(component); 283 | 284 | if ('children' in target) { 285 | for (const child of target.children) { 286 | await addComponent(child); 287 | } 288 | } 289 | } 290 | } 291 | 292 | await addComponent(node); 293 | 294 | return { components }; 295 | } 296 | 297 | function renderXml(node: LitNode) { 298 | const sb: string[] = []; 299 | if (node.component) { 300 | if (node.attributes) { 301 | sb.push(`<${node.tag} `) 302 | for (const attr of node.attributes) { 303 | sb.push(` ${propertyName(attr.key)}=\${this.${propertyName(attr.key)}} `) 304 | } 305 | sb.push(`>`) 306 | } else { 307 | sb.push(`<${node.tag}>`) 308 | } 309 | sb.push(``) 310 | } else { 311 | let events = false; 312 | let element = 'div'; 313 | if ('reactions' in node.node) { 314 | const reactions = node.node.reactions; 315 | events = reactions.length > 0; 316 | for (const item of reactions) { 317 | if (item.trigger) { 318 | if ( 319 | item.trigger.type === "ON_CLICK" || 320 | item.trigger.type === "ON_HOVER" || 321 | item.trigger.type === "ON_PRESS" || 322 | item.trigger.type === "MOUSE_DOWN" 323 | ) { 324 | element = 'button'; 325 | } 326 | } 327 | } 328 | } 329 | if (events) { 330 | sb.push(`<${element} class="${node.tag}"`) 331 | if ('reactions' in node.node) { 332 | const reactions = node.node.reactions; 333 | for (const item of reactions) { 334 | if (item.trigger) { 335 | const type = item.trigger.type; 336 | if (type === 'ON_CLICK') { 337 | const eventName = propertyName(`${snakeCase(uniqueName(node.node))}-${type}`); 338 | sb.push(` @click=\${this.${eventName}}`); 339 | } 340 | } 341 | } 342 | } 343 | sb.push(`>`) 344 | } else { 345 | sb.push(`<${element} class="${node.tag}">`) 346 | } 347 | if (node.children) { 348 | for (const child of node.children) { 349 | if (typeof child === 'string') { 350 | let bound = false; 351 | if (node.node.boundVariables?.characters) { 352 | const variable = figma.variables.getVariableById(node.node.boundVariables.characters.id); 353 | if (variable) { 354 | sb.push(` \${this.${propertyName(uniqueName(variable))}}`); 355 | bound = true; 356 | } 357 | } else if (node.node.componentPropertyReferences?.characters) { 358 | const label = node.node.componentPropertyReferences.characters.split('#')[0]; 359 | sb.push(` \${this.${propertyName(label)}}`); 360 | bound = true; 361 | } 362 | if (!bound) sb.push(` ${child}`); 363 | } else { 364 | sb.push(` ${renderXml(child)}`); 365 | } 366 | } 367 | } 368 | sb.push(``) 369 | } 370 | return sb.join('\n'); 371 | } 372 | 373 | function renderTemplate(args: LitTemplate, typescript: boolean = true) { 374 | const template = typescript ? litTSTemplate : litJSTemplate; 375 | Mustache.escape = function (text: string) { return text; }; 376 | return Mustache.render(template, { 377 | ...args, 378 | "xml": function () { 379 | return () => renderXml(this.node); 380 | } 381 | }); 382 | } 383 | 384 | function getNodeProperties(node: SceneNode, options?: { 385 | recursive?: boolean 386 | }) { 387 | const attributes: { [key: string]: string } = {}; 388 | 389 | if (node.type === 'COMPONENT') { 390 | const properties = node.componentPropertyDefinitions; 391 | for (const [key, value] of Object.entries(properties)) { 392 | const label = key.split('#')[0]; 393 | attributes[label] = `${value.defaultValue}`; 394 | } 395 | } 396 | if (node.type === 'INSTANCE') { 397 | const properties = node.componentProperties; 398 | for (const [key, value] of Object.entries(properties)) { 399 | const label = key.split('#')[0]; 400 | attributes[label] = `${value.value}`; 401 | } 402 | } 403 | if (node.boundVariables) { 404 | const variables = node.boundVariables! 405 | if (variables?.characters) { 406 | const variable = figma.variables.getVariableById(variables.characters.id); 407 | if (variable) { 408 | attributes[uniqueName(variable)] = ''; 409 | } 410 | } 411 | } 412 | 413 | const references = node.componentPropertyReferences; 414 | if (references?.characters) { 415 | const label = references.characters.split('#')[0]; 416 | attributes[label] = attributes[label] ?? label; 417 | } 418 | 419 | if (options?.recursive) { 420 | if ('children' in node) { 421 | for (const child of node.children) { 422 | const attrs = getNodeProperties(child, { recursive: true }); 423 | for (const [key, value] of Object.entries(attrs)) { 424 | attributes[key] = value; 425 | } 426 | } 427 | } 428 | } 429 | 430 | return attributes; 431 | } 432 | 433 | function nodeTree(node: SceneNode, root: boolean = true): LitNode { 434 | const children: LitNode[] = []; 435 | const attributes = getNodeProperties(node, { recursive: true }); 436 | if ('children' in node) { 437 | for (const child of node.children) { 438 | children.push(nodeTree(child, false)); 439 | } 440 | } 441 | const attrs = Object.entries(attributes).map(([key, value]) => ({ key, value })); 442 | let str: string | null = null; 443 | if ('characters' in node) { 444 | str = node.characters; 445 | } 446 | return { 447 | node, 448 | tag: tagName(uniqueName(node)), 449 | children: children.length === 0 ? (str ? [str] : null) : children, 450 | attributes: attrs.length === 0 ? null : attrs, 451 | component: isComponent(node) && !root, 452 | }; 453 | } 454 | 455 | function isComponent(node: SceneNode) { 456 | return ( 457 | node.type === "COMPONENT" || 458 | node.type === "INSTANCE" || 459 | node.type === 'FRAME' 460 | ); 461 | } 462 | -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Figma to Lit", 3 | "id": "1253959744483104113", 4 | "api": "1.0.0", 5 | "main": "code.js", 6 | "capabilities": [ 7 | "codegen" 8 | ], 9 | "enableProposedApi": false, 10 | "editorType": [ 11 | "dev" 12 | ], 13 | "ui": "ui.html", 14 | "codegenPreferences": [ 15 | { 16 | "itemType": "select", 17 | "propertyName": "outputType", 18 | "label": "Output Type", 19 | "options": [ 20 | { 21 | "label": "Single Web Component", 22 | "value": "single", "isDefault": true 23 | }, 24 | { 25 | "label": "Separate Web Components", 26 | "value": "multi" 27 | } 28 | ] 29 | } 30 | ], 31 | "codegenLanguages": [ 32 | { 33 | "label": "Lit", 34 | "value": "typescript" 35 | } 36 | ], 37 | "networkAccess": { 38 | "allowedDomains": [ 39 | "none" 40 | ] 41 | } 42 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "figma-lit-exporter", 3 | "version": "1.0.0", 4 | "description": "Lit (Web Component) export for Figma", 5 | "main": "code.js", 6 | "scripts": { 7 | "build": "esbuild code.ts --bundle --outfile=code.js --target=ES6", 8 | "watch": "esbuild code.ts --bundle --outfile=code.js --target=ES6 --watch" 9 | }, 10 | "author": "", 11 | "license": "", 12 | "devDependencies": { 13 | "@figma/plugin-typings": "*", 14 | "@types/mustache": "^4.2.2", 15 | "esbuild": "^0.18.7", 16 | "typescript": "*" 17 | }, 18 | "dependencies": { 19 | "change-case": "^4.1.2", 20 | "js-beautify": "^1.14.8", 21 | "mustache": "^4.2.0", 22 | "xml-formatter": "^3.4.1" 23 | } 24 | } -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: 5.4 2 | 3 | specifiers: 4 | '@figma/plugin-typings': '*' 5 | '@types/mustache': ^4.2.2 6 | change-case: ^4.1.2 7 | esbuild: ^0.18.7 8 | js-beautify: ^1.14.8 9 | mustache: ^4.2.0 10 | typescript: '*' 11 | xml-formatter: ^3.4.1 12 | 13 | dependencies: 14 | change-case: 4.1.2 15 | js-beautify: 1.14.8 16 | mustache: 4.2.0 17 | xml-formatter: 3.4.1 18 | 19 | devDependencies: 20 | '@figma/plugin-typings': 1.68.0 21 | '@types/mustache': 4.2.2 22 | esbuild: 0.18.9 23 | typescript: 5.1.3 24 | 25 | packages: 26 | 27 | /@esbuild/android-arm/0.18.9: 28 | resolution: {integrity: sha512-v1cr0l0RZOzIgLtTe8M1cRFFP0ICRdymPPa8HCPUpgZ+XasQrd5Mxyp9KlDqXLLyGmnZpzhufKEThLIihQL53A==} 29 | engines: {node: '>=12'} 30 | cpu: [arm] 31 | os: [android] 32 | requiresBuild: true 33 | dev: true 34 | optional: true 35 | 36 | /@esbuild/android-arm64/0.18.9: 37 | resolution: {integrity: sha512-G1rIBpSgjv0DEFmBYjljL85l4asf1dtQYwjoD02A5YG85JV3dsQSJL94vsEMWYMWkNd46hcvz3suURuY4dr+9g==} 38 | engines: {node: '>=12'} 39 | cpu: [arm64] 40 | os: [android] 41 | requiresBuild: true 42 | dev: true 43 | optional: true 44 | 45 | /@esbuild/android-x64/0.18.9: 46 | resolution: {integrity: sha512-rPgcISGfoP7/Yk8+0eUf9R/KLCYGgqtojz/Uvj26wp7/EclwxoaOMArBnDChfuWF5YLdS16dDfqb4qwXS087lw==} 47 | engines: {node: '>=12'} 48 | cpu: [x64] 49 | os: [android] 50 | requiresBuild: true 51 | dev: true 52 | optional: true 53 | 54 | /@esbuild/darwin-arm64/0.18.9: 55 | resolution: {integrity: sha512-vw9kWBT2EvDhLAVkI5c2KWFh+GMwgXrzR1QnIpZazA+tIacaelNLMMSTHEJisOeQqiMQhv8goTODFm9liS7wpw==} 56 | engines: {node: '>=12'} 57 | cpu: [arm64] 58 | os: [darwin] 59 | requiresBuild: true 60 | dev: true 61 | optional: true 62 | 63 | /@esbuild/darwin-x64/0.18.9: 64 | resolution: {integrity: sha512-tDbKKMUeS0PckRtIxdF3+NgkE19kTyLFmUQ0umgXDnBvcWC3/DqhZyu4P4Af3zBzOfWH5DAAmGW1hgy53Z706w==} 65 | engines: {node: '>=12'} 66 | cpu: [x64] 67 | os: [darwin] 68 | requiresBuild: true 69 | dev: true 70 | optional: true 71 | 72 | /@esbuild/freebsd-arm64/0.18.9: 73 | resolution: {integrity: sha512-Anyk3qeTKJUcxiLE8VQ6y6frVuqFc71M5TEc2EzvXchoy6oWn5eZK+MpZBVnENVMSDA4wOjDKiFsPtVhnrhHHA==} 74 | engines: {node: '>=12'} 75 | cpu: [arm64] 76 | os: [freebsd] 77 | requiresBuild: true 78 | dev: true 79 | optional: true 80 | 81 | /@esbuild/freebsd-x64/0.18.9: 82 | resolution: {integrity: sha512-BsOYio/4p/6RWG+sDQXVYet8qQ0bB91rfO0YNk5s0HlqE9vEth3Yi1jFNi4v7bUA4vQDWWoybpA/9NTz1sM88A==} 83 | engines: {node: '>=12'} 84 | cpu: [x64] 85 | os: [freebsd] 86 | requiresBuild: true 87 | dev: true 88 | optional: true 89 | 90 | /@esbuild/linux-arm/0.18.9: 91 | resolution: {integrity: sha512-YotJBEt9swVrEBRBIXQzI03A4kDQSWk+mbGTTBreIRvWWWTXXqhNYZgqiwnEvtyQi9aqSipEzkRzAGNqs54EXw==} 92 | engines: {node: '>=12'} 93 | cpu: [arm] 94 | os: [linux] 95 | requiresBuild: true 96 | dev: true 97 | optional: true 98 | 99 | /@esbuild/linux-arm64/0.18.9: 100 | resolution: {integrity: sha512-2fJtf4KKR301FrhRNY1KIgVid2nUrZV6fzx39E+JgT3jAw2NsZYUiphR31CyH4MloyoEwgQTnskwaQH+nT4bHA==} 101 | engines: {node: '>=12'} 102 | cpu: [arm64] 103 | os: [linux] 104 | requiresBuild: true 105 | dev: true 106 | optional: true 107 | 108 | /@esbuild/linux-ia32/0.18.9: 109 | resolution: {integrity: sha512-pTTBAGi2lrduXo4vATnqCtFi9zRbyXOlcV+euznW5EoFyjAIR+JCQgFDeFCMo343E2EI2MgV7ZQctO8IWcsdsA==} 110 | engines: {node: '>=12'} 111 | cpu: [ia32] 112 | os: [linux] 113 | requiresBuild: true 114 | dev: true 115 | optional: true 116 | 117 | /@esbuild/linux-loong64/0.18.9: 118 | resolution: {integrity: sha512-hmsjvhwHrsCKPthXhhNjLE+QON8uQCE9P/OBktaYOD8UDfmz9+txm04uXhnkRH0fDEqStsDEedbX+8KPg1CwyA==} 119 | engines: {node: '>=12'} 120 | cpu: [loong64] 121 | os: [linux] 122 | requiresBuild: true 123 | dev: true 124 | optional: true 125 | 126 | /@esbuild/linux-mips64el/0.18.9: 127 | resolution: {integrity: sha512-Ymv4j25ie7mVEVlcThnOlRVvqDSsj22MJBH31QGMsyA0dUwReqCg9yNqRM2Dh8QHDRO2UrMhGmiL6BaTdBWlQw==} 128 | engines: {node: '>=12'} 129 | cpu: [mips64el] 130 | os: [linux] 131 | requiresBuild: true 132 | dev: true 133 | optional: true 134 | 135 | /@esbuild/linux-ppc64/0.18.9: 136 | resolution: {integrity: sha512-y2viEHwLpNfWP1eLa+vV+DWIbw/pQyv1Vf6qxSGJeBQmmu9T2hOagMiCr6zhDo89l+MUAXiShdKmqlKI6HdCkw==} 137 | engines: {node: '>=12'} 138 | cpu: [ppc64] 139 | os: [linux] 140 | requiresBuild: true 141 | dev: true 142 | optional: true 143 | 144 | /@esbuild/linux-riscv64/0.18.9: 145 | resolution: {integrity: sha512-na8WG8Z7z1EIUcJFuXKOawJEsq8luOur7LHK/ophO0+RSE8A9yxCsKYhaN9IxlR1UciAuHjo/7d5yiflABwUmA==} 146 | engines: {node: '>=12'} 147 | cpu: [riscv64] 148 | os: [linux] 149 | requiresBuild: true 150 | dev: true 151 | optional: true 152 | 153 | /@esbuild/linux-s390x/0.18.9: 154 | resolution: {integrity: sha512-XsnaI89KstE0jG4cMdzuJ8SKcKAod26had7U/4SzvuMrci0/XyEQXB1jikn6MB7LPGrd5rcLeYp3F7psUxhkWw==} 155 | engines: {node: '>=12'} 156 | cpu: [s390x] 157 | os: [linux] 158 | requiresBuild: true 159 | dev: true 160 | optional: true 161 | 162 | /@esbuild/linux-x64/0.18.9: 163 | resolution: {integrity: sha512-odEbmjtm3tLPtY43FRWOG+CLN7d4ooQpGjYVFVti5rLXLym26dORxnlbekNPXuQRuQKNMPczNNWE1jOc8yAyJQ==} 164 | engines: {node: '>=12'} 165 | cpu: [x64] 166 | os: [linux] 167 | requiresBuild: true 168 | dev: true 169 | optional: true 170 | 171 | /@esbuild/netbsd-x64/0.18.9: 172 | resolution: {integrity: sha512-j/GgOjKNUPd54isC/RBYlS6CREbulnMWAJEIKTnPM0QnY0pEGfMHkFh73bsmZdovp/97zRty0NdePRk4dTP/cw==} 173 | engines: {node: '>=12'} 174 | cpu: [x64] 175 | os: [netbsd] 176 | requiresBuild: true 177 | dev: true 178 | optional: true 179 | 180 | /@esbuild/openbsd-x64/0.18.9: 181 | resolution: {integrity: sha512-DN0Z9RGU/hlaMWSG9GaDLvlu0718u1HDGiF19wJ35fUznf9yJYgXDwZ5/cRQXUewHXJB0pD/VyQfRLDP3M4maw==} 182 | engines: {node: '>=12'} 183 | cpu: [x64] 184 | os: [openbsd] 185 | requiresBuild: true 186 | dev: true 187 | optional: true 188 | 189 | /@esbuild/sunos-x64/0.18.9: 190 | resolution: {integrity: sha512-W/eHabLCXdki/8H3jmfE/ClDuh3bQQKpYfQHGQ7lQync9W72ZdVr2y1iWfEVTE7ZK/DQROo3GyfTkx5HPBZxmQ==} 191 | engines: {node: '>=12'} 192 | cpu: [x64] 193 | os: [sunos] 194 | requiresBuild: true 195 | dev: true 196 | optional: true 197 | 198 | /@esbuild/win32-arm64/0.18.9: 199 | resolution: {integrity: sha512-84FMz3Sh1hwGk/oWy6XGIW2bGVcsqvHLjjtbwd982XoTHOvQSthhrMef0J+4ShE1ZE7VeUXHIt2Mfer+myedYw==} 200 | engines: {node: '>=12'} 201 | cpu: [arm64] 202 | os: [win32] 203 | requiresBuild: true 204 | dev: true 205 | optional: true 206 | 207 | /@esbuild/win32-ia32/0.18.9: 208 | resolution: {integrity: sha512-/RsFTk0P13Nb+ixBVZfPdlLWKsP+he3ZLxOO/1eCsZZ2U7c/JxB053U7kURsyhhUPwiGzGVaAQAeyhGtYe8ehw==} 209 | engines: {node: '>=12'} 210 | cpu: [ia32] 211 | os: [win32] 212 | requiresBuild: true 213 | dev: true 214 | optional: true 215 | 216 | /@esbuild/win32-x64/0.18.9: 217 | resolution: {integrity: sha512-S+oBiO8UE1hmDJZlZJ6HZEdBBrxCGovwN66P9rle4DWVktM5fsMouYhpbtUf4WQLEy0HvcE2ZOQ2gIq8v0BkBw==} 218 | engines: {node: '>=12'} 219 | cpu: [x64] 220 | os: [win32] 221 | requiresBuild: true 222 | dev: true 223 | optional: true 224 | 225 | /@figma/plugin-typings/1.68.0: 226 | resolution: {integrity: sha512-hT+iqf5CRRqKI7NmPdwml+Ld/mG1QM8VcZZURV2AowIy6vC3VQ2iIIT5d7ulDnQU+WzQDvaGaDAw/J5X6tQ2Ww==} 227 | dev: true 228 | 229 | /@types/mustache/4.2.2: 230 | resolution: {integrity: sha512-MUSpfpW0yZbTgjekDbH0shMYBUD+X/uJJJMm9LXN1d5yjl5lCY1vN/eWKD6D1tOtjA6206K0zcIPnUaFMurdNA==} 231 | dev: true 232 | 233 | /abbrev/1.1.1: 234 | resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} 235 | dev: false 236 | 237 | /balanced-match/1.0.2: 238 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 239 | dev: false 240 | 241 | /brace-expansion/2.0.1: 242 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 243 | dependencies: 244 | balanced-match: 1.0.2 245 | dev: false 246 | 247 | /camel-case/4.1.2: 248 | resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} 249 | dependencies: 250 | pascal-case: 3.1.2 251 | tslib: 2.5.3 252 | dev: false 253 | 254 | /capital-case/1.0.4: 255 | resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==} 256 | dependencies: 257 | no-case: 3.0.4 258 | tslib: 2.5.3 259 | upper-case-first: 2.0.2 260 | dev: false 261 | 262 | /change-case/4.1.2: 263 | resolution: {integrity: sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==} 264 | dependencies: 265 | camel-case: 4.1.2 266 | capital-case: 1.0.4 267 | constant-case: 3.0.4 268 | dot-case: 3.0.4 269 | header-case: 2.0.4 270 | no-case: 3.0.4 271 | param-case: 3.0.4 272 | pascal-case: 3.1.2 273 | path-case: 3.0.4 274 | sentence-case: 3.0.4 275 | snake-case: 3.0.4 276 | tslib: 2.5.3 277 | dev: false 278 | 279 | /commander/2.20.3: 280 | resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} 281 | dev: false 282 | 283 | /config-chain/1.1.13: 284 | resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} 285 | dependencies: 286 | ini: 1.3.8 287 | proto-list: 1.2.4 288 | dev: false 289 | 290 | /constant-case/3.0.4: 291 | resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==} 292 | dependencies: 293 | no-case: 3.0.4 294 | tslib: 2.5.3 295 | upper-case: 2.0.2 296 | dev: false 297 | 298 | /dot-case/3.0.4: 299 | resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} 300 | dependencies: 301 | no-case: 3.0.4 302 | tslib: 2.5.3 303 | dev: false 304 | 305 | /editorconfig/0.15.3: 306 | resolution: {integrity: sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==} 307 | hasBin: true 308 | dependencies: 309 | commander: 2.20.3 310 | lru-cache: 4.1.5 311 | semver: 5.7.1 312 | sigmund: 1.0.1 313 | dev: false 314 | 315 | /esbuild/0.18.9: 316 | resolution: {integrity: sha512-rFw+7KsO3vF/imkldsCcIGnQVJ11Zq5a178SVS0N0wwFQ/alzS8owG06rivQ8FEuc66SJupdhTuYT7mnvmidLA==} 317 | engines: {node: '>=12'} 318 | hasBin: true 319 | requiresBuild: true 320 | optionalDependencies: 321 | '@esbuild/android-arm': 0.18.9 322 | '@esbuild/android-arm64': 0.18.9 323 | '@esbuild/android-x64': 0.18.9 324 | '@esbuild/darwin-arm64': 0.18.9 325 | '@esbuild/darwin-x64': 0.18.9 326 | '@esbuild/freebsd-arm64': 0.18.9 327 | '@esbuild/freebsd-x64': 0.18.9 328 | '@esbuild/linux-arm': 0.18.9 329 | '@esbuild/linux-arm64': 0.18.9 330 | '@esbuild/linux-ia32': 0.18.9 331 | '@esbuild/linux-loong64': 0.18.9 332 | '@esbuild/linux-mips64el': 0.18.9 333 | '@esbuild/linux-ppc64': 0.18.9 334 | '@esbuild/linux-riscv64': 0.18.9 335 | '@esbuild/linux-s390x': 0.18.9 336 | '@esbuild/linux-x64': 0.18.9 337 | '@esbuild/netbsd-x64': 0.18.9 338 | '@esbuild/openbsd-x64': 0.18.9 339 | '@esbuild/sunos-x64': 0.18.9 340 | '@esbuild/win32-arm64': 0.18.9 341 | '@esbuild/win32-ia32': 0.18.9 342 | '@esbuild/win32-x64': 0.18.9 343 | dev: true 344 | 345 | /fs.realpath/1.0.0: 346 | resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} 347 | dev: false 348 | 349 | /glob/8.1.0: 350 | resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} 351 | engines: {node: '>=12'} 352 | dependencies: 353 | fs.realpath: 1.0.0 354 | inflight: 1.0.6 355 | inherits: 2.0.4 356 | minimatch: 5.1.6 357 | once: 1.4.0 358 | dev: false 359 | 360 | /header-case/2.0.4: 361 | resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==} 362 | dependencies: 363 | capital-case: 1.0.4 364 | tslib: 2.5.3 365 | dev: false 366 | 367 | /inflight/1.0.6: 368 | resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} 369 | dependencies: 370 | once: 1.4.0 371 | wrappy: 1.0.2 372 | dev: false 373 | 374 | /inherits/2.0.4: 375 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 376 | dev: false 377 | 378 | /ini/1.3.8: 379 | resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} 380 | dev: false 381 | 382 | /js-beautify/1.14.8: 383 | resolution: {integrity: sha512-4S7HFeI9YfRvRgKnEweohs0tgJj28InHVIj4Nl8Htf96Y6pHg3+tJrmo4ucAM9f7l4SHbFI3IvFAZ2a1eQPbyg==} 384 | engines: {node: '>=12'} 385 | hasBin: true 386 | dependencies: 387 | config-chain: 1.1.13 388 | editorconfig: 0.15.3 389 | glob: 8.1.0 390 | nopt: 6.0.0 391 | dev: false 392 | 393 | /lower-case/2.0.2: 394 | resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} 395 | dependencies: 396 | tslib: 2.5.3 397 | dev: false 398 | 399 | /lru-cache/4.1.5: 400 | resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} 401 | dependencies: 402 | pseudomap: 1.0.2 403 | yallist: 2.1.2 404 | dev: false 405 | 406 | /minimatch/5.1.6: 407 | resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} 408 | engines: {node: '>=10'} 409 | dependencies: 410 | brace-expansion: 2.0.1 411 | dev: false 412 | 413 | /mustache/4.2.0: 414 | resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} 415 | hasBin: true 416 | dev: false 417 | 418 | /no-case/3.0.4: 419 | resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} 420 | dependencies: 421 | lower-case: 2.0.2 422 | tslib: 2.5.3 423 | dev: false 424 | 425 | /nopt/6.0.0: 426 | resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==} 427 | engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} 428 | hasBin: true 429 | dependencies: 430 | abbrev: 1.1.1 431 | dev: false 432 | 433 | /once/1.4.0: 434 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} 435 | dependencies: 436 | wrappy: 1.0.2 437 | dev: false 438 | 439 | /param-case/3.0.4: 440 | resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} 441 | dependencies: 442 | dot-case: 3.0.4 443 | tslib: 2.5.3 444 | dev: false 445 | 446 | /pascal-case/3.1.2: 447 | resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} 448 | dependencies: 449 | no-case: 3.0.4 450 | tslib: 2.5.3 451 | dev: false 452 | 453 | /path-case/3.0.4: 454 | resolution: {integrity: sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==} 455 | dependencies: 456 | dot-case: 3.0.4 457 | tslib: 2.5.3 458 | dev: false 459 | 460 | /proto-list/1.2.4: 461 | resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} 462 | dev: false 463 | 464 | /pseudomap/1.0.2: 465 | resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} 466 | dev: false 467 | 468 | /semver/5.7.1: 469 | resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} 470 | hasBin: true 471 | dev: false 472 | 473 | /sentence-case/3.0.4: 474 | resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==} 475 | dependencies: 476 | no-case: 3.0.4 477 | tslib: 2.5.3 478 | upper-case-first: 2.0.2 479 | dev: false 480 | 481 | /sigmund/1.0.1: 482 | resolution: {integrity: sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==} 483 | dev: false 484 | 485 | /snake-case/3.0.4: 486 | resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} 487 | dependencies: 488 | dot-case: 3.0.4 489 | tslib: 2.5.3 490 | dev: false 491 | 492 | /tslib/2.5.3: 493 | resolution: {integrity: sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==} 494 | dev: false 495 | 496 | /typescript/5.1.3: 497 | resolution: {integrity: sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==} 498 | engines: {node: '>=14.17'} 499 | hasBin: true 500 | dev: true 501 | 502 | /upper-case-first/2.0.2: 503 | resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==} 504 | dependencies: 505 | tslib: 2.5.3 506 | dev: false 507 | 508 | /upper-case/2.0.2: 509 | resolution: {integrity: sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==} 510 | dependencies: 511 | tslib: 2.5.3 512 | dev: false 513 | 514 | /wrappy/1.0.2: 515 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 516 | dev: false 517 | 518 | /xml-formatter/3.4.1: 519 | resolution: {integrity: sha512-C7VwnZpz662mZlKtrdREucsABAIlmdph/nMEUszTMsRAGGPMSNfyNOU4UaPBqxXYVadb9uSpc1Xibbj6XpbGRA==} 520 | engines: {node: '>= 14'} 521 | dependencies: 522 | xml-parser-xo: 4.1.0 523 | dev: false 524 | 525 | /xml-parser-xo/4.1.0: 526 | resolution: {integrity: sha512-9mQMLmq8J++XlQH9WF57oQxFVbR3YM6dPPtTuV+++aMe2gRoRU/kj819/6IptUmfhC1d2DSFiYxEcpkoLabeJw==} 527 | engines: {node: '>= 14'} 528 | dev: false 529 | 530 | /yallist/2.1.2: 531 | resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} 532 | dev: false 533 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "lib": ["es2017"], 5 | "strict": true, 6 | "moduleResolution": "node", 7 | "typeRoots": [ 8 | "./node_modules/@types", 9 | "./node_modules/@figma" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /ui.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rodydavis/figma-to-lit/65df555f378e06f13c57bb8081f6e2b598856f81/ui.html --------------------------------------------------------------------------------