@llc3233149/core 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (457) hide show
  1. package/dist/canvaskit.d.ts +9 -0
  2. package/dist/canvaskit.d.ts.map +1 -0
  3. package/dist/canvaskit.js +55 -0
  4. package/dist/canvaskit.js.map +1 -0
  5. package/dist/clipboard.d.ts +32 -0
  6. package/dist/clipboard.d.ts.map +1 -0
  7. package/dist/clipboard.js +345 -0
  8. package/dist/clipboard.js.map +1 -0
  9. package/dist/color.d.ts +28 -0
  10. package/dist/color.d.ts.map +1 -0
  11. package/dist/color.js +67 -0
  12. package/dist/color.js.map +1 -0
  13. package/dist/constants.d.ts +159 -0
  14. package/dist/constants.d.ts.map +1 -0
  15. package/dist/constants.js +224 -0
  16. package/dist/constants.js.map +1 -0
  17. package/dist/copy.d.ts +20 -0
  18. package/dist/copy.d.ts.map +1 -0
  19. package/dist/copy.js +64 -0
  20. package/dist/copy.js.map +1 -0
  21. package/dist/fig-export-worker.d.ts +2 -0
  22. package/dist/fig-export-worker.d.ts.map +1 -0
  23. package/dist/fig-export-worker.js +17 -0
  24. package/dist/fig-export-worker.js.map +1 -0
  25. package/dist/fig-export.d.ts +13 -0
  26. package/dist/fig-export.d.ts.map +1 -0
  27. package/dist/fig-export.js +243 -0
  28. package/dist/fig-export.js.map +1 -0
  29. package/dist/figma-api.d.ts +268 -0
  30. package/dist/figma-api.d.ts.map +1 -0
  31. package/dist/figma-api.js +1074 -0
  32. package/dist/figma-api.js.map +1 -0
  33. package/dist/figma-rest-import.d.ts +122 -0
  34. package/dist/figma-rest-import.d.ts.map +1 -0
  35. package/dist/figma-rest-import.js +319 -0
  36. package/dist/figma-rest-import.js.map +1 -0
  37. package/dist/fonts.d.ts +24 -0
  38. package/dist/fonts.d.ts.map +1 -0
  39. package/dist/fonts.js +356 -0
  40. package/dist/fonts.js.map +1 -0
  41. package/dist/geometry.d.ts +14 -0
  42. package/dist/geometry.d.ts.map +1 -0
  43. package/dist/geometry.js +47 -0
  44. package/dist/geometry.js.map +1 -0
  45. package/dist/index.d.ts +38 -0
  46. package/dist/index.d.ts.map +1 -0
  47. package/dist/index.js +32 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/kiwi/codec.d.ts +292 -0
  50. package/dist/kiwi/codec.d.ts.map +1 -0
  51. package/dist/kiwi/codec.js +340 -0
  52. package/dist/kiwi/codec.js.map +1 -0
  53. package/dist/kiwi/fig-file.d.ts +4 -0
  54. package/dist/kiwi/fig-file.d.ts.map +1 -0
  55. package/dist/kiwi/fig-file.js +236 -0
  56. package/dist/kiwi/fig-file.js.map +1 -0
  57. package/dist/kiwi/fig-import.d.ts +4 -0
  58. package/dist/kiwi/fig-import.d.ts.map +1 -0
  59. package/dist/kiwi/fig-import.js +248 -0
  60. package/dist/kiwi/fig-import.js.map +1 -0
  61. package/dist/kiwi/fig-parse-worker.d.ts +7 -0
  62. package/dist/kiwi/fig-parse-worker.d.ts.map +1 -0
  63. package/dist/kiwi/fig-parse-worker.js +184 -0
  64. package/dist/kiwi/fig-parse-worker.js.map +1 -0
  65. package/dist/kiwi/instance-overrides.d.ts +66 -0
  66. package/dist/kiwi/instance-overrides.d.ts.map +1 -0
  67. package/dist/kiwi/instance-overrides.js +644 -0
  68. package/dist/kiwi/instance-overrides.js.map +1 -0
  69. package/dist/kiwi/kiwi-convert.d.ts +19 -0
  70. package/dist/kiwi/kiwi-convert.d.ts.map +1 -0
  71. package/dist/kiwi/kiwi-convert.js +678 -0
  72. package/dist/kiwi/kiwi-convert.js.map +1 -0
  73. package/dist/kiwi/kiwi-schema/bb.d.ts +25 -0
  74. package/dist/kiwi/kiwi-schema/bb.d.ts.map +1 -0
  75. package/dist/kiwi/kiwi-schema/bb.js +225 -0
  76. package/dist/kiwi/kiwi-schema/bb.js.map +1 -0
  77. package/dist/kiwi/kiwi-schema/binary.d.ts +5 -0
  78. package/dist/kiwi/kiwi-schema/binary.d.ts.map +1 -0
  79. package/dist/kiwi/kiwi-schema/binary.js +86 -0
  80. package/dist/kiwi/kiwi-schema/binary.js.map +1 -0
  81. package/dist/kiwi/kiwi-schema/index.d.ts +6 -0
  82. package/dist/kiwi/kiwi-schema/index.d.ts.map +1 -0
  83. package/dist/kiwi/kiwi-schema/index.js +5 -0
  84. package/dist/kiwi/kiwi-schema/index.js.map +1 -0
  85. package/dist/kiwi/kiwi-schema/js.d.ts +4 -0
  86. package/dist/kiwi/kiwi-schema/js.d.ts.map +1 -0
  87. package/dist/kiwi/kiwi-schema/js.js +282 -0
  88. package/dist/kiwi/kiwi-schema/js.js.map +1 -0
  89. package/dist/kiwi/kiwi-schema/parser.d.ts +5 -0
  90. package/dist/kiwi/kiwi-schema/parser.d.ts.map +1 -0
  91. package/dist/kiwi/kiwi-schema/parser.js +228 -0
  92. package/dist/kiwi/kiwi-schema/parser.js.map +1 -0
  93. package/dist/kiwi/kiwi-schema/schema.d.ts +22 -0
  94. package/dist/kiwi/kiwi-schema/schema.d.ts.map +1 -0
  95. package/dist/kiwi/kiwi-schema/schema.js +2 -0
  96. package/dist/kiwi/kiwi-schema/schema.js.map +1 -0
  97. package/dist/kiwi/kiwi-schema/util.d.ts +3 -0
  98. package/dist/kiwi/kiwi-schema/util.d.ts.map +1 -0
  99. package/dist/kiwi/kiwi-schema/util.js +10 -0
  100. package/dist/kiwi/kiwi-schema/util.js.map +1 -0
  101. package/dist/kiwi/protocol.d.ts +172 -0
  102. package/dist/kiwi/protocol.d.ts.map +1 -0
  103. package/dist/kiwi/protocol.js +214 -0
  104. package/dist/kiwi/protocol.js.map +1 -0
  105. package/dist/kiwi/schema.d.ts +3 -0
  106. package/dist/kiwi/schema.d.ts.map +1 -0
  107. package/dist/kiwi/schema.js +2285 -0
  108. package/dist/kiwi/schema.js.map +1 -0
  109. package/dist/kiwi-serialize.d.ts +17 -0
  110. package/dist/kiwi-serialize.d.ts.map +1 -0
  111. package/dist/kiwi-serialize.js +419 -0
  112. package/dist/kiwi-serialize.js.map +1 -0
  113. package/dist/layout.d.ts +9 -0
  114. package/dist/layout.d.ts.map +1 -0
  115. package/dist/layout.js +533 -0
  116. package/dist/layout.js.map +1 -0
  117. package/dist/profiler/draw-call-counter.d.ts +9 -0
  118. package/dist/profiler/draw-call-counter.d.ts.map +1 -0
  119. package/dist/profiler/draw-call-counter.js +37 -0
  120. package/dist/profiler/draw-call-counter.js.map +1 -0
  121. package/dist/profiler/frame-capture.d.ts +34 -0
  122. package/dist/profiler/frame-capture.d.ts.map +1 -0
  123. package/dist/profiler/frame-capture.js +90 -0
  124. package/dist/profiler/frame-capture.js.map +1 -0
  125. package/dist/profiler/frame-stats.d.ts +33 -0
  126. package/dist/profiler/frame-stats.d.ts.map +1 -0
  127. package/dist/profiler/frame-stats.js +103 -0
  128. package/dist/profiler/frame-stats.js.map +1 -0
  129. package/dist/profiler/gpu-timer.d.ts +15 -0
  130. package/dist/profiler/gpu-timer.d.ts.map +1 -0
  131. package/dist/profiler/gpu-timer.js +77 -0
  132. package/dist/profiler/gpu-timer.js.map +1 -0
  133. package/dist/profiler/hud-renderer.d.ts +22 -0
  134. package/dist/profiler/hud-renderer.d.ts.map +1 -0
  135. package/dist/profiler/hud-renderer.js +200 -0
  136. package/dist/profiler/hud-renderer.js.map +1 -0
  137. package/dist/profiler/index.d.ts +9 -0
  138. package/dist/profiler/index.d.ts.map +1 -0
  139. package/dist/profiler/index.js +8 -0
  140. package/dist/profiler/index.js.map +1 -0
  141. package/dist/profiler/phase-timer.d.ts +9 -0
  142. package/dist/profiler/phase-timer.d.ts.map +1 -0
  143. package/dist/profiler/phase-timer.js +51 -0
  144. package/dist/profiler/phase-timer.js.map +1 -0
  145. package/dist/profiler/render-profiler.d.ts +41 -0
  146. package/dist/profiler/render-profiler.d.ts.map +1 -0
  147. package/dist/profiler/render-profiler.js +142 -0
  148. package/dist/profiler/render-profiler.js.map +1 -0
  149. package/dist/render/components.d.ts +25 -0
  150. package/dist/render/components.d.ts.map +1 -0
  151. package/dist/render/components.js +55 -0
  152. package/dist/render/components.js.map +1 -0
  153. package/dist/render/emoji-icons.d.ts +5 -0
  154. package/dist/render/emoji-icons.d.ts.map +1 -0
  155. package/dist/render/emoji-icons.js +55 -0
  156. package/dist/render/emoji-icons.js.map +1 -0
  157. package/dist/render/export-code.d.ts +9 -0
  158. package/dist/render/export-code.d.ts.map +1 -0
  159. package/dist/render/export-code.js +335 -0
  160. package/dist/render/export-code.js.map +1 -0
  161. package/dist/render/export-jsx.d.ts +5 -0
  162. package/dist/render/export-jsx.d.ts.map +1 -0
  163. package/dist/render/export-jsx.js +621 -0
  164. package/dist/render/export-jsx.js.map +1 -0
  165. package/dist/render/index.d.ts +8 -0
  166. package/dist/render/index.d.ts.map +1 -0
  167. package/dist/render/index.js +8 -0
  168. package/dist/render/index.js.map +1 -0
  169. package/dist/render/jsx-runtime.d.ts +31 -0
  170. package/dist/render/jsx-runtime.d.ts.map +1 -0
  171. package/dist/render/jsx-runtime.js +13 -0
  172. package/dist/render/jsx-runtime.js.map +1 -0
  173. package/dist/render/mini-react.d.ts +14 -0
  174. package/dist/render/mini-react.d.ts.map +1 -0
  175. package/dist/render/mini-react.js +16 -0
  176. package/dist/render/mini-react.js.map +1 -0
  177. package/dist/render/render-jsx.d.ts +24 -0
  178. package/dist/render/render-jsx.d.ts.map +1 -0
  179. package/dist/render/render-jsx.js +51 -0
  180. package/dist/render/render-jsx.js.map +1 -0
  181. package/dist/render/renderer.d.ts +16 -0
  182. package/dist/render/renderer.d.ts.map +1 -0
  183. package/dist/render/renderer.js +437 -0
  184. package/dist/render/renderer.js.map +1 -0
  185. package/dist/render/tailwind.d.ts +20 -0
  186. package/dist/render/tailwind.d.ts.map +1 -0
  187. package/dist/render/tailwind.js +115 -0
  188. package/dist/render/tailwind.js.map +1 -0
  189. package/dist/render/tree.d.ts +72 -0
  190. package/dist/render/tree.d.ts.map +1 -0
  191. package/dist/render/tree.js +63 -0
  192. package/dist/render/tree.js.map +1 -0
  193. package/dist/render-image.d.ts +19 -0
  194. package/dist/render-image.d.ts.map +1 -0
  195. package/dist/render-image.js +84 -0
  196. package/dist/render-image.js.map +1 -0
  197. package/dist/renderer/effects.d.ts +9 -0
  198. package/dist/renderer/effects.d.ts.map +1 -0
  199. package/dist/renderer/effects.js +44 -0
  200. package/dist/renderer/effects.js.map +1 -0
  201. package/dist/renderer/fills.d.ts +9 -0
  202. package/dist/renderer/fills.d.ts.map +1 -0
  203. package/dist/renderer/fills.js +189 -0
  204. package/dist/renderer/fills.js.map +1 -0
  205. package/dist/renderer/index.d.ts +2 -0
  206. package/dist/renderer/index.d.ts.map +1 -0
  207. package/dist/renderer/index.js +2 -0
  208. package/dist/renderer/index.js.map +1 -0
  209. package/dist/renderer/label-cache.d.ts +43 -0
  210. package/dist/renderer/label-cache.d.ts.map +1 -0
  211. package/dist/renderer/label-cache.js +85 -0
  212. package/dist/renderer/label-cache.js.map +1 -0
  213. package/dist/renderer/labels.d.ts +6 -0
  214. package/dist/renderer/labels.d.ts.map +1 -0
  215. package/dist/renderer/labels.js +126 -0
  216. package/dist/renderer/labels.js.map +1 -0
  217. package/dist/renderer/lru-cache.d.ts +20 -0
  218. package/dist/renderer/lru-cache.d.ts.map +1 -0
  219. package/dist/renderer/lru-cache.js +65 -0
  220. package/dist/renderer/lru-cache.js.map +1 -0
  221. package/dist/renderer/overlays.d.ts +25 -0
  222. package/dist/renderer/overlays.d.ts.map +1 -0
  223. package/dist/renderer/overlays.js +783 -0
  224. package/dist/renderer/overlays.js.map +1 -0
  225. package/dist/renderer/renderer.d.ts +229 -0
  226. package/dist/renderer/renderer.d.ts.map +1 -0
  227. package/dist/renderer/renderer.js +909 -0
  228. package/dist/renderer/renderer.js.map +1 -0
  229. package/dist/renderer/rulers.d.ts +8 -0
  230. package/dist/renderer/rulers.d.ts.map +1 -0
  231. package/dist/renderer/rulers.js +147 -0
  232. package/dist/renderer/rulers.js.map +1 -0
  233. package/dist/renderer/scene.d.ts +11 -0
  234. package/dist/renderer/scene.d.ts.map +1 -0
  235. package/dist/renderer/scene.js +392 -0
  236. package/dist/renderer/scene.js.map +1 -0
  237. package/dist/renderer/shapes.d.ts +13 -0
  238. package/dist/renderer/shapes.d.ts.map +1 -0
  239. package/dist/renderer/shapes.js +160 -0
  240. package/dist/renderer/shapes.js.map +1 -0
  241. package/dist/renderer/strokes.d.ts +9 -0
  242. package/dist/renderer/strokes.d.ts.map +1 -0
  243. package/dist/renderer/strokes.js +180 -0
  244. package/dist/renderer/strokes.js.map +1 -0
  245. package/dist/rpc/commands.d.ts +202 -0
  246. package/dist/rpc/commands.d.ts.map +1 -0
  247. package/dist/rpc/commands.js +429 -0
  248. package/dist/rpc/commands.js.map +1 -0
  249. package/dist/rpc/index.d.ts +3 -0
  250. package/dist/rpc/index.d.ts.map +1 -0
  251. package/dist/rpc/index.js +2 -0
  252. package/dist/rpc/index.js.map +1 -0
  253. package/dist/scene-graph.d.ts +318 -0
  254. package/dist/scene-graph.d.ts.map +1 -0
  255. package/dist/scene-graph.js +803 -0
  256. package/dist/scene-graph.js.map +1 -0
  257. package/dist/snap.d.ts +16 -0
  258. package/dist/snap.d.ts.map +1 -0
  259. package/dist/snap.js +97 -0
  260. package/dist/snap.js.map +1 -0
  261. package/dist/style-runs.d.ts +20 -0
  262. package/dist/style-runs.d.ts.map +1 -0
  263. package/dist/style-runs.js +168 -0
  264. package/dist/style-runs.js.map +1 -0
  265. package/dist/svg-export/defs.d.ts +19 -0
  266. package/dist/svg-export/defs.d.ts.map +1 -0
  267. package/dist/svg-export/defs.js +191 -0
  268. package/dist/svg-export/defs.js.map +1 -0
  269. package/dist/svg-export/index.d.ts +8 -0
  270. package/dist/svg-export/index.d.ts.map +1 -0
  271. package/dist/svg-export/index.js +318 -0
  272. package/dist/svg-export/index.js.map +1 -0
  273. package/dist/svg-export/paths.d.ts +9 -0
  274. package/dist/svg-export/paths.d.ts.map +1 -0
  275. package/dist/svg-export/paths.js +189 -0
  276. package/dist/svg-export/paths.js.map +1 -0
  277. package/dist/svg-node.d.ts +8 -0
  278. package/dist/svg-node.d.ts.map +1 -0
  279. package/dist/svg-node.js +48 -0
  280. package/dist/svg-node.js.map +1 -0
  281. package/dist/text-editor.d.ts +57 -0
  282. package/dist/text-editor.d.ts.map +1 -0
  283. package/dist/text-editor.js +337 -0
  284. package/dist/text-editor.js.map +1 -0
  285. package/dist/tools/ai-adapter.d.ts +22 -0
  286. package/dist/tools/ai-adapter.d.ts.map +1 -0
  287. package/dist/tools/ai-adapter.js +121 -0
  288. package/dist/tools/ai-adapter.js.map +1 -0
  289. package/dist/tools/analyze.d.ts +22 -0
  290. package/dist/tools/analyze.d.ts.map +1 -0
  291. package/dist/tools/analyze.js +677 -0
  292. package/dist/tools/analyze.js.map +1 -0
  293. package/dist/tools/create.d.ts +8 -0
  294. package/dist/tools/create.d.ts.map +1 -0
  295. package/dist/tools/create.js +204 -0
  296. package/dist/tools/create.js.map +1 -0
  297. package/dist/tools/describe.d.ts +9 -0
  298. package/dist/tools/describe.d.ts.map +1 -0
  299. package/dist/tools/describe.js +295 -0
  300. package/dist/tools/describe.js.map +1 -0
  301. package/dist/tools/export-code.d.ts +2 -0
  302. package/dist/tools/export-code.d.ts.map +1 -0
  303. package/dist/tools/export-code.js +34 -0
  304. package/dist/tools/export-code.js.map +1 -0
  305. package/dist/tools/export-tailwind-config.d.ts +27 -0
  306. package/dist/tools/export-tailwind-config.d.ts.map +1 -0
  307. package/dist/tools/export-tailwind-config.js +215 -0
  308. package/dist/tools/export-tailwind-config.js.map +1 -0
  309. package/dist/tools/icons.d.ts +5 -0
  310. package/dist/tools/icons.d.ts.map +1 -0
  311. package/dist/tools/icons.js +192 -0
  312. package/dist/tools/icons.js.map +1 -0
  313. package/dist/tools/index.d.ts +7 -0
  314. package/dist/tools/index.d.ts.map +1 -0
  315. package/dist/tools/index.js +6 -0
  316. package/dist/tools/index.js.map +1 -0
  317. package/dist/tools/modify.d.ts +22 -0
  318. package/dist/tools/modify.d.ts.map +1 -0
  319. package/dist/tools/modify.js +653 -0
  320. package/dist/tools/modify.js.map +1 -0
  321. package/dist/tools/patterns.d.ts +2 -0
  322. package/dist/tools/patterns.d.ts.map +1 -0
  323. package/dist/tools/patterns.js +173 -0
  324. package/dist/tools/patterns.js.map +1 -0
  325. package/dist/tools/read.d.ts +17 -0
  326. package/dist/tools/read.d.ts.map +1 -0
  327. package/dist/tools/read.js +379 -0
  328. package/dist/tools/read.js.map +1 -0
  329. package/dist/tools/registry.d.ts +3 -0
  330. package/dist/tools/registry.d.ts.map +1 -0
  331. package/dist/tools/registry.js +124 -0
  332. package/dist/tools/registry.js.map +1 -0
  333. package/dist/tools/schema.d.ts +46 -0
  334. package/dist/tools/schema.d.ts.map +1 -0
  335. package/dist/tools/schema.js +17 -0
  336. package/dist/tools/schema.js.map +1 -0
  337. package/dist/tools/structure.d.ts +18 -0
  338. package/dist/tools/structure.d.ts.map +1 -0
  339. package/dist/tools/structure.js +345 -0
  340. package/dist/tools/structure.js.map +1 -0
  341. package/dist/tools/variables.d.ts +12 -0
  342. package/dist/tools/variables.d.ts.map +1 -0
  343. package/dist/tools/variables.js +190 -0
  344. package/dist/tools/variables.js.map +1 -0
  345. package/dist/tools/vector.d.ts +15 -0
  346. package/dist/tools/vector.d.ts.map +1 -0
  347. package/dist/tools/vector.js +312 -0
  348. package/dist/tools/vector.js.map +1 -0
  349. package/dist/types.d.ts +29 -0
  350. package/dist/types.d.ts.map +1 -0
  351. package/dist/types.js +2 -0
  352. package/dist/types.js.map +1 -0
  353. package/dist/undo.d.ts +33 -0
  354. package/dist/undo.d.ts.map +1 -0
  355. package/dist/undo.js +98 -0
  356. package/dist/undo.js.map +1 -0
  357. package/dist/vector.d.ts +14 -0
  358. package/dist/vector.d.ts.map +1 -0
  359. package/dist/vector.js +334 -0
  360. package/dist/vector.js.map +1 -0
  361. package/dist/xpath.d.ts +8 -0
  362. package/dist/xpath.d.ts.map +1 -0
  363. package/dist/xpath.js +199 -0
  364. package/dist/xpath.js.map +1 -0
  365. package/package.json +54 -0
  366. package/src/canvaskit.ts +66 -0
  367. package/src/clipboard.ts +444 -0
  368. package/src/color.ts +83 -0
  369. package/src/constants.ts +277 -0
  370. package/src/copy.ts +75 -0
  371. package/src/fig-export-worker.ts +28 -0
  372. package/src/fig-export.ts +321 -0
  373. package/src/figma-api.ts +1297 -0
  374. package/src/figma-rest-import.ts +443 -0
  375. package/src/fonts.ts +369 -0
  376. package/src/geometry.ts +73 -0
  377. package/src/global.d.ts +20 -0
  378. package/src/index.ts +247 -0
  379. package/src/kiwi/codec.ts +614 -0
  380. package/src/kiwi/fig-file.ts +248 -0
  381. package/src/kiwi/fig-import.ts +300 -0
  382. package/src/kiwi/fig-parse-worker.ts +213 -0
  383. package/src/kiwi/instance-overrides.ts +682 -0
  384. package/src/kiwi/kiwi-convert.ts +771 -0
  385. package/src/kiwi/kiwi-schema/bb.ts +244 -0
  386. package/src/kiwi/kiwi-schema/binary.ts +102 -0
  387. package/src/kiwi/kiwi-schema/index.ts +5 -0
  388. package/src/kiwi/kiwi-schema/js.ts +339 -0
  389. package/src/kiwi/kiwi-schema/parser.ts +287 -0
  390. package/src/kiwi/kiwi-schema/schema.ts +24 -0
  391. package/src/kiwi/kiwi-schema/util.ts +10 -0
  392. package/src/kiwi/protocol.ts +237 -0
  393. package/src/kiwi/schema.ts +2286 -0
  394. package/src/kiwi-serialize.ts +467 -0
  395. package/src/layout.ts +608 -0
  396. package/src/profiler/draw-call-counter.ts +43 -0
  397. package/src/profiler/frame-capture.ts +139 -0
  398. package/src/profiler/frame-stats.ts +122 -0
  399. package/src/profiler/gpu-timer.ts +93 -0
  400. package/src/profiler/hud-renderer.ts +242 -0
  401. package/src/profiler/index.ts +8 -0
  402. package/src/profiler/phase-timer.ts +62 -0
  403. package/src/profiler/render-profiler.ts +163 -0
  404. package/src/render/components.ts +69 -0
  405. package/src/render/emoji-icons.ts +60 -0
  406. package/src/render/export-code.ts +366 -0
  407. package/src/render/export-jsx.ts +633 -0
  408. package/src/render/index.ts +38 -0
  409. package/src/render/jsx-runtime.ts +36 -0
  410. package/src/render/mini-react.ts +30 -0
  411. package/src/render/render-jsx.ts +74 -0
  412. package/src/render/renderer.ts +508 -0
  413. package/src/render/tailwind.ts +114 -0
  414. package/src/render/tree.ts +137 -0
  415. package/src/render-image.ts +139 -0
  416. package/src/renderer/effects.ts +64 -0
  417. package/src/renderer/fills.ts +248 -0
  418. package/src/renderer/index.ts +1 -0
  419. package/src/renderer/label-cache.ts +114 -0
  420. package/src/renderer/labels.ts +168 -0
  421. package/src/renderer/lru-cache.ts +71 -0
  422. package/src/renderer/overlays.ts +1089 -0
  423. package/src/renderer/renderer.ts +1226 -0
  424. package/src/renderer/rulers.ts +230 -0
  425. package/src/renderer/scene.ts +554 -0
  426. package/src/renderer/shapes.ts +193 -0
  427. package/src/renderer/strokes.ts +221 -0
  428. package/src/rpc/commands.ts +667 -0
  429. package/src/rpc/index.ts +25 -0
  430. package/src/scene-graph.ts +1254 -0
  431. package/src/snap.ts +122 -0
  432. package/src/style-runs.ts +234 -0
  433. package/src/svg-export/defs.ts +255 -0
  434. package/src/svg-export/index.ts +427 -0
  435. package/src/svg-export/paths.ts +212 -0
  436. package/src/svg-node.ts +62 -0
  437. package/src/text-editor.ts +349 -0
  438. package/src/tools/ai-adapter.ts +144 -0
  439. package/src/tools/analyze.ts +786 -0
  440. package/src/tools/create.ts +206 -0
  441. package/src/tools/describe.ts +280 -0
  442. package/src/tools/export-code.ts +41 -0
  443. package/src/tools/export-tailwind-config.ts +266 -0
  444. package/src/tools/icons.ts +213 -0
  445. package/src/tools/index.ts +6 -0
  446. package/src/tools/modify.ts +651 -0
  447. package/src/tools/patterns.ts +189 -0
  448. package/src/tools/read.ts +401 -0
  449. package/src/tools/registry.ts +155 -0
  450. package/src/tools/schema.ts +65 -0
  451. package/src/tools/structure.ts +348 -0
  452. package/src/tools/variables.ts +193 -0
  453. package/src/tools/vector.ts +311 -0
  454. package/src/types.ts +32 -0
  455. package/src/undo.ts +126 -0
  456. package/src/vector.ts +413 -0
  457. package/src/xpath.ts +259 -0
@@ -0,0 +1,633 @@
1
+ import { colorToHex8, colorToCSSCompact } from '../color'
2
+ import { DEFAULT_FONT_FAMILY } from '../constants'
3
+ import {
4
+ pxToSpacing,
5
+ colorToTwClass,
6
+ fontSizeToTw,
7
+ fontWeightToTw,
8
+ borderRadiusToTw,
9
+ opacityToTw
10
+ } from './tailwind'
11
+
12
+ import type {
13
+ SceneGraph,
14
+ SceneNode,
15
+ Fill,
16
+ Stroke,
17
+ Effect,
18
+ NodeType,
19
+ Color,
20
+ GridTrack
21
+ } from '../scene-graph'
22
+
23
+ export type JSXFormat = 'lutris' | 'tailwind'
24
+
25
+ const NODE_TYPE_TO_TAG: Partial<Record<NodeType, string>> = {
26
+ FRAME: 'Frame',
27
+ RECTANGLE: 'Rectangle',
28
+ ROUNDED_RECTANGLE: 'Rectangle',
29
+ ELLIPSE: 'Ellipse',
30
+ TEXT: 'Text',
31
+ LINE: 'Line',
32
+ STAR: 'Star',
33
+ POLYGON: 'Polygon',
34
+ VECTOR: 'Vector',
35
+ GROUP: 'Group',
36
+ SECTION: 'Section',
37
+ COMPONENT: 'Component',
38
+ COMPONENT_SET: 'Frame',
39
+ INSTANCE: 'Frame'
40
+ }
41
+
42
+ const NODE_TYPE_TO_TW_TAG: Partial<Record<NodeType, string>> = {
43
+ FRAME: 'div',
44
+ RECTANGLE: 'div',
45
+ ROUNDED_RECTANGLE: 'div',
46
+ ELLIPSE: 'div',
47
+ TEXT: 'p',
48
+ LINE: 'div',
49
+ STAR: 'div',
50
+ POLYGON: 'div',
51
+ VECTOR: 'div',
52
+ GROUP: 'div',
53
+ SECTION: 'section',
54
+ COMPONENT: 'div',
55
+ COMPONENT_SET: 'div',
56
+ INSTANCE: 'div'
57
+ }
58
+
59
+ function formatColor(color: Color, opacity = 1): string {
60
+ return colorToHex8(color, opacity)
61
+ }
62
+
63
+ function solidFillColor(fills: Fill[]): string | null {
64
+ const visible = fills.filter((f) => f.visible && f.type === 'SOLID')
65
+ if (visible.length !== 1) return null
66
+ return formatColor(visible[0].color, visible[0].opacity)
67
+ }
68
+
69
+ function solidStroke(strokes: Stroke[]): { color: string; weight: number } | null {
70
+ const visible = strokes.filter((s) => s.visible)
71
+ if (visible.length !== 1) return null
72
+ return {
73
+ color: formatColor(visible[0].color, visible[0].opacity),
74
+ weight: visible[0].weight
75
+ }
76
+ }
77
+
78
+ function formatShadow(e: Effect): string | null {
79
+ if (e.type !== 'DROP_SHADOW' && e.type !== 'INNER_SHADOW') return null
80
+ return `${e.offset.x} ${e.offset.y} ${e.radius} ${formatColor(e.color, e.color.a)}`
81
+ }
82
+
83
+ function formatTailwindShadow(e: Effect): string | null {
84
+ if (e.type !== 'DROP_SHADOW' && e.type !== 'INNER_SHADOW') return null
85
+ const color = colorToCSSCompact(e.color)
86
+ const inset = e.type === 'INNER_SHADOW' ? 'inset_' : ''
87
+ const spread = e.spread !== 0 ? `_${e.spread}px` : ''
88
+ return `${inset}${e.offset.x}px_${e.offset.y}px_${e.radius}px${spread}_${color}`
89
+ }
90
+
91
+ function formatTailwindAngle(degrees: number): string {
92
+ const rounded = Number(degrees.toFixed(2))
93
+ const integer = Math.round(rounded)
94
+ const named = new Set([0, 1, 2, 3, 6, 12, 45, 90, 180])
95
+ if (rounded === integer && named.has(integer)) return String(integer)
96
+ return `[${rounded}deg]`
97
+ }
98
+
99
+ function formatTailwindFontFamily(fontFamily: string): string {
100
+ const escaped = fontFamily.replace(/\\/g, '\\\\').replace(/'/g, "\\'")
101
+ return `['${escaped}']`
102
+ }
103
+
104
+ const JSX_ENTITY: Record<string, string> = {
105
+ '{': '&#123;',
106
+ '}': '&#125;',
107
+ '<': '&lt;',
108
+ '>': '&gt;',
109
+ '&': '&amp;'
110
+ }
111
+
112
+ function escapeJSXText(text: string): string {
113
+ return text.replace(/[{}<>&]/g, (c) => JSX_ENTITY[c])
114
+ }
115
+
116
+ function formatProp(key: string, value: unknown): string {
117
+ if (typeof value === 'string') return `${key}="${value}"`
118
+ if (typeof value === 'number') return `${key}={${value}}`
119
+ if (typeof value === 'boolean') return value ? key : `${key}={false}`
120
+ return `${key}={${JSON.stringify(value)}}`
121
+ }
122
+
123
+ function getNodeContext(node: SceneNode, graph: SceneGraph) {
124
+ const parent = node.parentId ? graph.getNode(node.parentId) : null
125
+ return {
126
+ isAutoLayout: node.layoutMode !== 'NONE',
127
+ isGrid: node.layoutMode === 'GRID',
128
+ isFlex: node.layoutMode === 'HORIZONTAL' || node.layoutMode === 'VERTICAL',
129
+ parentIsAutoLayout: parent ? parent.layoutMode !== 'NONE' : false,
130
+ parentIsGrid: parent ? parent.layoutMode === 'GRID' : false
131
+ }
132
+ }
133
+
134
+ type PaddingEdges = { pt: number; pr: number; pb: number; pl: number }
135
+
136
+ function collectPadding(node: SceneNode): PaddingEdges | null {
137
+ const { paddingTop: pt, paddingRight: pr, paddingBottom: pb, paddingLeft: pl } = node
138
+ if (pt === 0 && pr === 0 && pb === 0 && pl === 0) return null
139
+ return { pt, pr, pb, pl }
140
+ }
141
+
142
+ function emitPadding<T>(
143
+ edges: PaddingEdges,
144
+ uniform: (v: number) => T,
145
+ symmetric: (y: number, x: number) => T[],
146
+ individual: (edges: PaddingEdges) => T[]
147
+ ): T[] {
148
+ const { pt, pr, pb, pl } = edges
149
+ if (pt === pr && pr === pb && pb === pl) return [uniform(pt)]
150
+ if (pt === pb && pl === pr) return symmetric(pt, pl)
151
+ return individual(edges)
152
+ }
153
+
154
+ interface CornerRadii {
155
+ tl: number
156
+ tr: number
157
+ br: number
158
+ bl: number
159
+ }
160
+
161
+ function collectCornerRadii(node: SceneNode): CornerRadii | null {
162
+ if (node.cornerRadius <= 0) return null
163
+ if (node.independentCorners) {
164
+ return {
165
+ tl: node.topLeftRadius,
166
+ tr: node.topRightRadius,
167
+ br: node.bottomRightRadius,
168
+ bl: node.bottomLeftRadius
169
+ }
170
+ }
171
+ const r = node.cornerRadius
172
+ return { tl: r, tr: r, br: r, bl: r }
173
+ }
174
+
175
+ function formatTrack(t: GridTrack): string {
176
+ if (t.sizing === 'FR') return `${t.value}fr`
177
+ if (t.sizing === 'FIXED') return `${t.value}px`
178
+ return 'auto'
179
+ }
180
+
181
+ function formatTracks(tracks: GridTrack[]): string {
182
+ return tracks.map(formatTrack).join(' ')
183
+ }
184
+
185
+ // --- Lutris format helpers ---
186
+
187
+ function collectGridSizingProps(node: SceneNode, props: [string, unknown][]): void {
188
+ props.push(['grid', true])
189
+ if (node.gridTemplateColumns.length > 0)
190
+ props.push(['columns', formatTracks(node.gridTemplateColumns)])
191
+ if (node.gridTemplateRows.length > 0)
192
+ props.push(['rows', formatTracks(node.gridTemplateRows)])
193
+ if (node.width > 0) props.push(['w', node.width])
194
+ if (node.gridTemplateRows.length > 0 && node.height > 0) props.push(['h', node.height])
195
+ if (node.gridColumnGap > 0) props.push(['columnGap', node.gridColumnGap])
196
+ if (node.gridRowGap > 0) props.push(['rowGap', node.gridRowGap])
197
+ }
198
+
199
+ function collectFlexSizingProps(node: SceneNode, props: [string, unknown][]): void {
200
+ props.push(['flex', node.layoutMode === 'HORIZONTAL' ? 'row' : 'col'])
201
+ const primaryAxis = node.layoutMode === 'HORIZONTAL' ? 'width' : 'height'
202
+ const crossAxis = node.layoutMode === 'HORIZONTAL' ? 'height' : 'width'
203
+
204
+ if (node.primaryAxisSizing === 'FILL')
205
+ props.push([primaryAxis === 'width' ? 'w' : 'h', 'fill'])
206
+ else if (node.primaryAxisSizing !== 'HUG')
207
+ props.push([primaryAxis === 'width' ? 'w' : 'h', node[primaryAxis]])
208
+
209
+ if (node.counterAxisSizing === 'FILL')
210
+ props.push([crossAxis === 'width' ? 'w' : 'h', 'fill'])
211
+ else if (node.counterAxisSizing !== 'HUG')
212
+ props.push([crossAxis === 'width' ? 'w' : 'h', node[crossAxis]])
213
+ }
214
+
215
+ function collectGridPositionProps(node: SceneNode, props: [string, unknown][]): void {
216
+ if (!node.gridPosition) return
217
+ const pos = node.gridPosition
218
+ if (pos.column > 0) props.push(['colStart', pos.column])
219
+ if (pos.row > 0) props.push(['rowStart', pos.row])
220
+ if (pos.columnSpan > 1) props.push(['colSpan', pos.columnSpan])
221
+ if (pos.rowSpan > 1) props.push(['rowSpan', pos.rowSpan])
222
+ }
223
+
224
+ function collectFlexAlignmentProps(node: SceneNode, props: [string, unknown][]): void {
225
+ if (node.itemSpacing > 0) props.push(['gap', node.itemSpacing])
226
+
227
+ if (node.layoutWrap === 'WRAP') {
228
+ props.push(['wrap', true])
229
+ if (node.counterAxisSpacing > 0) props.push(['rowGap', node.counterAxisSpacing])
230
+ }
231
+
232
+ if (node.primaryAxisAlign === 'CENTER') props.push(['justify', 'center'])
233
+ else if (node.primaryAxisAlign === 'MAX') props.push(['justify', 'end'])
234
+ else if (node.primaryAxisAlign === 'SPACE_BETWEEN') props.push(['justify', 'between'])
235
+
236
+ if (node.counterAxisAlign === 'CENTER') props.push(['items', 'center'])
237
+ else if (node.counterAxisAlign === 'MAX') props.push(['items', 'end'])
238
+ else if (node.counterAxisAlign === 'STRETCH') props.push(['items', 'stretch'])
239
+ }
240
+
241
+ function collectAutoLayoutPaddingProps(node: SceneNode, props: [string, unknown][]): void {
242
+ const pad = collectPadding(node)
243
+ if (!pad) return
244
+ props.push(
245
+ ...emitPadding(
246
+ pad,
247
+ (v) => ['p', v] as [string, unknown],
248
+ (y, x) => [['py', y], ['px', x]] as [string, unknown][],
249
+ ({ pt, pr, pb, pl }) => {
250
+ const r: [string, unknown][] = []
251
+ if (pt > 0) r.push(['pt', pt])
252
+ if (pr > 0) r.push(['pr', pr])
253
+ if (pb > 0) r.push(['pb', pb])
254
+ if (pl > 0) r.push(['pl', pl])
255
+ return r
256
+ }
257
+ )
258
+ )
259
+ }
260
+
261
+ function collectCornerRadiiProps(node: SceneNode, props: [string, unknown][]): void {
262
+ const corners = collectCornerRadii(node)
263
+ if (!corners) return
264
+ const { tl, tr, br, bl } = corners
265
+ if (tl === tr && tr === br && br === bl) {
266
+ props.push(['rounded', tl])
267
+ } else {
268
+ if (tl > 0) props.push(['roundedTL', tl])
269
+ if (tr > 0) props.push(['roundedTR', tr])
270
+ if (br > 0) props.push(['roundedBR', br])
271
+ if (bl > 0) props.push(['roundedBL', bl])
272
+ }
273
+ }
274
+
275
+ function collectAppearanceProps(node: SceneNode, props: [string, unknown][]): void {
276
+ const bg = solidFillColor(node.fills)
277
+ if (bg) props.push(['bg', bg])
278
+
279
+ const stroke = solidStroke(node.strokes)
280
+ if (stroke) {
281
+ props.push(['stroke', stroke.color])
282
+ if (stroke.weight !== 1) props.push(['strokeWidth', stroke.weight])
283
+ }
284
+
285
+ collectCornerRadiiProps(node, props)
286
+
287
+ if (node.cornerSmoothing > 0) props.push(['cornerSmoothing', node.cornerSmoothing])
288
+ if (node.opacity < 1) props.push(['opacity', Math.round(node.opacity * 100) / 100])
289
+ if (node.rotation !== 0) props.push(['rotate', Math.round(node.rotation * 100) / 100])
290
+ if (node.blendMode !== 'PASS_THROUGH' && node.blendMode !== 'NORMAL') {
291
+ props.push(['blendMode', node.blendMode.toLowerCase()])
292
+ }
293
+ if (node.clipsContent) props.push(['overflow', 'hidden'])
294
+
295
+ for (const effect of node.effects) {
296
+ if (!effect.visible) continue
297
+ if (effect.type === 'DROP_SHADOW' || effect.type === 'INNER_SHADOW') {
298
+ const shadow = formatShadow(effect)
299
+ if (shadow) props.push(['shadow', shadow])
300
+ } else if (effect.type === 'LAYER_BLUR' || effect.type === 'BACKGROUND_BLUR') {
301
+ props.push(['blur', effect.radius])
302
+ }
303
+ }
304
+ }
305
+
306
+ function collectPositionProps(
307
+ node: SceneNode,
308
+ ctx: ReturnType<typeof getNodeContext>,
309
+ props: [string, unknown][]
310
+ ): void {
311
+ if (ctx.parentIsAutoLayout || ctx.parentIsGrid) return
312
+ if (node.x !== 0) props.push(['x', node.x])
313
+ if (node.y !== 0) props.push(['y', node.y])
314
+ }
315
+
316
+ function collectSizingProps(
317
+ node: SceneNode,
318
+ ctx: ReturnType<typeof getNodeContext>,
319
+ graph: SceneGraph,
320
+ props: [string, unknown][]
321
+ ): void {
322
+ if (ctx.isGrid) collectGridSizingProps(node, props)
323
+ else if (ctx.isFlex) collectFlexSizingProps(node, props)
324
+ else if (node.type === 'TEXT') collectTextSizingProps(node, props)
325
+ else {
326
+ if (node.width > 0) props.push(['w', node.width])
327
+ if (node.height > 0) props.push(['h', node.height])
328
+ }
329
+
330
+ if (!ctx.parentIsAutoLayout) return
331
+ if (node.layoutGrow > 0) props.push(['grow', node.layoutGrow])
332
+ if (node.layoutAlignSelf === 'STRETCH') {
333
+ const parent = node.parentId ? graph.getNode(node.parentId) : null
334
+ if (parent && (parent.layoutMode === 'HORIZONTAL' || parent.layoutMode === 'VERTICAL')) {
335
+ const crossDim = parent.layoutMode === 'HORIZONTAL' ? 'h' : 'w'
336
+ if (!props.some(([k]) => k === crossDim)) props.push([crossDim, 'fill'])
337
+ }
338
+ }
339
+ }
340
+
341
+ function collectTextSizingProps(node: SceneNode, props: [string, unknown][]): void {
342
+ const autoResize = node.textAutoResize
343
+ const emitW = autoResize !== 'WIDTH_AND_HEIGHT'
344
+ const emitH = autoResize === 'NONE' || autoResize === 'TRUNCATE'
345
+ if (emitW && node.width > 0) props.push(['w', node.width])
346
+ if (emitH && node.height > 0) props.push(['h', node.height])
347
+ }
348
+
349
+ function collectTextNodeProps(node: SceneNode, props: [string, unknown][]): void {
350
+ if (node.fontSize !== 14) props.push(['size', node.fontSize])
351
+ if (node.fontFamily && node.fontFamily !== DEFAULT_FONT_FAMILY)
352
+ props.push(['font', node.fontFamily])
353
+ if (node.fontWeight !== 400) {
354
+ if (node.fontWeight === 700) props.push(['weight', 'bold'])
355
+ else if (node.fontWeight === 500) props.push(['weight', 'medium'])
356
+ else props.push(['weight', node.fontWeight])
357
+ }
358
+ if (node.textAlignHorizontal !== 'LEFT') {
359
+ props.push(['textAlign', node.textAlignHorizontal.toLowerCase()])
360
+ }
361
+ const textColor = solidFillColor(node.fills)
362
+ if (textColor) {
363
+ const bgIdx = props.findIndex(([k]) => k === 'bg')
364
+ if (bgIdx !== -1) props.splice(bgIdx, 1)
365
+ props.push(['color', textColor])
366
+ }
367
+ }
368
+
369
+ function collectShapeNodeProps(node: SceneNode, props: [string, unknown][]): void {
370
+ if (node.type === 'STAR') {
371
+ if (node.pointCount !== 5) props.push(['points', node.pointCount])
372
+ if (node.starInnerRadius !== 0.382) props.push(['innerRadius', node.starInnerRadius])
373
+ }
374
+ if (node.type === 'POLYGON' && node.pointCount !== 3) {
375
+ props.push(['points', node.pointCount])
376
+ }
377
+ }
378
+
379
+ function collectProps(node: SceneNode, graph: SceneGraph): [string, unknown][] {
380
+ const props: [string, unknown][] = []
381
+ const ctx = getNodeContext(node, graph)
382
+
383
+ if (node.name && node.name !== node.type) props.push(['name', node.name])
384
+
385
+ collectPositionProps(node, ctx, props)
386
+ collectSizingProps(node, ctx, graph, props)
387
+ if (ctx.parentIsGrid) collectGridPositionProps(node, props)
388
+ if (ctx.isFlex) collectFlexAlignmentProps(node, props)
389
+ if (ctx.isAutoLayout) collectAutoLayoutPaddingProps(node, props)
390
+ collectAppearanceProps(node, props)
391
+ if (node.type === 'TEXT') collectTextNodeProps(node, props)
392
+ collectShapeNodeProps(node, props)
393
+
394
+ return props
395
+ }
396
+
397
+ // --- Tailwind CSS v4 format helpers ---
398
+
399
+ function twRounded(prefix: string, px: number): string {
400
+ const r = borderRadiusToTw(px)
401
+ return r ? `${prefix}-${r}` : prefix
402
+ }
403
+
404
+ function gridTemplateTw(tracks: GridTrack[]): string {
405
+ const allEqual1Fr = tracks.every((t) => t.sizing === 'FR' && t.value === 1)
406
+ if (allEqual1Fr) return String(tracks.length)
407
+ return `[${tracks.map(formatTrack).join('_')}]`
408
+ }
409
+
410
+ function collectTwGridClasses(node: SceneNode, classes: string[]): void {
411
+ classes.push('grid')
412
+ if (node.gridTemplateColumns.length > 0)
413
+ classes.push(`grid-cols-${gridTemplateTw(node.gridTemplateColumns)}`)
414
+ if (node.gridTemplateRows.length > 0)
415
+ classes.push(`grid-rows-${gridTemplateTw(node.gridTemplateRows)}`)
416
+ if (node.width > 0) classes.push(`w-${pxToSpacing(node.width)}`)
417
+ if (node.gridTemplateRows.length > 0 && node.height > 0)
418
+ classes.push(`h-${pxToSpacing(node.height)}`)
419
+ if (node.gridColumnGap > 0) classes.push(`gap-x-${pxToSpacing(node.gridColumnGap)}`)
420
+ if (node.gridRowGap > 0) classes.push(`gap-y-${pxToSpacing(node.gridRowGap)}`)
421
+ }
422
+
423
+ function collectTwFlexSizingClasses(node: SceneNode, classes: string[]): void {
424
+ classes.push('flex')
425
+ if (node.layoutMode === 'VERTICAL') classes.push('flex-col')
426
+
427
+ const primaryAxis = node.layoutMode === 'HORIZONTAL' ? 'width' : 'height'
428
+ const crossAxis = node.layoutMode === 'HORIZONTAL' ? 'height' : 'width'
429
+ const wProp = primaryAxis === 'width' ? 'w' : 'h'
430
+ const hProp = crossAxis === 'width' ? 'w' : 'h'
431
+
432
+ if (node.primaryAxisSizing === 'FILL') classes.push(`${wProp}-full`)
433
+ else if (node.primaryAxisSizing !== 'HUG')
434
+ classes.push(`${wProp}-${pxToSpacing(node[primaryAxis])}`)
435
+
436
+ if (node.counterAxisSizing === 'FILL') classes.push(`${hProp}-full`)
437
+ else if (node.counterAxisSizing !== 'HUG')
438
+ classes.push(`${hProp}-${pxToSpacing(node[crossAxis])}`)
439
+ }
440
+
441
+ function collectTwGridPositionClasses(node: SceneNode, classes: string[]): void {
442
+ if (!node.gridPosition) return
443
+ const pos = node.gridPosition
444
+ if (pos.column > 0) classes.push(`col-start-${pos.column}`)
445
+ if (pos.row > 0) classes.push(`row-start-${pos.row}`)
446
+ if (pos.columnSpan > 1) classes.push(`col-span-${pos.columnSpan}`)
447
+ if (pos.rowSpan > 1) classes.push(`row-span-${pos.rowSpan}`)
448
+ }
449
+
450
+ function collectTwFlexAlignmentClasses(node: SceneNode, classes: string[]): void {
451
+ if (node.itemSpacing > 0) classes.push(`gap-${pxToSpacing(node.itemSpacing)}`)
452
+
453
+ if (node.layoutWrap === 'WRAP') {
454
+ classes.push('flex-wrap')
455
+ if (node.counterAxisSpacing > 0) classes.push(`gap-y-${pxToSpacing(node.counterAxisSpacing)}`)
456
+ }
457
+
458
+ if (node.primaryAxisAlign === 'CENTER') classes.push('justify-center')
459
+ else if (node.primaryAxisAlign === 'MAX') classes.push('justify-end')
460
+ else if (node.primaryAxisAlign === 'SPACE_BETWEEN') classes.push('justify-between')
461
+
462
+ if (node.counterAxisAlign === 'CENTER') classes.push('items-center')
463
+ else if (node.counterAxisAlign === 'MAX') classes.push('items-end')
464
+ else if (node.counterAxisAlign === 'STRETCH') classes.push('items-stretch')
465
+ }
466
+
467
+ function collectTwPaddingClasses(node: SceneNode, classes: string[]): void {
468
+ const pad = collectPadding(node)
469
+ if (!pad) return
470
+ classes.push(
471
+ ...emitPadding(
472
+ pad,
473
+ (v) => `p-${pxToSpacing(v)}`,
474
+ (y, x) => [`py-${pxToSpacing(y)}`, `px-${pxToSpacing(x)}`],
475
+ ({ pt, pr, pb, pl }) => {
476
+ const r: string[] = []
477
+ if (pt > 0) r.push(`pt-${pxToSpacing(pt)}`)
478
+ if (pr > 0) r.push(`pr-${pxToSpacing(pr)}`)
479
+ if (pb > 0) r.push(`pb-${pxToSpacing(pb)}`)
480
+ if (pl > 0) r.push(`pl-${pxToSpacing(pl)}`)
481
+ return r
482
+ }
483
+ )
484
+ )
485
+ }
486
+
487
+ function collectTwCornerRadiiClasses(node: SceneNode, classes: string[]): void {
488
+ const corners = collectCornerRadii(node)
489
+ if (!corners) return
490
+ const { tl, tr, br, bl } = corners
491
+ if (tl === tr && tr === br && br === bl) {
492
+ classes.push(twRounded('rounded', tl))
493
+ } else {
494
+ if (tl > 0) classes.push(twRounded('rounded-tl', tl))
495
+ if (tr > 0) classes.push(twRounded('rounded-tr', tr))
496
+ if (br > 0) classes.push(twRounded('rounded-br', br))
497
+ if (bl > 0) classes.push(twRounded('rounded-bl', bl))
498
+ }
499
+ }
500
+
501
+ function collectTwAppearanceClasses(node: SceneNode, classes: string[]): void {
502
+ const bg = solidFillColor(node.fills)
503
+ if (bg && node.type !== 'TEXT') classes.push(`bg-${colorToTwClass(bg)}`)
504
+
505
+ const stroke = solidStroke(node.strokes)
506
+ if (stroke) {
507
+ if (stroke.weight !== 1) classes.push(`border-${pxToSpacing(stroke.weight)}`)
508
+ else classes.push('border')
509
+ classes.push(`border-${colorToTwClass(stroke.color)}`)
510
+ }
511
+
512
+ collectTwCornerRadiiClasses(node, classes)
513
+
514
+ if (node.opacity < 1) classes.push(`opacity-${opacityToTw(node.opacity)}`)
515
+ if (node.rotation !== 0) classes.push(`rotate-${formatTailwindAngle(node.rotation)}`)
516
+ if (node.clipsContent) classes.push('overflow-hidden')
517
+
518
+ for (const effect of node.effects) {
519
+ if (!effect.visible) continue
520
+ if (effect.type === 'DROP_SHADOW' || effect.type === 'INNER_SHADOW') {
521
+ const shadow = formatTailwindShadow(effect)
522
+ if (shadow) classes.push(`shadow-[${shadow}]`)
523
+ } else if (effect.type === 'LAYER_BLUR' || effect.type === 'FOREGROUND_BLUR') {
524
+ classes.push(`blur-[${effect.radius}px]`)
525
+ } else {
526
+ classes.push(`backdrop-blur-[${effect.radius}px]`)
527
+ }
528
+ }
529
+ }
530
+
531
+ function collectTwTextClasses(node: SceneNode, classes: string[]): void {
532
+ classes.push(`text-${fontSizeToTw(node.fontSize)}`)
533
+ if (node.fontFamily && node.fontFamily !== DEFAULT_FONT_FAMILY) {
534
+ classes.push(`font-${formatTailwindFontFamily(node.fontFamily)}`)
535
+ }
536
+ if (node.fontWeight !== 400) classes.push(`font-${fontWeightToTw(node.fontWeight)}`)
537
+ if (node.textAlignHorizontal !== 'LEFT') {
538
+ classes.push(`text-${node.textAlignHorizontal.toLowerCase()}`)
539
+ }
540
+ const textColor = solidFillColor(node.fills)
541
+ if (textColor) classes.push(`text-${colorToTwClass(textColor)}`)
542
+ }
543
+
544
+ function collectTailwindClasses(node: SceneNode, graph: SceneGraph): string[] {
545
+ const classes: string[] = []
546
+ const ctx = getNodeContext(node, graph)
547
+
548
+ if (ctx.isGrid) collectTwGridClasses(node, classes)
549
+ else if (ctx.isFlex) collectTwFlexSizingClasses(node, classes)
550
+ else {
551
+ if (node.width > 0) classes.push(`w-${pxToSpacing(node.width)}`)
552
+ if (node.height > 0) classes.push(`h-${pxToSpacing(node.height)}`)
553
+ }
554
+
555
+ if (ctx.parentIsAutoLayout && node.layoutGrow > 0) classes.push('grow')
556
+ if (ctx.parentIsGrid) collectTwGridPositionClasses(node, classes)
557
+ if (ctx.isFlex) collectTwFlexAlignmentClasses(node, classes)
558
+ if (ctx.isAutoLayout) collectTwPaddingClasses(node, classes)
559
+ collectTwAppearanceClasses(node, classes)
560
+ if (node.type === 'TEXT') collectTwTextClasses(node, classes)
561
+
562
+ return classes
563
+ }
564
+
565
+ // --- JSX rendering ---
566
+
567
+ function nodeToJSX(node: SceneNode, graph: SceneGraph, indent: number, format: JSXFormat): string {
568
+ const tagMap = format === 'tailwind' ? NODE_TYPE_TO_TW_TAG : NODE_TYPE_TO_TAG
569
+ const tag = tagMap[node.type]
570
+ if (!tag) return ''
571
+
572
+ const prefix = ' '.repeat(indent)
573
+ let attrsStr: string
574
+
575
+ if (format === 'tailwind') {
576
+ const classes = collectTailwindClasses(node, graph)
577
+ const nameAttr = node.name && node.name !== node.type ? ` data-name="${node.name}"` : ''
578
+ const classAttr = classes.length > 0 ? ` className="${classes.join(' ')}"` : ''
579
+ attrsStr = `${nameAttr}${classAttr}`.trim()
580
+ } else {
581
+ const props = collectProps(node, graph)
582
+ attrsStr = props.map(([k, v]) => formatProp(k, v)).join(' ')
583
+ }
584
+
585
+ const opening = attrsStr ? `<${tag} ${attrsStr}` : `<${tag}`
586
+ const children = graph.getChildren(node.id)
587
+
588
+ if (node.type === 'TEXT') {
589
+ const text = node.text
590
+ if (!text) return `${prefix}${opening} />`
591
+ const escaped = escapeJSXText(text)
592
+ if (!escaped.includes('\n')) {
593
+ return `${prefix}${opening}>${escaped}</${tag}>`
594
+ }
595
+ return [
596
+ `${prefix}${opening}>`,
597
+ ...escaped.split('\n').map((l) => `${prefix} ${l}`),
598
+ `${prefix}</${tag}>`
599
+ ].join('\n')
600
+ }
601
+
602
+ if (children.length === 0) return `${prefix}${opening} />`
603
+
604
+ const childJSX = children
605
+ .filter((c) => c.visible)
606
+ .map((c) => nodeToJSX(c, graph, indent + 1, format))
607
+ .filter(Boolean)
608
+
609
+ if (childJSX.length === 0) return `${prefix}${opening} />`
610
+
611
+ return [`${prefix}${opening}>`, ...childJSX, `${prefix}</${tag}>`].join('\n')
612
+ }
613
+
614
+ export function sceneNodeToJSX(
615
+ nodeId: string,
616
+ graph: SceneGraph,
617
+ format: JSXFormat = 'lutris'
618
+ ): string {
619
+ const node = graph.getNode(nodeId)
620
+ if (!node) return ''
621
+ return nodeToJSX(node, graph, 0, format)
622
+ }
623
+
624
+ export function selectionToJSX(
625
+ nodeIds: string[],
626
+ graph: SceneGraph,
627
+ format: JSXFormat = 'lutris'
628
+ ): string {
629
+ return nodeIds
630
+ .map((id) => sceneNodeToJSX(id, graph, format))
631
+ .filter(Boolean)
632
+ .join('\n\n')
633
+ }
@@ -0,0 +1,38 @@
1
+ export {
2
+ Frame,
3
+ Text,
4
+ Rectangle,
5
+ Ellipse,
6
+ Line,
7
+ Star,
8
+ Polygon,
9
+ Vector,
10
+ Group,
11
+ Section,
12
+ View,
13
+ Rect,
14
+ Component,
15
+ Instance,
16
+ Page,
17
+ INTRINSIC_ELEMENTS
18
+ } from './components'
19
+
20
+ export {
21
+ type TreeNode,
22
+ type BaseProps,
23
+ type TextProps,
24
+ type StyleProps,
25
+ isTreeNode,
26
+ node,
27
+ resolveToTree
28
+ } from './tree'
29
+
30
+ export { renderTree, type RenderResult } from './renderer'
31
+
32
+ export { createElement } from './mini-react'
33
+
34
+ export { renderJSX, renderTreeNode, buildComponent } from './render-jsx'
35
+
36
+ export { sceneNodeToJSX, selectionToJSX, type JSXFormat } from './export-jsx'
37
+
38
+ export { selectionToCode, type CodeFormat } from './export-code'
@@ -0,0 +1,36 @@
1
+ import { node, type BaseProps, type TreeNode, type TextProps } from './tree'
2
+
3
+ export function jsx(type: string | ((props: BaseProps) => TreeNode), props: BaseProps): TreeNode {
4
+ if (typeof type === 'function') {
5
+ return type(props)
6
+ }
7
+ return node(type, props)
8
+ }
9
+
10
+ export const jsxs = jsx
11
+ export const jsxDEV = jsx
12
+
13
+ export function Fragment({ children }: { children?: unknown }): TreeNode {
14
+ return node('fragment', { children })
15
+ }
16
+
17
+ export namespace JSX {
18
+ export type Element = TreeNode
19
+
20
+ export interface IntrinsicElements {
21
+ frame: BaseProps
22
+ text: TextProps
23
+ rectangle: BaseProps
24
+ ellipse: BaseProps
25
+ line: BaseProps
26
+ star: BaseProps & { points?: number; innerRadius?: number }
27
+ polygon: BaseProps & { pointCount?: number }
28
+ vector: BaseProps
29
+ group: BaseProps
30
+ section: BaseProps
31
+ }
32
+
33
+ export interface ElementChildrenAttribute {
34
+ children: {}
35
+ }
36
+ }