@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,193 @@
1
+ import { parseColor } from '../color'
2
+
3
+ import { defineTool } from './schema'
4
+
5
+ export const listVariables = defineTool({
6
+ name: 'list_variables',
7
+ description: 'List all design variables (colors, numbers, strings, booleans).',
8
+ params: {
9
+ type: {
10
+ type: 'string',
11
+ description: 'Filter by variable type',
12
+ enum: ['COLOR', 'FLOAT', 'STRING', 'BOOLEAN']
13
+ }
14
+ },
15
+ execute: (figma, args) => {
16
+ const vars = figma.getLocalVariables(args.type)
17
+ return { count: vars.length, variables: vars }
18
+ }
19
+ })
20
+
21
+ export const listCollections = defineTool({
22
+ name: 'list_collections',
23
+ description: 'List all variable collections.',
24
+ params: {},
25
+ execute: (figma) => {
26
+ const cols = figma.getLocalVariableCollections()
27
+ return { count: cols.length, collections: cols }
28
+ }
29
+ })
30
+
31
+ export const getVariable = defineTool({
32
+ name: 'get_variable',
33
+ description: 'Get a variable by ID.',
34
+ params: {
35
+ id: { type: 'string', description: 'Variable ID', required: true }
36
+ },
37
+ execute: (figma, { id }) => {
38
+ const v = figma.getVariableById(id)
39
+ if (!v) return { error: `Variable "${id}" not found` }
40
+ return v
41
+ }
42
+ })
43
+
44
+ export const findVariables = defineTool({
45
+ name: 'find_variables',
46
+ description: 'Find variables by name pattern.',
47
+ params: {
48
+ query: { type: 'string', description: 'Name substring (case-insensitive)', required: true },
49
+ type: {
50
+ type: 'string',
51
+ description: 'Filter by type',
52
+ enum: ['COLOR', 'FLOAT', 'STRING', 'BOOLEAN']
53
+ }
54
+ },
55
+ execute: (figma, args) => {
56
+ let vars = figma.getLocalVariables(args.type)
57
+ vars = vars.filter((v) => v.name.toLowerCase().includes(args.query.toLowerCase()))
58
+ return { count: vars.length, variables: vars }
59
+ }
60
+ })
61
+
62
+ export const createVariable = defineTool({
63
+ name: 'create_variable',
64
+ mutates: true,
65
+ description: 'Create a new variable in a collection.',
66
+ params: {
67
+ name: { type: 'string', description: 'Variable name', required: true },
68
+ type: {
69
+ type: 'string',
70
+ description: 'Variable type',
71
+ required: true,
72
+ enum: ['COLOR', 'FLOAT', 'STRING', 'BOOLEAN']
73
+ },
74
+ collection_id: { type: 'string', description: 'Collection ID', required: true },
75
+ value: { type: 'string', description: 'Initial value (hex for COLOR, number for FLOAT, etc.)' }
76
+ },
77
+ execute: (figma, args) => {
78
+ let parsedValue: unknown
79
+ if (args.value !== undefined) {
80
+ if (args.type === 'COLOR') parsedValue = parseColor(args.value)
81
+ else if (args.type === 'FLOAT') parsedValue = Number(args.value)
82
+ else if (args.type === 'BOOLEAN') parsedValue = args.value === 'true'
83
+ else parsedValue = args.value
84
+ }
85
+ const v = figma.createVariable(
86
+ args.name,
87
+ args.type as any,
88
+ args.collection_id,
89
+ parsedValue as any
90
+ )
91
+ return v
92
+ }
93
+ })
94
+
95
+ export const setVariable = defineTool({
96
+ name: 'set_variable',
97
+ mutates: true,
98
+ description: 'Set the value of a variable for a specific mode.',
99
+ params: {
100
+ id: { type: 'string', description: 'Variable ID', required: true },
101
+ mode: { type: 'string', description: 'Mode ID', required: true },
102
+ value: {
103
+ type: 'string',
104
+ description: 'Value (hex for COLOR, number for FLOAT, etc.)',
105
+ required: true
106
+ }
107
+ },
108
+ execute: (figma, args) => {
109
+ const v = figma.getVariableById(args.id)
110
+ if (!v) return { error: `Variable "${args.id}" not found` }
111
+ let parsedValue: unknown
112
+ if (v.type === 'COLOR') parsedValue = parseColor(args.value)
113
+ else if (v.type === 'FLOAT') parsedValue = Number(args.value)
114
+ else if (v.type === 'BOOLEAN') parsedValue = args.value === 'true'
115
+ else parsedValue = args.value
116
+ figma.setVariableValue(args.id, args.mode, parsedValue as any)
117
+ return { id: args.id, mode: args.mode, value: parsedValue }
118
+ }
119
+ })
120
+
121
+ export const deleteVariable = defineTool({
122
+ name: 'delete_variable',
123
+ mutates: true,
124
+ description: 'Delete a variable.',
125
+ params: {
126
+ id: { type: 'string', description: 'Variable ID', required: true }
127
+ },
128
+ execute: (figma, { id }) => {
129
+ figma.deleteVariable(id)
130
+ return { deleted: id }
131
+ }
132
+ })
133
+
134
+ export const bindVariable = defineTool({
135
+ name: 'bind_variable',
136
+ mutates: true,
137
+ description: 'Bind a variable to a node property (fills, strokes, opacity, width, height, etc.).',
138
+ params: {
139
+ node_id: { type: 'string', description: 'Node ID', required: true },
140
+ field: {
141
+ type: 'string',
142
+ description: 'Property field (fills, strokes, opacity, width, height, etc.)',
143
+ required: true
144
+ },
145
+ variable_id: { type: 'string', description: 'Variable ID', required: true }
146
+ },
147
+ execute: (figma, args) => {
148
+ const node = figma.getNodeById(args.node_id)
149
+ if (!node) return { error: `Node "${args.node_id}" not found` }
150
+ const v = figma.getVariableById(args.variable_id)
151
+ if (!v) return { error: `Variable "${args.variable_id}" not found` }
152
+ figma.bindVariable(args.node_id, args.field, args.variable_id)
153
+ return { node_id: args.node_id, field: args.field, variable_id: args.variable_id }
154
+ }
155
+ })
156
+
157
+ export const getCollection = defineTool({
158
+ name: 'get_collection',
159
+ description: 'Get a variable collection by ID.',
160
+ params: {
161
+ id: { type: 'string', description: 'Collection ID', required: true }
162
+ },
163
+ execute: (figma, { id }) => {
164
+ const c = figma.getVariableCollectionById(id)
165
+ if (!c) return { error: `Collection "${id}" not found` }
166
+ return c
167
+ }
168
+ })
169
+
170
+ export const createCollection = defineTool({
171
+ name: 'create_collection',
172
+ mutates: true,
173
+ description: 'Create a new variable collection.',
174
+ params: {
175
+ name: { type: 'string', description: 'Collection name', required: true }
176
+ },
177
+ execute: (figma, { name }) => {
178
+ return figma.createVariableCollection(name)
179
+ }
180
+ })
181
+
182
+ export const deleteCollection = defineTool({
183
+ name: 'delete_collection',
184
+ mutates: true,
185
+ description: 'Delete a variable collection and all its variables.',
186
+ params: {
187
+ id: { type: 'string', description: 'Collection ID', required: true }
188
+ },
189
+ execute: (figma, { id }) => {
190
+ figma.deleteVariableCollection(id)
191
+ return { deleted: id }
192
+ }
193
+ })
@@ -0,0 +1,311 @@
1
+ import { defineTool, nodeSummary } from './schema'
2
+
3
+ const CHUNK_SIZE = 0x8000
4
+
5
+ function uint8ArrayToBase64(bytes: Uint8Array): string {
6
+ if (typeof Buffer !== 'undefined') {
7
+ return Buffer.from(bytes).toString('base64')
8
+ }
9
+ let binary = ''
10
+ for (let i = 0; i < bytes.length; i += CHUNK_SIZE) {
11
+ const chunk = bytes.subarray(i, i + CHUNK_SIZE)
12
+ binary += String.fromCharCode.apply(null, chunk as unknown as number[])
13
+ }
14
+ return btoa(binary)
15
+ }
16
+
17
+ export const booleanUnion = defineTool({
18
+ name: 'boolean_union',
19
+ mutates: true,
20
+ description: 'Union (combine) multiple nodes.',
21
+ params: {
22
+ ids: { type: 'string[]', description: 'Node IDs to union', required: true }
23
+ },
24
+ execute: (figma, { ids }) => {
25
+ const result = figma.booleanOperation('UNION', ids)
26
+ return nodeSummary(result)
27
+ }
28
+ })
29
+
30
+ export const booleanSubtract = defineTool({
31
+ name: 'boolean_subtract',
32
+ mutates: true,
33
+ description: 'Subtract the second node from the first.',
34
+ params: {
35
+ ids: { type: 'string[]', description: 'Node IDs (first minus rest)', required: true }
36
+ },
37
+ execute: (figma, { ids }) => {
38
+ const result = figma.booleanOperation('SUBTRACT', ids)
39
+ return nodeSummary(result)
40
+ }
41
+ })
42
+
43
+ export const booleanIntersect = defineTool({
44
+ name: 'boolean_intersect',
45
+ mutates: true,
46
+ description: 'Intersect multiple nodes.',
47
+ params: {
48
+ ids: { type: 'string[]', description: 'Node IDs to intersect', required: true }
49
+ },
50
+ execute: (figma, { ids }) => {
51
+ const result = figma.booleanOperation('INTERSECT', ids)
52
+ return nodeSummary(result)
53
+ }
54
+ })
55
+
56
+ export const booleanExclude = defineTool({
57
+ name: 'boolean_exclude',
58
+ mutates: true,
59
+ description: 'Exclude (XOR) multiple nodes.',
60
+ params: {
61
+ ids: { type: 'string[]', description: 'Node IDs to exclude', required: true }
62
+ },
63
+ execute: (figma, { ids }) => {
64
+ const result = figma.booleanOperation('EXCLUDE', ids)
65
+ return nodeSummary(result)
66
+ }
67
+ })
68
+
69
+ export const pathGet = defineTool({
70
+ name: 'path_get',
71
+ description: 'Get vector path data of a node.',
72
+ params: {
73
+ id: { type: 'string', description: 'Node ID', required: true }
74
+ },
75
+ execute: (figma, { id }) => {
76
+ const raw = figma.graph.getNode(id)
77
+ if (!raw) return { error: `Node "${id}" not found` }
78
+ if (!raw.vectorNetwork) return { error: `Node "${id}" has no vector data` }
79
+ return { id, vectorNetwork: raw.vectorNetwork }
80
+ }
81
+ })
82
+
83
+ export const pathSet = defineTool({
84
+ name: 'path_set',
85
+ mutates: true,
86
+ description: 'Set vector path data on a node. Provide a VectorNetwork JSON.',
87
+ params: {
88
+ id: { type: 'string', description: 'Node ID', required: true },
89
+ path: { type: 'string', description: 'VectorNetwork JSON', required: true }
90
+ },
91
+ execute: (figma, args) => {
92
+ const raw = figma.graph.getNode(args.id)
93
+ if (!raw) return { error: `Node "${args.id}" not found` }
94
+ const network = JSON.parse(args.path)
95
+ figma.graph.updateNode(args.id, { vectorNetwork: network } as any)
96
+ return { id: args.id }
97
+ }
98
+ })
99
+
100
+ export const pathScale = defineTool({
101
+ name: 'path_scale',
102
+ mutates: true,
103
+ description: 'Scale vector path from center.',
104
+ params: {
105
+ id: { type: 'string', description: 'Node ID', required: true },
106
+ factor: { type: 'number', description: 'Scale factor (e.g. 2 for double)', required: true }
107
+ },
108
+ execute: (figma, { id, factor }) => {
109
+ const raw = figma.graph.getNode(id)
110
+ if (!raw) return { error: `Node "${id}" not found` }
111
+ if (!raw.vectorNetwork) return { error: `Node "${id}" has no vector data` }
112
+ const vn = structuredClone(raw.vectorNetwork)
113
+ const cx = raw.width / 2
114
+ const cy = raw.height / 2
115
+ for (const v of vn.vertices) {
116
+ v.x = cx + (v.x - cx) * factor
117
+ v.y = cy + (v.y - cy) * factor
118
+ }
119
+ for (const s of vn.segments) {
120
+ s.tangentStart.x *= factor
121
+ s.tangentStart.y *= factor
122
+ s.tangentEnd.x *= factor
123
+ s.tangentEnd.y *= factor
124
+ }
125
+ figma.graph.updateNode(id, { vectorNetwork: vn } as any)
126
+ return { id, factor }
127
+ }
128
+ })
129
+
130
+ export const pathFlip = defineTool({
131
+ name: 'path_flip',
132
+ mutates: true,
133
+ description: 'Flip vector path horizontally or vertically.',
134
+ params: {
135
+ id: { type: 'string', description: 'Node ID', required: true },
136
+ axis: {
137
+ type: 'string',
138
+ description: 'Flip axis',
139
+ required: true,
140
+ enum: ['horizontal', 'vertical']
141
+ }
142
+ },
143
+ execute: (figma, { id, axis }) => {
144
+ const raw = figma.graph.getNode(id)
145
+ if (!raw) return { error: `Node "${id}" not found` }
146
+ if (!raw.vectorNetwork) return { error: `Node "${id}" has no vector data` }
147
+ const vn = structuredClone(raw.vectorNetwork)
148
+ const w = raw.width
149
+ const h = raw.height
150
+ for (const v of vn.vertices) {
151
+ if (axis === 'horizontal') v.x = w - v.x
152
+ else v.y = h - v.y
153
+ }
154
+ for (const s of vn.segments) {
155
+ if (axis === 'horizontal') s.tangentStart.x = -s.tangentStart.x
156
+ else s.tangentStart.y = -s.tangentStart.y
157
+ if (axis === 'horizontal') s.tangentEnd.x = -s.tangentEnd.x
158
+ else s.tangentEnd.y = -s.tangentEnd.y
159
+ }
160
+ figma.graph.updateNode(id, { vectorNetwork: vn } as any)
161
+ return { id, axis }
162
+ }
163
+ })
164
+
165
+ export const pathMove = defineTool({
166
+ name: 'path_move',
167
+ mutates: true,
168
+ description: 'Move all path points by an offset.',
169
+ params: {
170
+ id: { type: 'string', description: 'Node ID', required: true },
171
+ dx: { type: 'number', description: 'X offset', required: true },
172
+ dy: { type: 'number', description: 'Y offset', required: true }
173
+ },
174
+ execute: (figma, { id, dx, dy }) => {
175
+ const raw = figma.graph.getNode(id)
176
+ if (!raw) return { error: `Node "${id}" not found` }
177
+ if (!raw.vectorNetwork) return { error: `Node "${id}" has no vector data` }
178
+ const vn = structuredClone(raw.vectorNetwork)
179
+ for (const v of vn.vertices) {
180
+ v.x += dx
181
+ v.y += dy
182
+ }
183
+ figma.graph.updateNode(id, { vectorNetwork: vn } as any)
184
+ return { id, dx, dy }
185
+ }
186
+ })
187
+
188
+ export const viewportGet = defineTool({
189
+ name: 'viewport_get',
190
+ description: 'Get current viewport position and zoom level.',
191
+ params: {},
192
+ execute: (figma) => {
193
+ return figma.viewport
194
+ }
195
+ })
196
+
197
+ export const viewportSet = defineTool({
198
+ name: 'viewport_set',
199
+ mutates: true,
200
+ description: 'Set viewport position and zoom.',
201
+ params: {
202
+ x: { type: 'number', description: 'Center X', required: true },
203
+ y: { type: 'number', description: 'Center Y', required: true },
204
+ zoom: { type: 'number', description: 'Zoom level', required: true, min: 0.01 }
205
+ },
206
+ execute: (figma, { x, y, zoom }) => {
207
+ figma.viewport = { center: { x, y }, zoom }
208
+ return { x, y, zoom }
209
+ }
210
+ })
211
+
212
+ export const viewportZoomToFit = defineTool({
213
+ name: 'viewport_zoom_to_fit',
214
+ mutates: true,
215
+ description: 'Zoom viewport to fit specified nodes.',
216
+ params: {
217
+ ids: { type: 'string[]', description: 'Node IDs to fit in view', required: true }
218
+ },
219
+ execute: (figma, { ids }) => {
220
+ let minX = Infinity
221
+ let minY = Infinity
222
+ let maxX = -Infinity
223
+ let maxY = -Infinity
224
+ for (const id of ids) {
225
+ const node = figma.getNodeById(id)
226
+ if (!node) continue
227
+ const bounds = node.absoluteBoundingBox
228
+ minX = Math.min(minX, bounds.x)
229
+ minY = Math.min(minY, bounds.y)
230
+ maxX = Math.max(maxX, bounds.x + bounds.width)
231
+ maxY = Math.max(maxY, bounds.y + bounds.height)
232
+ }
233
+ if (minX === Infinity) return { error: 'No valid nodes found' }
234
+ const cx = (minX + maxX) / 2
235
+ const cy = (minY + maxY) / 2
236
+ figma.viewport = { center: { x: cx, y: cy }, zoom: 1 }
237
+ return {
238
+ center: { x: cx, y: cy },
239
+ bounds: { x: minX, y: minY, width: maxX - minX, height: maxY - minY }
240
+ }
241
+ }
242
+ })
243
+
244
+ export const exportSvg = defineTool({
245
+ name: 'export_svg',
246
+ description: 'Export nodes as SVG markup. Returns the SVG string.',
247
+ params: {
248
+ ids: {
249
+ type: 'string[]',
250
+ description: 'Node IDs to export. Omit to export all top-level nodes on the current page.'
251
+ }
252
+ },
253
+ execute: async (figma, args) => {
254
+ const { renderNodesToSVG } = await import('../svg-export/index.js')
255
+ const pageId = figma.currentPageId
256
+ const ids =
257
+ args.ids && args.ids.length > 0
258
+ ? args.ids
259
+ : figma.currentPage.children.map((n) => n.id)
260
+ const svg = renderNodesToSVG(figma.graph, pageId, ids)
261
+ if (!svg) return { error: 'No visible nodes to export' }
262
+ return { svg }
263
+ }
264
+ })
265
+
266
+ export const exportImage = defineTool({
267
+ name: 'export_image',
268
+ description:
269
+ 'Export nodes as a raster image (PNG, JPG, or WEBP). Returns base64-encoded image data. Use to visually verify designs.',
270
+ params: {
271
+ ids: {
272
+ type: 'string[]',
273
+ description: 'Node IDs to export. Omit to export all top-level nodes on the current page.'
274
+ },
275
+ format: {
276
+ type: 'string',
277
+ description: 'Image format',
278
+ enum: ['PNG', 'JPG', 'WEBP'],
279
+ default: 'PNG'
280
+ },
281
+ scale: {
282
+ type: 'number',
283
+ description: 'Export scale multiplier (default: 1)',
284
+ default: 1,
285
+ min: 0.1,
286
+ max: 4
287
+ }
288
+ },
289
+ execute: async (figma, args) => {
290
+ if (!figma.exportImage) {
291
+ return { error: 'Image export is not available in this environment' }
292
+ }
293
+ const ids =
294
+ args.ids && args.ids.length > 0
295
+ ? args.ids
296
+ : figma.currentPage.children.map((n) => n.id)
297
+ const format = (args.format ?? 'PNG').toUpperCase() as 'PNG' | 'JPG' | 'WEBP'
298
+ const data = await figma.exportImage(ids, {
299
+ scale: args.scale ?? 1,
300
+ format
301
+ })
302
+ if (!data || data.length === 0) return { error: 'No visible nodes to export' }
303
+ const base64 = uint8ArrayToBase64(data)
304
+ const mimeMap = { PNG: 'image/png', JPG: 'image/jpeg', WEBP: 'image/webp' } as const
305
+ return {
306
+ mimeType: mimeMap[format],
307
+ base64,
308
+ byteLength: data.length
309
+ }
310
+ }
311
+ })
package/src/types.ts ADDED
@@ -0,0 +1,32 @@
1
+ export interface GUID {
2
+ sessionID: number
3
+ localID: number
4
+ }
5
+
6
+ export interface Color {
7
+ r: number
8
+ g: number
9
+ b: number
10
+ a: number
11
+ }
12
+
13
+ export interface Vector {
14
+ x: number
15
+ y: number
16
+ }
17
+
18
+ export interface Matrix {
19
+ m00: number
20
+ m01: number
21
+ m02: number
22
+ m10: number
23
+ m11: number
24
+ m12: number
25
+ }
26
+
27
+ export interface Rect {
28
+ x: number
29
+ y: number
30
+ width: number
31
+ height: number
32
+ }
package/src/undo.ts ADDED
@@ -0,0 +1,126 @@
1
+ import type { SceneNode, SceneGraph } from './scene-graph'
2
+
3
+ export interface UndoEntry {
4
+ label: string
5
+ forward: () => void
6
+ inverse: () => void
7
+ }
8
+
9
+ export class UndoManager {
10
+ private undoStack: UndoEntry[] = []
11
+ private redoStack: UndoEntry[] = []
12
+ private batchEntries: UndoEntry[] | null = null
13
+ private batchLabel = ''
14
+
15
+ apply(entry: UndoEntry): void {
16
+ entry.forward()
17
+ if (this.batchEntries) {
18
+ this.batchEntries.push(entry)
19
+ } else {
20
+ this.undoStack.push(entry)
21
+ this.redoStack = []
22
+ }
23
+ }
24
+
25
+ push(entry: UndoEntry): void {
26
+ if (this.batchEntries) {
27
+ this.batchEntries.push(entry)
28
+ } else {
29
+ this.undoStack.push(entry)
30
+ this.redoStack = []
31
+ }
32
+ }
33
+
34
+ undo(): string | null {
35
+ const entry = this.undoStack.pop()
36
+ if (!entry) return null
37
+ entry.inverse()
38
+ this.redoStack.push(entry)
39
+ return entry.label
40
+ }
41
+
42
+ redo(): string | null {
43
+ const entry = this.redoStack.pop()
44
+ if (!entry) return null
45
+ entry.forward()
46
+ this.undoStack.push(entry)
47
+ return entry.label
48
+ }
49
+
50
+ beginBatch(label: string): void {
51
+ this.batchLabel = label
52
+ this.batchEntries = []
53
+ }
54
+
55
+ commitBatch(): void {
56
+ if (!this.batchEntries || this.batchEntries.length === 0) {
57
+ this.batchEntries = null
58
+ return
59
+ }
60
+ const entries = this.batchEntries
61
+ const label = this.batchLabel
62
+ this.batchEntries = null
63
+
64
+ this.undoStack.push({
65
+ label,
66
+ forward: () => entries.forEach((e) => e.forward()),
67
+ inverse: () => [...entries].reverse().forEach((e) => e.inverse())
68
+ })
69
+ this.redoStack = []
70
+ }
71
+
72
+ clear(): void {
73
+ this.undoStack = []
74
+ this.redoStack = []
75
+ this.batchEntries = null
76
+ }
77
+
78
+ get canUndo(): boolean {
79
+ return this.undoStack.length > 0
80
+ }
81
+
82
+ get canRedo(): boolean {
83
+ return this.redoStack.length > 0
84
+ }
85
+
86
+ get undoLabel(): string | null {
87
+ return this.undoStack.at(-1)?.label ?? null
88
+ }
89
+
90
+ get redoLabel(): string | null {
91
+ return this.redoStack.at(-1)?.label ?? null
92
+ }
93
+
94
+ get undoEntries(): ReadonlyArray<{ label: string }> {
95
+ return this.undoStack.map((e) => ({ label: e.label }))
96
+ }
97
+
98
+ get redoEntries(): ReadonlyArray<{ label: string }> {
99
+ return this.redoStack.map((e) => ({ label: e.label }))
100
+ }
101
+
102
+ get undoCount(): number {
103
+ return this.undoStack.length
104
+ }
105
+
106
+ get redoCount(): number {
107
+ return this.redoStack.length
108
+ }
109
+ }
110
+
111
+ export function createPropertyChange(
112
+ graph: SceneGraph,
113
+ node: SceneNode,
114
+ changes: Partial<SceneNode>,
115
+ label: string
116
+ ): UndoEntry {
117
+ const previous = Object.fromEntries(
118
+ (Object.keys(changes) as (keyof SceneNode)[]).map((key) => [key, node[key]])
119
+ ) as Partial<SceneNode>
120
+
121
+ return {
122
+ label,
123
+ forward: () => graph.updateNode(node.id, changes),
124
+ inverse: () => graph.updateNode(node.id, previous)
125
+ }
126
+ }