@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.
- package/dist/canvaskit.d.ts +9 -0
- package/dist/canvaskit.d.ts.map +1 -0
- package/dist/canvaskit.js +55 -0
- package/dist/canvaskit.js.map +1 -0
- package/dist/clipboard.d.ts +32 -0
- package/dist/clipboard.d.ts.map +1 -0
- package/dist/clipboard.js +345 -0
- package/dist/clipboard.js.map +1 -0
- package/dist/color.d.ts +28 -0
- package/dist/color.d.ts.map +1 -0
- package/dist/color.js +67 -0
- package/dist/color.js.map +1 -0
- package/dist/constants.d.ts +159 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +224 -0
- package/dist/constants.js.map +1 -0
- package/dist/copy.d.ts +20 -0
- package/dist/copy.d.ts.map +1 -0
- package/dist/copy.js +64 -0
- package/dist/copy.js.map +1 -0
- package/dist/fig-export-worker.d.ts +2 -0
- package/dist/fig-export-worker.d.ts.map +1 -0
- package/dist/fig-export-worker.js +17 -0
- package/dist/fig-export-worker.js.map +1 -0
- package/dist/fig-export.d.ts +13 -0
- package/dist/fig-export.d.ts.map +1 -0
- package/dist/fig-export.js +243 -0
- package/dist/fig-export.js.map +1 -0
- package/dist/figma-api.d.ts +268 -0
- package/dist/figma-api.d.ts.map +1 -0
- package/dist/figma-api.js +1074 -0
- package/dist/figma-api.js.map +1 -0
- package/dist/figma-rest-import.d.ts +122 -0
- package/dist/figma-rest-import.d.ts.map +1 -0
- package/dist/figma-rest-import.js +319 -0
- package/dist/figma-rest-import.js.map +1 -0
- package/dist/fonts.d.ts +24 -0
- package/dist/fonts.d.ts.map +1 -0
- package/dist/fonts.js +356 -0
- package/dist/fonts.js.map +1 -0
- package/dist/geometry.d.ts +14 -0
- package/dist/geometry.d.ts.map +1 -0
- package/dist/geometry.js +47 -0
- package/dist/geometry.js.map +1 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/kiwi/codec.d.ts +292 -0
- package/dist/kiwi/codec.d.ts.map +1 -0
- package/dist/kiwi/codec.js +340 -0
- package/dist/kiwi/codec.js.map +1 -0
- package/dist/kiwi/fig-file.d.ts +4 -0
- package/dist/kiwi/fig-file.d.ts.map +1 -0
- package/dist/kiwi/fig-file.js +236 -0
- package/dist/kiwi/fig-file.js.map +1 -0
- package/dist/kiwi/fig-import.d.ts +4 -0
- package/dist/kiwi/fig-import.d.ts.map +1 -0
- package/dist/kiwi/fig-import.js +248 -0
- package/dist/kiwi/fig-import.js.map +1 -0
- package/dist/kiwi/fig-parse-worker.d.ts +7 -0
- package/dist/kiwi/fig-parse-worker.d.ts.map +1 -0
- package/dist/kiwi/fig-parse-worker.js +184 -0
- package/dist/kiwi/fig-parse-worker.js.map +1 -0
- package/dist/kiwi/instance-overrides.d.ts +66 -0
- package/dist/kiwi/instance-overrides.d.ts.map +1 -0
- package/dist/kiwi/instance-overrides.js +644 -0
- package/dist/kiwi/instance-overrides.js.map +1 -0
- package/dist/kiwi/kiwi-convert.d.ts +19 -0
- package/dist/kiwi/kiwi-convert.d.ts.map +1 -0
- package/dist/kiwi/kiwi-convert.js +678 -0
- package/dist/kiwi/kiwi-convert.js.map +1 -0
- package/dist/kiwi/kiwi-schema/bb.d.ts +25 -0
- package/dist/kiwi/kiwi-schema/bb.d.ts.map +1 -0
- package/dist/kiwi/kiwi-schema/bb.js +225 -0
- package/dist/kiwi/kiwi-schema/bb.js.map +1 -0
- package/dist/kiwi/kiwi-schema/binary.d.ts +5 -0
- package/dist/kiwi/kiwi-schema/binary.d.ts.map +1 -0
- package/dist/kiwi/kiwi-schema/binary.js +86 -0
- package/dist/kiwi/kiwi-schema/binary.js.map +1 -0
- package/dist/kiwi/kiwi-schema/index.d.ts +6 -0
- package/dist/kiwi/kiwi-schema/index.d.ts.map +1 -0
- package/dist/kiwi/kiwi-schema/index.js +5 -0
- package/dist/kiwi/kiwi-schema/index.js.map +1 -0
- package/dist/kiwi/kiwi-schema/js.d.ts +4 -0
- package/dist/kiwi/kiwi-schema/js.d.ts.map +1 -0
- package/dist/kiwi/kiwi-schema/js.js +282 -0
- package/dist/kiwi/kiwi-schema/js.js.map +1 -0
- package/dist/kiwi/kiwi-schema/parser.d.ts +5 -0
- package/dist/kiwi/kiwi-schema/parser.d.ts.map +1 -0
- package/dist/kiwi/kiwi-schema/parser.js +228 -0
- package/dist/kiwi/kiwi-schema/parser.js.map +1 -0
- package/dist/kiwi/kiwi-schema/schema.d.ts +22 -0
- package/dist/kiwi/kiwi-schema/schema.d.ts.map +1 -0
- package/dist/kiwi/kiwi-schema/schema.js +2 -0
- package/dist/kiwi/kiwi-schema/schema.js.map +1 -0
- package/dist/kiwi/kiwi-schema/util.d.ts +3 -0
- package/dist/kiwi/kiwi-schema/util.d.ts.map +1 -0
- package/dist/kiwi/kiwi-schema/util.js +10 -0
- package/dist/kiwi/kiwi-schema/util.js.map +1 -0
- package/dist/kiwi/protocol.d.ts +172 -0
- package/dist/kiwi/protocol.d.ts.map +1 -0
- package/dist/kiwi/protocol.js +214 -0
- package/dist/kiwi/protocol.js.map +1 -0
- package/dist/kiwi/schema.d.ts +3 -0
- package/dist/kiwi/schema.d.ts.map +1 -0
- package/dist/kiwi/schema.js +2285 -0
- package/dist/kiwi/schema.js.map +1 -0
- package/dist/kiwi-serialize.d.ts +17 -0
- package/dist/kiwi-serialize.d.ts.map +1 -0
- package/dist/kiwi-serialize.js +419 -0
- package/dist/kiwi-serialize.js.map +1 -0
- package/dist/layout.d.ts +9 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +533 -0
- package/dist/layout.js.map +1 -0
- package/dist/profiler/draw-call-counter.d.ts +9 -0
- package/dist/profiler/draw-call-counter.d.ts.map +1 -0
- package/dist/profiler/draw-call-counter.js +37 -0
- package/dist/profiler/draw-call-counter.js.map +1 -0
- package/dist/profiler/frame-capture.d.ts +34 -0
- package/dist/profiler/frame-capture.d.ts.map +1 -0
- package/dist/profiler/frame-capture.js +90 -0
- package/dist/profiler/frame-capture.js.map +1 -0
- package/dist/profiler/frame-stats.d.ts +33 -0
- package/dist/profiler/frame-stats.d.ts.map +1 -0
- package/dist/profiler/frame-stats.js +103 -0
- package/dist/profiler/frame-stats.js.map +1 -0
- package/dist/profiler/gpu-timer.d.ts +15 -0
- package/dist/profiler/gpu-timer.d.ts.map +1 -0
- package/dist/profiler/gpu-timer.js +77 -0
- package/dist/profiler/gpu-timer.js.map +1 -0
- package/dist/profiler/hud-renderer.d.ts +22 -0
- package/dist/profiler/hud-renderer.d.ts.map +1 -0
- package/dist/profiler/hud-renderer.js +200 -0
- package/dist/profiler/hud-renderer.js.map +1 -0
- package/dist/profiler/index.d.ts +9 -0
- package/dist/profiler/index.d.ts.map +1 -0
- package/dist/profiler/index.js +8 -0
- package/dist/profiler/index.js.map +1 -0
- package/dist/profiler/phase-timer.d.ts +9 -0
- package/dist/profiler/phase-timer.d.ts.map +1 -0
- package/dist/profiler/phase-timer.js +51 -0
- package/dist/profiler/phase-timer.js.map +1 -0
- package/dist/profiler/render-profiler.d.ts +41 -0
- package/dist/profiler/render-profiler.d.ts.map +1 -0
- package/dist/profiler/render-profiler.js +142 -0
- package/dist/profiler/render-profiler.js.map +1 -0
- package/dist/render/components.d.ts +25 -0
- package/dist/render/components.d.ts.map +1 -0
- package/dist/render/components.js +55 -0
- package/dist/render/components.js.map +1 -0
- package/dist/render/emoji-icons.d.ts +5 -0
- package/dist/render/emoji-icons.d.ts.map +1 -0
- package/dist/render/emoji-icons.js +55 -0
- package/dist/render/emoji-icons.js.map +1 -0
- package/dist/render/export-code.d.ts +9 -0
- package/dist/render/export-code.d.ts.map +1 -0
- package/dist/render/export-code.js +335 -0
- package/dist/render/export-code.js.map +1 -0
- package/dist/render/export-jsx.d.ts +5 -0
- package/dist/render/export-jsx.d.ts.map +1 -0
- package/dist/render/export-jsx.js +621 -0
- package/dist/render/export-jsx.js.map +1 -0
- package/dist/render/index.d.ts +8 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +8 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/jsx-runtime.d.ts +31 -0
- package/dist/render/jsx-runtime.d.ts.map +1 -0
- package/dist/render/jsx-runtime.js +13 -0
- package/dist/render/jsx-runtime.js.map +1 -0
- package/dist/render/mini-react.d.ts +14 -0
- package/dist/render/mini-react.d.ts.map +1 -0
- package/dist/render/mini-react.js +16 -0
- package/dist/render/mini-react.js.map +1 -0
- package/dist/render/render-jsx.d.ts +24 -0
- package/dist/render/render-jsx.d.ts.map +1 -0
- package/dist/render/render-jsx.js +51 -0
- package/dist/render/render-jsx.js.map +1 -0
- package/dist/render/renderer.d.ts +16 -0
- package/dist/render/renderer.d.ts.map +1 -0
- package/dist/render/renderer.js +437 -0
- package/dist/render/renderer.js.map +1 -0
- package/dist/render/tailwind.d.ts +20 -0
- package/dist/render/tailwind.d.ts.map +1 -0
- package/dist/render/tailwind.js +115 -0
- package/dist/render/tailwind.js.map +1 -0
- package/dist/render/tree.d.ts +72 -0
- package/dist/render/tree.d.ts.map +1 -0
- package/dist/render/tree.js +63 -0
- package/dist/render/tree.js.map +1 -0
- package/dist/render-image.d.ts +19 -0
- package/dist/render-image.d.ts.map +1 -0
- package/dist/render-image.js +84 -0
- package/dist/render-image.js.map +1 -0
- package/dist/renderer/effects.d.ts +9 -0
- package/dist/renderer/effects.d.ts.map +1 -0
- package/dist/renderer/effects.js +44 -0
- package/dist/renderer/effects.js.map +1 -0
- package/dist/renderer/fills.d.ts +9 -0
- package/dist/renderer/fills.d.ts.map +1 -0
- package/dist/renderer/fills.js +189 -0
- package/dist/renderer/fills.js.map +1 -0
- package/dist/renderer/index.d.ts +2 -0
- package/dist/renderer/index.d.ts.map +1 -0
- package/dist/renderer/index.js +2 -0
- package/dist/renderer/index.js.map +1 -0
- package/dist/renderer/label-cache.d.ts +43 -0
- package/dist/renderer/label-cache.d.ts.map +1 -0
- package/dist/renderer/label-cache.js +85 -0
- package/dist/renderer/label-cache.js.map +1 -0
- package/dist/renderer/labels.d.ts +6 -0
- package/dist/renderer/labels.d.ts.map +1 -0
- package/dist/renderer/labels.js +126 -0
- package/dist/renderer/labels.js.map +1 -0
- package/dist/renderer/lru-cache.d.ts +20 -0
- package/dist/renderer/lru-cache.d.ts.map +1 -0
- package/dist/renderer/lru-cache.js +65 -0
- package/dist/renderer/lru-cache.js.map +1 -0
- package/dist/renderer/overlays.d.ts +25 -0
- package/dist/renderer/overlays.d.ts.map +1 -0
- package/dist/renderer/overlays.js +783 -0
- package/dist/renderer/overlays.js.map +1 -0
- package/dist/renderer/renderer.d.ts +229 -0
- package/dist/renderer/renderer.d.ts.map +1 -0
- package/dist/renderer/renderer.js +909 -0
- package/dist/renderer/renderer.js.map +1 -0
- package/dist/renderer/rulers.d.ts +8 -0
- package/dist/renderer/rulers.d.ts.map +1 -0
- package/dist/renderer/rulers.js +147 -0
- package/dist/renderer/rulers.js.map +1 -0
- package/dist/renderer/scene.d.ts +11 -0
- package/dist/renderer/scene.d.ts.map +1 -0
- package/dist/renderer/scene.js +392 -0
- package/dist/renderer/scene.js.map +1 -0
- package/dist/renderer/shapes.d.ts +13 -0
- package/dist/renderer/shapes.d.ts.map +1 -0
- package/dist/renderer/shapes.js +160 -0
- package/dist/renderer/shapes.js.map +1 -0
- package/dist/renderer/strokes.d.ts +9 -0
- package/dist/renderer/strokes.d.ts.map +1 -0
- package/dist/renderer/strokes.js +180 -0
- package/dist/renderer/strokes.js.map +1 -0
- package/dist/rpc/commands.d.ts +202 -0
- package/dist/rpc/commands.d.ts.map +1 -0
- package/dist/rpc/commands.js +429 -0
- package/dist/rpc/commands.js.map +1 -0
- package/dist/rpc/index.d.ts +3 -0
- package/dist/rpc/index.d.ts.map +1 -0
- package/dist/rpc/index.js +2 -0
- package/dist/rpc/index.js.map +1 -0
- package/dist/scene-graph.d.ts +318 -0
- package/dist/scene-graph.d.ts.map +1 -0
- package/dist/scene-graph.js +803 -0
- package/dist/scene-graph.js.map +1 -0
- package/dist/snap.d.ts +16 -0
- package/dist/snap.d.ts.map +1 -0
- package/dist/snap.js +97 -0
- package/dist/snap.js.map +1 -0
- package/dist/style-runs.d.ts +20 -0
- package/dist/style-runs.d.ts.map +1 -0
- package/dist/style-runs.js +168 -0
- package/dist/style-runs.js.map +1 -0
- package/dist/svg-export/defs.d.ts +19 -0
- package/dist/svg-export/defs.d.ts.map +1 -0
- package/dist/svg-export/defs.js +191 -0
- package/dist/svg-export/defs.js.map +1 -0
- package/dist/svg-export/index.d.ts +8 -0
- package/dist/svg-export/index.d.ts.map +1 -0
- package/dist/svg-export/index.js +318 -0
- package/dist/svg-export/index.js.map +1 -0
- package/dist/svg-export/paths.d.ts +9 -0
- package/dist/svg-export/paths.d.ts.map +1 -0
- package/dist/svg-export/paths.js +189 -0
- package/dist/svg-export/paths.js.map +1 -0
- package/dist/svg-node.d.ts +8 -0
- package/dist/svg-node.d.ts.map +1 -0
- package/dist/svg-node.js +48 -0
- package/dist/svg-node.js.map +1 -0
- package/dist/text-editor.d.ts +57 -0
- package/dist/text-editor.d.ts.map +1 -0
- package/dist/text-editor.js +337 -0
- package/dist/text-editor.js.map +1 -0
- package/dist/tools/ai-adapter.d.ts +22 -0
- package/dist/tools/ai-adapter.d.ts.map +1 -0
- package/dist/tools/ai-adapter.js +121 -0
- package/dist/tools/ai-adapter.js.map +1 -0
- package/dist/tools/analyze.d.ts +22 -0
- package/dist/tools/analyze.d.ts.map +1 -0
- package/dist/tools/analyze.js +677 -0
- package/dist/tools/analyze.js.map +1 -0
- package/dist/tools/create.d.ts +8 -0
- package/dist/tools/create.d.ts.map +1 -0
- package/dist/tools/create.js +204 -0
- package/dist/tools/create.js.map +1 -0
- package/dist/tools/describe.d.ts +9 -0
- package/dist/tools/describe.d.ts.map +1 -0
- package/dist/tools/describe.js +295 -0
- package/dist/tools/describe.js.map +1 -0
- package/dist/tools/export-code.d.ts +2 -0
- package/dist/tools/export-code.d.ts.map +1 -0
- package/dist/tools/export-code.js +34 -0
- package/dist/tools/export-code.js.map +1 -0
- package/dist/tools/export-tailwind-config.d.ts +27 -0
- package/dist/tools/export-tailwind-config.d.ts.map +1 -0
- package/dist/tools/export-tailwind-config.js +215 -0
- package/dist/tools/export-tailwind-config.js.map +1 -0
- package/dist/tools/icons.d.ts +5 -0
- package/dist/tools/icons.d.ts.map +1 -0
- package/dist/tools/icons.js +192 -0
- package/dist/tools/icons.js.map +1 -0
- package/dist/tools/index.d.ts +7 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +6 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/modify.d.ts +22 -0
- package/dist/tools/modify.d.ts.map +1 -0
- package/dist/tools/modify.js +653 -0
- package/dist/tools/modify.js.map +1 -0
- package/dist/tools/patterns.d.ts +2 -0
- package/dist/tools/patterns.d.ts.map +1 -0
- package/dist/tools/patterns.js +173 -0
- package/dist/tools/patterns.js.map +1 -0
- package/dist/tools/read.d.ts +17 -0
- package/dist/tools/read.d.ts.map +1 -0
- package/dist/tools/read.js +379 -0
- package/dist/tools/read.js.map +1 -0
- package/dist/tools/registry.d.ts +3 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +124 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/schema.d.ts +46 -0
- package/dist/tools/schema.d.ts.map +1 -0
- package/dist/tools/schema.js +17 -0
- package/dist/tools/schema.js.map +1 -0
- package/dist/tools/structure.d.ts +18 -0
- package/dist/tools/structure.d.ts.map +1 -0
- package/dist/tools/structure.js +345 -0
- package/dist/tools/structure.js.map +1 -0
- package/dist/tools/variables.d.ts +12 -0
- package/dist/tools/variables.d.ts.map +1 -0
- package/dist/tools/variables.js +190 -0
- package/dist/tools/variables.js.map +1 -0
- package/dist/tools/vector.d.ts +15 -0
- package/dist/tools/vector.d.ts.map +1 -0
- package/dist/tools/vector.js +312 -0
- package/dist/tools/vector.js.map +1 -0
- package/dist/types.d.ts +29 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/undo.d.ts +33 -0
- package/dist/undo.d.ts.map +1 -0
- package/dist/undo.js +98 -0
- package/dist/undo.js.map +1 -0
- package/dist/vector.d.ts +14 -0
- package/dist/vector.d.ts.map +1 -0
- package/dist/vector.js +334 -0
- package/dist/vector.js.map +1 -0
- package/dist/xpath.d.ts +8 -0
- package/dist/xpath.d.ts.map +1 -0
- package/dist/xpath.js +199 -0
- package/dist/xpath.js.map +1 -0
- package/package.json +54 -0
- package/src/canvaskit.ts +66 -0
- package/src/clipboard.ts +444 -0
- package/src/color.ts +83 -0
- package/src/constants.ts +277 -0
- package/src/copy.ts +75 -0
- package/src/fig-export-worker.ts +28 -0
- package/src/fig-export.ts +321 -0
- package/src/figma-api.ts +1297 -0
- package/src/figma-rest-import.ts +443 -0
- package/src/fonts.ts +369 -0
- package/src/geometry.ts +73 -0
- package/src/global.d.ts +20 -0
- package/src/index.ts +247 -0
- package/src/kiwi/codec.ts +614 -0
- package/src/kiwi/fig-file.ts +248 -0
- package/src/kiwi/fig-import.ts +300 -0
- package/src/kiwi/fig-parse-worker.ts +213 -0
- package/src/kiwi/instance-overrides.ts +682 -0
- package/src/kiwi/kiwi-convert.ts +771 -0
- package/src/kiwi/kiwi-schema/bb.ts +244 -0
- package/src/kiwi/kiwi-schema/binary.ts +102 -0
- package/src/kiwi/kiwi-schema/index.ts +5 -0
- package/src/kiwi/kiwi-schema/js.ts +339 -0
- package/src/kiwi/kiwi-schema/parser.ts +287 -0
- package/src/kiwi/kiwi-schema/schema.ts +24 -0
- package/src/kiwi/kiwi-schema/util.ts +10 -0
- package/src/kiwi/protocol.ts +237 -0
- package/src/kiwi/schema.ts +2286 -0
- package/src/kiwi-serialize.ts +467 -0
- package/src/layout.ts +608 -0
- package/src/profiler/draw-call-counter.ts +43 -0
- package/src/profiler/frame-capture.ts +139 -0
- package/src/profiler/frame-stats.ts +122 -0
- package/src/profiler/gpu-timer.ts +93 -0
- package/src/profiler/hud-renderer.ts +242 -0
- package/src/profiler/index.ts +8 -0
- package/src/profiler/phase-timer.ts +62 -0
- package/src/profiler/render-profiler.ts +163 -0
- package/src/render/components.ts +69 -0
- package/src/render/emoji-icons.ts +60 -0
- package/src/render/export-code.ts +366 -0
- package/src/render/export-jsx.ts +633 -0
- package/src/render/index.ts +38 -0
- package/src/render/jsx-runtime.ts +36 -0
- package/src/render/mini-react.ts +30 -0
- package/src/render/render-jsx.ts +74 -0
- package/src/render/renderer.ts +508 -0
- package/src/render/tailwind.ts +114 -0
- package/src/render/tree.ts +137 -0
- package/src/render-image.ts +139 -0
- package/src/renderer/effects.ts +64 -0
- package/src/renderer/fills.ts +248 -0
- package/src/renderer/index.ts +1 -0
- package/src/renderer/label-cache.ts +114 -0
- package/src/renderer/labels.ts +168 -0
- package/src/renderer/lru-cache.ts +71 -0
- package/src/renderer/overlays.ts +1089 -0
- package/src/renderer/renderer.ts +1226 -0
- package/src/renderer/rulers.ts +230 -0
- package/src/renderer/scene.ts +554 -0
- package/src/renderer/shapes.ts +193 -0
- package/src/renderer/strokes.ts +221 -0
- package/src/rpc/commands.ts +667 -0
- package/src/rpc/index.ts +25 -0
- package/src/scene-graph.ts +1254 -0
- package/src/snap.ts +122 -0
- package/src/style-runs.ts +234 -0
- package/src/svg-export/defs.ts +255 -0
- package/src/svg-export/index.ts +427 -0
- package/src/svg-export/paths.ts +212 -0
- package/src/svg-node.ts +62 -0
- package/src/text-editor.ts +349 -0
- package/src/tools/ai-adapter.ts +144 -0
- package/src/tools/analyze.ts +786 -0
- package/src/tools/create.ts +206 -0
- package/src/tools/describe.ts +280 -0
- package/src/tools/export-code.ts +41 -0
- package/src/tools/export-tailwind-config.ts +266 -0
- package/src/tools/icons.ts +213 -0
- package/src/tools/index.ts +6 -0
- package/src/tools/modify.ts +651 -0
- package/src/tools/patterns.ts +189 -0
- package/src/tools/read.ts +401 -0
- package/src/tools/registry.ts +155 -0
- package/src/tools/schema.ts +65 -0
- package/src/tools/structure.ts +348 -0
- package/src/tools/variables.ts +193 -0
- package/src/tools/vector.ts +311 -0
- package/src/types.ts +32 -0
- package/src/undo.ts +126 -0
- package/src/vector.ts +413 -0
- package/src/xpath.ts +259 -0
package/src/figma-api.ts
ADDED
|
@@ -0,0 +1,1297 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
SceneGraph,
|
|
3
|
+
SceneNode,
|
|
4
|
+
NodeType,
|
|
5
|
+
Fill,
|
|
6
|
+
Stroke,
|
|
7
|
+
Effect,
|
|
8
|
+
LayoutMode,
|
|
9
|
+
Variable,
|
|
10
|
+
VariableCollection,
|
|
11
|
+
VariableType,
|
|
12
|
+
VariableValue
|
|
13
|
+
} from './scene-graph'
|
|
14
|
+
import type { Rect, Vector } from './types'
|
|
15
|
+
import { copyFills, copyStrokes, copyEffects } from './copy'
|
|
16
|
+
import { weightToStyle, styleToWeight } from './fonts'
|
|
17
|
+
|
|
18
|
+
const MIXED = Symbol('mixed')
|
|
19
|
+
|
|
20
|
+
type FigmaFontName = { family: string; style: string }
|
|
21
|
+
|
|
22
|
+
export function computeImageHash(data: Uint8Array): string {
|
|
23
|
+
let h1 = 0x811c9dc5 >>> 0
|
|
24
|
+
let h2 = 0x811c9dc5 >>> 0
|
|
25
|
+
let h3 = 0x811c9dc5 >>> 0
|
|
26
|
+
let h4 = 0x811c9dc5 >>> 0
|
|
27
|
+
let h5 = 0x811c9dc5 >>> 0
|
|
28
|
+
for (let i = 0; i < data.length; i++) {
|
|
29
|
+
const b = data[i]
|
|
30
|
+
switch (i % 5) {
|
|
31
|
+
case 0: h1 ^= b; h1 = Math.imul(h1, 0x01000193) >>> 0; break
|
|
32
|
+
case 1: h2 ^= b; h2 = Math.imul(h2, 0x01000193) >>> 0; break
|
|
33
|
+
case 2: h3 ^= b; h3 = Math.imul(h3, 0x01000193) >>> 0; break
|
|
34
|
+
case 3: h4 ^= b; h4 = Math.imul(h4, 0x01000193) >>> 0; break
|
|
35
|
+
case 4: h5 ^= b; h5 = Math.imul(h5, 0x01000193) >>> 0; break
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return [h1, h2, h3, h4, h5].map(h => h.toString(16).padStart(8, '0')).join('')
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const INTERNAL_ID = Symbol('id')
|
|
42
|
+
const INTERNAL_GRAPH = Symbol('graph')
|
|
43
|
+
const INTERNAL_API = Symbol('api')
|
|
44
|
+
|
|
45
|
+
class FigmaNodeProxy {
|
|
46
|
+
[INTERNAL_ID]: string;
|
|
47
|
+
[INTERNAL_GRAPH]: SceneGraph;
|
|
48
|
+
[INTERNAL_API]: FigmaAPI
|
|
49
|
+
|
|
50
|
+
constructor(id: string, graph: SceneGraph, api: FigmaAPI) {
|
|
51
|
+
this[INTERNAL_ID] = id
|
|
52
|
+
this[INTERNAL_GRAPH] = graph
|
|
53
|
+
this[INTERNAL_API] = api
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
private _raw(): SceneNode {
|
|
57
|
+
const n = this[INTERNAL_GRAPH].getNode(this[INTERNAL_ID])
|
|
58
|
+
if (!n) throw new Error(`Node ${this[INTERNAL_ID]} has been removed`)
|
|
59
|
+
return n
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
get id(): string {
|
|
63
|
+
return this[INTERNAL_ID]
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
get type(): NodeType {
|
|
67
|
+
return this._raw().type
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
get name(): string {
|
|
71
|
+
return this._raw().name
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
set name(v: string) {
|
|
75
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { name: v })
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
get removed(): boolean {
|
|
79
|
+
return !this[INTERNAL_GRAPH].getNode(this[INTERNAL_ID])
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// --- Geometry ---
|
|
83
|
+
|
|
84
|
+
get x(): number {
|
|
85
|
+
return this._raw().x
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
set x(v: number) {
|
|
89
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { x: v })
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
get y(): number {
|
|
93
|
+
return this._raw().y
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
set y(v: number) {
|
|
97
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { y: v })
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
get width(): number {
|
|
101
|
+
return this._raw().width
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
get height(): number {
|
|
105
|
+
return this._raw().height
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
get rotation(): number {
|
|
109
|
+
return this._raw().rotation
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
set rotation(v: number) {
|
|
113
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { rotation: v })
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
resize(width: number, height: number): void {
|
|
117
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { width, height })
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
resizeWithoutConstraints(width: number, height: number): void {
|
|
121
|
+
this.resize(width, height)
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
get absoluteTransform(): [[number, number, number], [number, number, number]] {
|
|
125
|
+
const pos = this[INTERNAL_GRAPH].getAbsolutePosition(this[INTERNAL_ID])
|
|
126
|
+
return [
|
|
127
|
+
[1, 0, pos.x],
|
|
128
|
+
[0, 1, pos.y]
|
|
129
|
+
]
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
get absoluteBoundingBox(): Rect {
|
|
133
|
+
return this[INTERNAL_GRAPH].getAbsoluteBounds(this[INTERNAL_ID])
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
get absoluteRenderBounds(): Rect {
|
|
137
|
+
return this.absoluteBoundingBox
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// --- Visual ---
|
|
141
|
+
|
|
142
|
+
get fills(): readonly Fill[] {
|
|
143
|
+
return Object.freeze(copyFills(this._raw().fills))
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
set fills(v: readonly Fill[]) {
|
|
147
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { fills: [...v] })
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
get strokes(): readonly Stroke[] {
|
|
151
|
+
return Object.freeze(copyStrokes(this._raw().strokes))
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
set strokes(v: readonly Stroke[]) {
|
|
155
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { strokes: [...v] })
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
get effects(): readonly Effect[] {
|
|
159
|
+
return Object.freeze(copyEffects(this._raw().effects))
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
set effects(v: readonly Effect[]) {
|
|
163
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { effects: [...v] })
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
get opacity(): number {
|
|
167
|
+
return this._raw().opacity
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
set opacity(v: number) {
|
|
171
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { opacity: v })
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
get visible(): boolean {
|
|
175
|
+
return this._raw().visible
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
set visible(v: boolean) {
|
|
179
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { visible: v })
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
get locked(): boolean {
|
|
183
|
+
return this._raw().locked
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
set locked(v: boolean) {
|
|
187
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { locked: v })
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
get blendMode(): string {
|
|
191
|
+
return this._raw().blendMode
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
set blendMode(v: string) {
|
|
195
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { blendMode: v as SceneNode['blendMode'] })
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
get clipsContent(): boolean {
|
|
199
|
+
return this._raw().clipsContent
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
set clipsContent(v: boolean) {
|
|
203
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { clipsContent: v })
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// --- Corner Radius ---
|
|
207
|
+
|
|
208
|
+
get cornerRadius(): number | typeof MIXED {
|
|
209
|
+
const n = this._raw()
|
|
210
|
+
if (n.independentCorners) return MIXED
|
|
211
|
+
return n.cornerRadius
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
set cornerRadius(v: number | typeof MIXED) {
|
|
215
|
+
if (v === MIXED) return
|
|
216
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
217
|
+
cornerRadius: v,
|
|
218
|
+
topLeftRadius: v,
|
|
219
|
+
topRightRadius: v,
|
|
220
|
+
bottomRightRadius: v,
|
|
221
|
+
bottomLeftRadius: v,
|
|
222
|
+
independentCorners: false
|
|
223
|
+
})
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
get topLeftRadius(): number {
|
|
227
|
+
return this._raw().topLeftRadius
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
set topLeftRadius(v: number) {
|
|
231
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
232
|
+
topLeftRadius: v,
|
|
233
|
+
independentCorners: true
|
|
234
|
+
})
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
get topRightRadius(): number {
|
|
238
|
+
return this._raw().topRightRadius
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
set topRightRadius(v: number) {
|
|
242
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
243
|
+
topRightRadius: v,
|
|
244
|
+
independentCorners: true
|
|
245
|
+
})
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
get bottomLeftRadius(): number {
|
|
249
|
+
return this._raw().bottomLeftRadius
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
set bottomLeftRadius(v: number) {
|
|
253
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
254
|
+
bottomLeftRadius: v,
|
|
255
|
+
independentCorners: true
|
|
256
|
+
})
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
get bottomRightRadius(): number {
|
|
260
|
+
return this._raw().bottomRightRadius
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
set bottomRightRadius(v: number) {
|
|
264
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
265
|
+
bottomRightRadius: v,
|
|
266
|
+
independentCorners: true
|
|
267
|
+
})
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
get cornerSmoothing(): number {
|
|
271
|
+
return this._raw().cornerSmoothing
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
set cornerSmoothing(v: number) {
|
|
275
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { cornerSmoothing: v })
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// --- Stroke details ---
|
|
279
|
+
|
|
280
|
+
get strokeWeight(): number {
|
|
281
|
+
const s = this._raw().strokes
|
|
282
|
+
return s.length > 0 ? s[0].weight : 0
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
set strokeWeight(v: number) {
|
|
286
|
+
const n = this._raw()
|
|
287
|
+
if (n.strokes.length > 0) {
|
|
288
|
+
const strokes = copyStrokes(n.strokes)
|
|
289
|
+
strokes[0].weight = v
|
|
290
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { strokes })
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
get strokeAlign(): string {
|
|
295
|
+
const s = this._raw().strokes
|
|
296
|
+
return s.length > 0 ? s[0].align : 'INSIDE'
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
set strokeAlign(v: string) {
|
|
300
|
+
const n = this._raw()
|
|
301
|
+
if (n.strokes.length > 0) {
|
|
302
|
+
const strokes = copyStrokes(n.strokes)
|
|
303
|
+
strokes[0].align = v as Stroke['align']
|
|
304
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { strokes })
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
get dashPattern(): readonly number[] {
|
|
309
|
+
return Object.freeze([...this._raw().dashPattern])
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
set dashPattern(v: readonly number[]) {
|
|
313
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { dashPattern: [...v] })
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
get strokeCap(): string {
|
|
317
|
+
return this._raw().strokeCap
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
set strokeCap(v: string) {
|
|
321
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { strokeCap: v as SceneNode['strokeCap'] })
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
get strokeJoin(): string {
|
|
325
|
+
return this._raw().strokeJoin
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
set strokeJoin(v: string) {
|
|
329
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { strokeJoin: v as SceneNode['strokeJoin'] })
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
get strokeMiterLimit(): number {
|
|
333
|
+
return this._raw().strokeMiterLimit
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
set strokeMiterLimit(v: number) {
|
|
337
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { strokeMiterLimit: v })
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
get strokeTopWeight(): number {
|
|
341
|
+
return this._raw().borderTopWeight
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
set strokeTopWeight(v: number) {
|
|
345
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
346
|
+
borderTopWeight: v,
|
|
347
|
+
independentStrokeWeights: true
|
|
348
|
+
})
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
get strokeBottomWeight(): number {
|
|
352
|
+
return this._raw().borderBottomWeight
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
set strokeBottomWeight(v: number) {
|
|
356
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
357
|
+
borderBottomWeight: v,
|
|
358
|
+
independentStrokeWeights: true
|
|
359
|
+
})
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
get strokeLeftWeight(): number {
|
|
363
|
+
return this._raw().borderLeftWeight
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
set strokeLeftWeight(v: number) {
|
|
367
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
368
|
+
borderLeftWeight: v,
|
|
369
|
+
independentStrokeWeights: true
|
|
370
|
+
})
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
get strokeRightWeight(): number {
|
|
374
|
+
return this._raw().borderRightWeight
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
set strokeRightWeight(v: number) {
|
|
378
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
379
|
+
borderRightWeight: v,
|
|
380
|
+
independentStrokeWeights: true
|
|
381
|
+
})
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// --- Text ---
|
|
385
|
+
|
|
386
|
+
get characters(): string {
|
|
387
|
+
return this._raw().text
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
set characters(v: string) {
|
|
391
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { text: v })
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
get fontSize(): number {
|
|
395
|
+
return this._raw().fontSize
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
set fontSize(v: number) {
|
|
399
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { fontSize: v })
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
get fontName(): FigmaFontName {
|
|
403
|
+
const n = this._raw()
|
|
404
|
+
return { family: n.fontFamily, style: weightToStyle(n.fontWeight, n.italic) }
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
set fontName(v: FigmaFontName) {
|
|
408
|
+
const weight = styleToWeight(v.style)
|
|
409
|
+
const italic = v.style.toLowerCase().includes('italic')
|
|
410
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
411
|
+
fontFamily: v.family,
|
|
412
|
+
fontWeight: weight,
|
|
413
|
+
italic
|
|
414
|
+
})
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
get fontWeight(): number {
|
|
418
|
+
return this._raw().fontWeight
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
set fontWeight(v: number) {
|
|
422
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { fontWeight: v })
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
get textAlignHorizontal(): string {
|
|
426
|
+
return this._raw().textAlignHorizontal
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
set textAlignHorizontal(v: string) {
|
|
430
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
431
|
+
textAlignHorizontal: v as SceneNode['textAlignHorizontal']
|
|
432
|
+
})
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
get textAlignVertical(): string {
|
|
436
|
+
return this._raw().textAlignVertical
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
set textAlignVertical(v: string) {
|
|
440
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
441
|
+
textAlignVertical: v as SceneNode['textAlignVertical']
|
|
442
|
+
})
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
get textAutoResize(): string {
|
|
446
|
+
return this._raw().textAutoResize
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
set textAutoResize(v: string) {
|
|
450
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
451
|
+
textAutoResize: v as SceneNode['textAutoResize']
|
|
452
|
+
})
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
get letterSpacing(): number {
|
|
456
|
+
return this._raw().letterSpacing
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
set letterSpacing(v: number) {
|
|
460
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { letterSpacing: v })
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
get lineHeight(): number | null {
|
|
464
|
+
return this._raw().lineHeight
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
set lineHeight(v: number | null) {
|
|
468
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { lineHeight: v })
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
get textCase(): string {
|
|
472
|
+
return this._raw().textCase
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
set textCase(v: string) {
|
|
476
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { textCase: v as SceneNode['textCase'] })
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
get textDecoration(): string {
|
|
480
|
+
return this._raw().textDecoration
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
set textDecoration(v: string) {
|
|
484
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
485
|
+
textDecoration: v as SceneNode['textDecoration']
|
|
486
|
+
})
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
get maxLines(): number | null {
|
|
490
|
+
return this._raw().maxLines
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
set maxLines(v: number | null) {
|
|
494
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { maxLines: v })
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
get textTruncation(): string {
|
|
498
|
+
return this._raw().textTruncation
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
set textTruncation(v: string) {
|
|
502
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
503
|
+
textTruncation: v as SceneNode['textTruncation']
|
|
504
|
+
})
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
get autoRename(): boolean {
|
|
508
|
+
return this._raw().autoRename
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
set autoRename(v: boolean) {
|
|
512
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { autoRename: v })
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
insertCharacters(start: number, characters: string): void {
|
|
516
|
+
const n = this._raw()
|
|
517
|
+
const text = n.text.slice(0, start) + characters + n.text.slice(start)
|
|
518
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { text })
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
deleteCharacters(start: number, end: number): void {
|
|
522
|
+
const n = this._raw()
|
|
523
|
+
const text = n.text.slice(0, start) + n.text.slice(end)
|
|
524
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { text })
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
// --- Auto-layout ---
|
|
528
|
+
|
|
529
|
+
get layoutMode(): LayoutMode {
|
|
530
|
+
return this._raw().layoutMode
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
set layoutMode(v: LayoutMode) {
|
|
534
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { layoutMode: v })
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
get primaryAxisAlignItems(): string {
|
|
538
|
+
return this._raw().primaryAxisAlign
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
set primaryAxisAlignItems(v: string) {
|
|
542
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
543
|
+
primaryAxisAlign: v as SceneNode['primaryAxisAlign']
|
|
544
|
+
})
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
get counterAxisAlignItems(): string {
|
|
548
|
+
return this._raw().counterAxisAlign
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
set counterAxisAlignItems(v: string) {
|
|
552
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
553
|
+
counterAxisAlign: v as SceneNode['counterAxisAlign']
|
|
554
|
+
})
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
get itemSpacing(): number {
|
|
558
|
+
return this._raw().itemSpacing
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
set itemSpacing(v: number) {
|
|
562
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { itemSpacing: v })
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
get counterAxisSpacing(): number {
|
|
566
|
+
return this._raw().counterAxisSpacing
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
set counterAxisSpacing(v: number) {
|
|
570
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { counterAxisSpacing: v })
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
get paddingTop(): number {
|
|
574
|
+
return this._raw().paddingTop
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
set paddingTop(v: number) {
|
|
578
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { paddingTop: v })
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
get paddingRight(): number {
|
|
582
|
+
return this._raw().paddingRight
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
set paddingRight(v: number) {
|
|
586
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { paddingRight: v })
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
get paddingBottom(): number {
|
|
590
|
+
return this._raw().paddingBottom
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
set paddingBottom(v: number) {
|
|
594
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { paddingBottom: v })
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
get paddingLeft(): number {
|
|
598
|
+
return this._raw().paddingLeft
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
set paddingLeft(v: number) {
|
|
602
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { paddingLeft: v })
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
get layoutWrap(): string {
|
|
606
|
+
return this._raw().layoutWrap
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
set layoutWrap(v: string) {
|
|
610
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { layoutWrap: v as SceneNode['layoutWrap'] })
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
get primaryAxisSizingMode(): string {
|
|
614
|
+
return this._raw().primaryAxisSizing === 'HUG' ? 'AUTO' : this._raw().primaryAxisSizing
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
set primaryAxisSizingMode(v: string) {
|
|
618
|
+
const mapped = v === 'AUTO' ? 'HUG' : v
|
|
619
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
620
|
+
primaryAxisSizing: mapped as SceneNode['primaryAxisSizing']
|
|
621
|
+
})
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
get counterAxisSizingMode(): string {
|
|
625
|
+
return this._raw().counterAxisSizing === 'HUG' ? 'AUTO' : this._raw().counterAxisSizing
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
set counterAxisSizingMode(v: string) {
|
|
629
|
+
const mapped = v === 'AUTO' ? 'HUG' : v
|
|
630
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
631
|
+
counterAxisSizing: mapped as SceneNode['counterAxisSizing']
|
|
632
|
+
})
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
get counterAxisAlignContent(): string {
|
|
636
|
+
return this._raw().counterAxisAlignContent
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
set counterAxisAlignContent(v: string) {
|
|
640
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
641
|
+
counterAxisAlignContent: v as SceneNode['counterAxisAlignContent']
|
|
642
|
+
})
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
get itemReverseZIndex(): boolean {
|
|
646
|
+
return this._raw().itemReverseZIndex
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
set itemReverseZIndex(v: boolean) {
|
|
650
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { itemReverseZIndex: v })
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
get strokesIncludedInLayout(): boolean {
|
|
654
|
+
return this._raw().strokesIncludedInLayout
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
set strokesIncludedInLayout(v: boolean) {
|
|
658
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { strokesIncludedInLayout: v })
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
// --- Layout child props ---
|
|
662
|
+
|
|
663
|
+
get layoutPositioning(): string {
|
|
664
|
+
return this._raw().layoutPositioning
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
set layoutPositioning(v: string) {
|
|
668
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
669
|
+
layoutPositioning: v as SceneNode['layoutPositioning']
|
|
670
|
+
})
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
get layoutGrow(): number {
|
|
674
|
+
return this._raw().layoutGrow
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
set layoutGrow(v: number) {
|
|
678
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { layoutGrow: v })
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
get layoutAlign(): string {
|
|
682
|
+
const n = this._raw()
|
|
683
|
+
if (n.layoutAlignSelf === 'AUTO') return 'INHERIT'
|
|
684
|
+
return n.layoutAlignSelf
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
set layoutAlign(v: string) {
|
|
688
|
+
const mapped = v === 'INHERIT' ? 'AUTO' : v
|
|
689
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
690
|
+
layoutAlignSelf: mapped as SceneNode['layoutAlignSelf']
|
|
691
|
+
})
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
get layoutSizingHorizontal(): string {
|
|
695
|
+
const n = this._raw()
|
|
696
|
+
const parent = n.parentId ? this[INTERNAL_GRAPH].getNode(n.parentId) : undefined
|
|
697
|
+
const refLayout = parent && parent.layoutMode !== 'NONE' ? parent.layoutMode : n.layoutMode
|
|
698
|
+
if (refLayout === 'NONE') return 'FIXED'
|
|
699
|
+
return refLayout === 'HORIZONTAL' ? n.primaryAxisSizing : n.counterAxisSizing
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
set layoutSizingHorizontal(v: string) {
|
|
703
|
+
const n = this._raw()
|
|
704
|
+
const parent = n.parentId ? this[INTERNAL_GRAPH].getNode(n.parentId) : undefined
|
|
705
|
+
const refLayout = parent && parent.layoutMode !== 'NONE' ? parent.layoutMode : n.layoutMode
|
|
706
|
+
if (refLayout === 'VERTICAL') {
|
|
707
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
708
|
+
counterAxisSizing: v as SceneNode['counterAxisSizing']
|
|
709
|
+
})
|
|
710
|
+
} else {
|
|
711
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
712
|
+
primaryAxisSizing: v as SceneNode['primaryAxisSizing']
|
|
713
|
+
})
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
get layoutSizingVertical(): string {
|
|
718
|
+
const n = this._raw()
|
|
719
|
+
const parent = n.parentId ? this[INTERNAL_GRAPH].getNode(n.parentId) : undefined
|
|
720
|
+
const refLayout = parent && parent.layoutMode !== 'NONE' ? parent.layoutMode : n.layoutMode
|
|
721
|
+
if (refLayout === 'NONE') return 'FIXED'
|
|
722
|
+
return refLayout === 'VERTICAL' ? n.primaryAxisSizing : n.counterAxisSizing
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
set layoutSizingVertical(v: string) {
|
|
726
|
+
const n = this._raw()
|
|
727
|
+
const parent = n.parentId ? this[INTERNAL_GRAPH].getNode(n.parentId) : undefined
|
|
728
|
+
const refLayout = parent && parent.layoutMode !== 'NONE' ? parent.layoutMode : n.layoutMode
|
|
729
|
+
if (refLayout === 'HORIZONTAL') {
|
|
730
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
731
|
+
counterAxisSizing: v as SceneNode['counterAxisSizing']
|
|
732
|
+
})
|
|
733
|
+
} else {
|
|
734
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
735
|
+
primaryAxisSizing: v as SceneNode['primaryAxisSizing']
|
|
736
|
+
})
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
// --- Constraints ---
|
|
741
|
+
|
|
742
|
+
get constraints(): { horizontal: string; vertical: string } {
|
|
743
|
+
const n = this._raw()
|
|
744
|
+
return { horizontal: n.horizontalConstraint, vertical: n.verticalConstraint }
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
set constraints(v: { horizontal: string; vertical: string }) {
|
|
748
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], {
|
|
749
|
+
horizontalConstraint: v.horizontal as SceneNode['horizontalConstraint'],
|
|
750
|
+
verticalConstraint: v.vertical as SceneNode['verticalConstraint']
|
|
751
|
+
})
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// --- Dimension constraints ---
|
|
755
|
+
|
|
756
|
+
get minWidth(): number | null {
|
|
757
|
+
return this._raw().minWidth
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
set minWidth(v: number | null) {
|
|
761
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { minWidth: v })
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
get maxWidth(): number | null {
|
|
765
|
+
return this._raw().maxWidth
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
set maxWidth(v: number | null) {
|
|
769
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { maxWidth: v })
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
get minHeight(): number | null {
|
|
773
|
+
return this._raw().minHeight
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
set minHeight(v: number | null) {
|
|
777
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { minHeight: v })
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
get maxHeight(): number | null {
|
|
781
|
+
return this._raw().maxHeight
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
set maxHeight(v: number | null) {
|
|
785
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { maxHeight: v })
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// --- Mask ---
|
|
789
|
+
|
|
790
|
+
get isMask(): boolean {
|
|
791
|
+
return this._raw().isMask
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
set isMask(v: boolean) {
|
|
795
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { isMask: v })
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
get maskType(): string {
|
|
799
|
+
return this._raw().maskType
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
set maskType(v: string) {
|
|
803
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { maskType: v as SceneNode['maskType'] })
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
// --- UI state ---
|
|
807
|
+
|
|
808
|
+
get expanded(): boolean {
|
|
809
|
+
return this._raw().expanded
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
set expanded(v: boolean) {
|
|
813
|
+
this[INTERNAL_GRAPH].updateNode(this[INTERNAL_ID], { expanded: v })
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// --- Components ---
|
|
817
|
+
|
|
818
|
+
get mainComponent(): FigmaNodeProxy | null {
|
|
819
|
+
const n = this._raw()
|
|
820
|
+
if (!n.componentId) return null
|
|
821
|
+
const comp = this[INTERNAL_GRAPH].getNode(n.componentId)
|
|
822
|
+
if (!comp) return null
|
|
823
|
+
return this[INTERNAL_API].wrapNode(comp.id)
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
createInstance(): FigmaNodeProxy {
|
|
827
|
+
const n = this._raw()
|
|
828
|
+
if (n.type !== 'COMPONENT') throw new Error('createInstance() can only be called on components')
|
|
829
|
+
const pageId = this[INTERNAL_API].currentPageId
|
|
830
|
+
const inst = this[INTERNAL_GRAPH].createInstance(n.id, pageId)
|
|
831
|
+
if (!inst) throw new Error('Failed to create instance')
|
|
832
|
+
return this[INTERNAL_API].wrapNode(inst.id)
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// --- Tree ---
|
|
836
|
+
|
|
837
|
+
get parent(): FigmaNodeProxy | null {
|
|
838
|
+
const n = this._raw()
|
|
839
|
+
if (!n.parentId) return null
|
|
840
|
+
return this[INTERNAL_API].wrapNode(n.parentId)
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
get children(): FigmaNodeProxy[] {
|
|
844
|
+
return this[INTERNAL_GRAPH]
|
|
845
|
+
.getChildren(this[INTERNAL_ID])
|
|
846
|
+
.map((c) => this[INTERNAL_API].wrapNode(c.id))
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
appendChild(child: FigmaNodeProxy): void {
|
|
850
|
+
this[INTERNAL_GRAPH].reparentNode(child[INTERNAL_ID], this[INTERNAL_ID])
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
insertChild(index: number, child: FigmaNodeProxy): void {
|
|
854
|
+
this[INTERNAL_GRAPH].reparentNode(child[INTERNAL_ID], this[INTERNAL_ID])
|
|
855
|
+
this[INTERNAL_GRAPH].reorderChild(child[INTERNAL_ID], this[INTERNAL_ID], index)
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
clone(): FigmaNodeProxy {
|
|
859
|
+
const n = this._raw()
|
|
860
|
+
const parentId = n.parentId ?? this[INTERNAL_API].currentPageId
|
|
861
|
+
const cloned = this[INTERNAL_GRAPH].cloneTree(this[INTERNAL_ID], parentId)
|
|
862
|
+
if (!cloned) throw new Error(`Failed to clone node ${this[INTERNAL_ID]}`)
|
|
863
|
+
return this[INTERNAL_API].wrapNode(cloned.id)
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
remove(): void {
|
|
867
|
+
this[INTERNAL_GRAPH].deleteNode(this[INTERNAL_ID])
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
findAll(callback?: (node: FigmaNodeProxy) => boolean): FigmaNodeProxy[] {
|
|
871
|
+
const results: FigmaNodeProxy[] = []
|
|
872
|
+
const walk = (id: string) => {
|
|
873
|
+
for (const child of this[INTERNAL_GRAPH].getChildren(id)) {
|
|
874
|
+
const proxy = this[INTERNAL_API].wrapNode(child.id)
|
|
875
|
+
if (!callback || callback(proxy)) results.push(proxy)
|
|
876
|
+
walk(child.id)
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
walk(this[INTERNAL_ID])
|
|
880
|
+
return results
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
findOne(callback: (node: FigmaNodeProxy) => boolean): FigmaNodeProxy | null {
|
|
884
|
+
const walk = (id: string): FigmaNodeProxy | null => {
|
|
885
|
+
for (const child of this[INTERNAL_GRAPH].getChildren(id)) {
|
|
886
|
+
const proxy = this[INTERNAL_API].wrapNode(child.id)
|
|
887
|
+
if (callback(proxy)) return proxy
|
|
888
|
+
const found = walk(child.id)
|
|
889
|
+
if (found) return found
|
|
890
|
+
}
|
|
891
|
+
return null
|
|
892
|
+
}
|
|
893
|
+
return walk(this[INTERNAL_ID])
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
findChild(callback: (node: FigmaNodeProxy) => boolean): FigmaNodeProxy | null {
|
|
897
|
+
for (const child of this[INTERNAL_GRAPH].getChildren(this[INTERNAL_ID])) {
|
|
898
|
+
const proxy = this[INTERNAL_API].wrapNode(child.id)
|
|
899
|
+
if (callback(proxy)) return proxy
|
|
900
|
+
}
|
|
901
|
+
return null
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
findChildren(callback?: (node: FigmaNodeProxy) => boolean): FigmaNodeProxy[] {
|
|
905
|
+
return this[INTERNAL_GRAPH]
|
|
906
|
+
.getChildren(this[INTERNAL_ID])
|
|
907
|
+
.map((c) => this[INTERNAL_API].wrapNode(c.id))
|
|
908
|
+
.filter((proxy) => !callback || callback(proxy))
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
findAllWithCriteria(criteria: { types?: string[] }): FigmaNodeProxy[] {
|
|
912
|
+
const types = criteria.types ? new Set(criteria.types) : null
|
|
913
|
+
return this.findAll((node) => !types || types.has(node.type))
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
// --- Serialization ---
|
|
917
|
+
|
|
918
|
+
toJSON(): Record<string, unknown> {
|
|
919
|
+
const n = this._raw()
|
|
920
|
+
const obj: Record<string, unknown> = {
|
|
921
|
+
id: n.id,
|
|
922
|
+
type: n.type,
|
|
923
|
+
name: n.name,
|
|
924
|
+
x: n.x,
|
|
925
|
+
y: n.y,
|
|
926
|
+
width: n.width,
|
|
927
|
+
height: n.height
|
|
928
|
+
}
|
|
929
|
+
if (n.fills.length > 0) obj.fills = n.fills
|
|
930
|
+
if (n.strokes.length > 0) obj.strokes = n.strokes
|
|
931
|
+
if (n.effects.length > 0) obj.effects = n.effects
|
|
932
|
+
if (n.opacity !== 1) obj.opacity = n.opacity
|
|
933
|
+
if (n.cornerRadius > 0) obj.cornerRadius = n.cornerRadius
|
|
934
|
+
if (!n.visible) obj.visible = false
|
|
935
|
+
if (n.text) obj.characters = n.text
|
|
936
|
+
if (n.layoutMode !== 'NONE') {
|
|
937
|
+
obj.layoutMode = n.layoutMode
|
|
938
|
+
obj.itemSpacing = n.itemSpacing
|
|
939
|
+
}
|
|
940
|
+
const children = this[INTERNAL_GRAPH].getChildren(this[INTERNAL_ID])
|
|
941
|
+
if (children.length > 0) {
|
|
942
|
+
obj.children = children.map((c) => this[INTERNAL_API].wrapNode(c.id).toJSON())
|
|
943
|
+
}
|
|
944
|
+
return obj
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
toString(): string {
|
|
948
|
+
const n = this._raw()
|
|
949
|
+
return `[${n.type} "${n.name}" ${n.id}]`
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
[Symbol.for('nodejs.util.inspect.custom')](): string {
|
|
953
|
+
return this.toString()
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
export class FigmaAPI {
|
|
958
|
+
readonly graph: SceneGraph
|
|
959
|
+
private _currentPageId: string
|
|
960
|
+
private _selection: FigmaNodeProxy[] = []
|
|
961
|
+
private _nodeCache = new Map<string, FigmaNodeProxy>()
|
|
962
|
+
private _pageProxies = new WeakSet<FigmaNodeProxy>()
|
|
963
|
+
|
|
964
|
+
readonly mixed = MIXED
|
|
965
|
+
|
|
966
|
+
constructor(graph: SceneGraph) {
|
|
967
|
+
this.graph = graph
|
|
968
|
+
const pages = graph.getPages()
|
|
969
|
+
this._currentPageId = pages[0]?.id ?? graph.rootId
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
get currentPageId(): string {
|
|
973
|
+
return this._currentPageId
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
wrapNode(id: string): FigmaNodeProxy {
|
|
977
|
+
let proxy = this._nodeCache.get(id)
|
|
978
|
+
if (!proxy) {
|
|
979
|
+
proxy = new FigmaNodeProxy(id, this.graph, this)
|
|
980
|
+
this._nodeCache.set(id, proxy)
|
|
981
|
+
}
|
|
982
|
+
return proxy
|
|
983
|
+
}
|
|
984
|
+
|
|
985
|
+
private _ensurePageProxy(
|
|
986
|
+
proxy: FigmaNodeProxy
|
|
987
|
+
): FigmaNodeProxy & { selection: FigmaNodeProxy[] } {
|
|
988
|
+
if (!this._pageProxies.has(proxy)) {
|
|
989
|
+
Object.defineProperty(proxy, 'selection', {
|
|
990
|
+
get: () => this._selection,
|
|
991
|
+
set: (nodes: FigmaNodeProxy[]) => {
|
|
992
|
+
this._selection = nodes
|
|
993
|
+
},
|
|
994
|
+
enumerable: true,
|
|
995
|
+
configurable: true
|
|
996
|
+
})
|
|
997
|
+
this._pageProxies.add(proxy)
|
|
998
|
+
}
|
|
999
|
+
return proxy as FigmaNodeProxy & { selection: FigmaNodeProxy[] }
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
get root(): FigmaNodeProxy {
|
|
1003
|
+
return this.wrapNode(this.graph.rootId)
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
get currentPage(): FigmaNodeProxy & { selection: FigmaNodeProxy[] } {
|
|
1007
|
+
return this._ensurePageProxy(this.wrapNode(this._currentPageId))
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
set currentPage(page: FigmaNodeProxy) {
|
|
1011
|
+
this._currentPageId = page[INTERNAL_ID]
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
getNodeById(id: string): FigmaNodeProxy | null {
|
|
1015
|
+
const node = this.graph.getNode(id)
|
|
1016
|
+
return node ? this.wrapNode(id) : null
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
// --- Node Creation ---
|
|
1020
|
+
|
|
1021
|
+
private _createNode(type: NodeType): FigmaNodeProxy {
|
|
1022
|
+
const node = this.graph.createNode(type, this._currentPageId)
|
|
1023
|
+
return this.wrapNode(node.id)
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
createFrame(): FigmaNodeProxy {
|
|
1027
|
+
return this._createNode('FRAME')
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
createRectangle(): FigmaNodeProxy {
|
|
1031
|
+
return this._createNode('RECTANGLE')
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
createEllipse(): FigmaNodeProxy {
|
|
1035
|
+
return this._createNode('ELLIPSE')
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
createText(): FigmaNodeProxy {
|
|
1039
|
+
return this._createNode('TEXT')
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
createLine(): FigmaNodeProxy {
|
|
1043
|
+
return this._createNode('LINE')
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
createPolygon(): FigmaNodeProxy {
|
|
1047
|
+
return this._createNode('POLYGON')
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
createStar(): FigmaNodeProxy {
|
|
1051
|
+
return this._createNode('STAR')
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
createVector(): FigmaNodeProxy {
|
|
1055
|
+
return this._createNode('VECTOR')
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
createComponent(): FigmaNodeProxy {
|
|
1059
|
+
return this._createNode('COMPONENT')
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
createSection(): FigmaNodeProxy {
|
|
1063
|
+
return this._createNode('SECTION')
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
createPage(): FigmaNodeProxy {
|
|
1067
|
+
const page = this.graph.addPage('Page')
|
|
1068
|
+
return this.wrapNode(page.id)
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1071
|
+
// --- Grouping ---
|
|
1072
|
+
|
|
1073
|
+
group(nodes: FigmaNodeProxy[], parent: FigmaNodeProxy): FigmaNodeProxy {
|
|
1074
|
+
const groupNode = this.graph.createNode('GROUP', parent[INTERNAL_ID])
|
|
1075
|
+
for (const n of nodes) {
|
|
1076
|
+
this.graph.reparentNode(n[INTERNAL_ID], groupNode.id)
|
|
1077
|
+
}
|
|
1078
|
+
return this.wrapNode(groupNode.id)
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
ungroup(node: FigmaNodeProxy): void {
|
|
1082
|
+
const raw = this.graph.getNode(node[INTERNAL_ID])
|
|
1083
|
+
if (raw?.type !== 'GROUP') return
|
|
1084
|
+
const parentId = raw.parentId ?? this._currentPageId
|
|
1085
|
+
for (const childId of Array.from(raw.childIds)) {
|
|
1086
|
+
this.graph.reparentNode(childId, parentId)
|
|
1087
|
+
}
|
|
1088
|
+
this.graph.deleteNode(node[INTERNAL_ID])
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
createComponentFromNode(node: FigmaNodeProxy): FigmaNodeProxy {
|
|
1092
|
+
const raw = this.graph.getNode(node[INTERNAL_ID])
|
|
1093
|
+
if (!raw) throw new Error('Node not found')
|
|
1094
|
+
const parentId = raw.parentId ?? this._currentPageId
|
|
1095
|
+
const comp = this.graph.createNode('COMPONENT', parentId)
|
|
1096
|
+
this.graph.updateNode(comp.id, {
|
|
1097
|
+
name: raw.name,
|
|
1098
|
+
width: raw.width,
|
|
1099
|
+
height: raw.height,
|
|
1100
|
+
x: raw.x,
|
|
1101
|
+
y: raw.y,
|
|
1102
|
+
fills: copyFills(raw.fills),
|
|
1103
|
+
strokes: copyStrokes(raw.strokes),
|
|
1104
|
+
effects: copyEffects(raw.effects),
|
|
1105
|
+
cornerRadius: raw.cornerRadius,
|
|
1106
|
+
topLeftRadius: raw.topLeftRadius,
|
|
1107
|
+
topRightRadius: raw.topRightRadius,
|
|
1108
|
+
bottomRightRadius: raw.bottomRightRadius,
|
|
1109
|
+
bottomLeftRadius: raw.bottomLeftRadius,
|
|
1110
|
+
independentCorners: raw.independentCorners,
|
|
1111
|
+
opacity: raw.opacity,
|
|
1112
|
+
layoutMode: raw.layoutMode,
|
|
1113
|
+
primaryAxisAlign: raw.primaryAxisAlign,
|
|
1114
|
+
counterAxisAlign: raw.counterAxisAlign,
|
|
1115
|
+
itemSpacing: raw.itemSpacing,
|
|
1116
|
+
paddingTop: raw.paddingTop,
|
|
1117
|
+
paddingRight: raw.paddingRight,
|
|
1118
|
+
paddingBottom: raw.paddingBottom,
|
|
1119
|
+
paddingLeft: raw.paddingLeft
|
|
1120
|
+
})
|
|
1121
|
+
for (const childId of raw.childIds) {
|
|
1122
|
+
this.graph.cloneTree(childId, comp.id)
|
|
1123
|
+
}
|
|
1124
|
+
this.graph.deleteNode(node[INTERNAL_ID])
|
|
1125
|
+
return this.wrapNode(comp.id)
|
|
1126
|
+
}
|
|
1127
|
+
|
|
1128
|
+
// --- Variables ---
|
|
1129
|
+
|
|
1130
|
+
getVariableById(id: string): Variable | null {
|
|
1131
|
+
return this.graph.variables.get(id) ?? null
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
getLocalVariables(type?: string): Variable[] {
|
|
1135
|
+
const vars = [...this.graph.variables.values()]
|
|
1136
|
+
if (type) return vars.filter((v) => v.type === type)
|
|
1137
|
+
return vars
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
getLocalVariableCollections(): VariableCollection[] {
|
|
1141
|
+
return [...this.graph.variableCollections.values()]
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
getVariableCollectionById(id: string): VariableCollection | null {
|
|
1145
|
+
return this.graph.variableCollections.get(id) ?? null
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
// --- Variable/Collection CRUD ---
|
|
1149
|
+
|
|
1150
|
+
createVariable(
|
|
1151
|
+
name: string,
|
|
1152
|
+
type: VariableType,
|
|
1153
|
+
collectionId: string,
|
|
1154
|
+
value?: VariableValue
|
|
1155
|
+
): Variable {
|
|
1156
|
+
return this.graph.createVariable(name, type, collectionId, value)
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1159
|
+
setVariableValue(variableId: string, modeId: string, value: VariableValue): void {
|
|
1160
|
+
const variable = this.graph.variables.get(variableId)
|
|
1161
|
+
if (!variable) throw new Error(`Variable "${variableId}" not found`)
|
|
1162
|
+
variable.valuesByMode[modeId] = value
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
deleteVariable(id: string): void {
|
|
1166
|
+
this.graph.removeVariable(id)
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
createVariableCollection(name: string): VariableCollection {
|
|
1170
|
+
return this.graph.createCollection(name)
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1173
|
+
deleteVariableCollection(id: string): void {
|
|
1174
|
+
this.graph.removeCollection(id)
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
bindVariable(nodeId: string, field: string, variableId: string): void {
|
|
1178
|
+
this.graph.bindVariable(nodeId, field, variableId)
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
unbindVariable(nodeId: string, field: string): void {
|
|
1182
|
+
this.graph.unbindVariable(nodeId, field)
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
// --- Boolean Operations ---
|
|
1186
|
+
|
|
1187
|
+
booleanOperation(
|
|
1188
|
+
operation: 'UNION' | 'SUBTRACT' | 'INTERSECT' | 'EXCLUDE',
|
|
1189
|
+
nodeIds: string[]
|
|
1190
|
+
): FigmaNodeProxy {
|
|
1191
|
+
if (nodeIds.length < 2) throw new Error('Need at least 2 nodes for boolean operation')
|
|
1192
|
+
const nodes = nodeIds.map((id) => this.graph.getNode(id))
|
|
1193
|
+
const first = nodes[0]
|
|
1194
|
+
if (!first || nodes.some((n) => !n)) throw new Error('One or more nodes not found')
|
|
1195
|
+
const parentId = first.parentId ?? this._currentPageId
|
|
1196
|
+
const group = this.graph.createNode('GROUP', parentId, {
|
|
1197
|
+
name: `Boolean ${operation.toLowerCase()}`,
|
|
1198
|
+
x: first.x,
|
|
1199
|
+
y: first.y,
|
|
1200
|
+
width: first.width,
|
|
1201
|
+
height: first.height
|
|
1202
|
+
})
|
|
1203
|
+
for (const id of nodeIds) {
|
|
1204
|
+
this.graph.reparentNode(id, group.id)
|
|
1205
|
+
}
|
|
1206
|
+
return this.wrapNode(group.id)
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
// --- Flatten ---
|
|
1210
|
+
|
|
1211
|
+
flattenNode(nodeIds: string[]): FigmaNodeProxy {
|
|
1212
|
+
if (nodeIds.length === 0) throw new Error('Need at least 1 node to flatten')
|
|
1213
|
+
const first = this.graph.getNode(nodeIds[0])
|
|
1214
|
+
if (!first) throw new Error('Node not found')
|
|
1215
|
+
const parentId = first.parentId ?? this._currentPageId
|
|
1216
|
+
const vector = this.graph.createNode('VECTOR', parentId, {
|
|
1217
|
+
name: 'Flatten',
|
|
1218
|
+
x: first.x,
|
|
1219
|
+
y: first.y,
|
|
1220
|
+
width: first.width,
|
|
1221
|
+
height: first.height,
|
|
1222
|
+
fills: copyFills(first.fills)
|
|
1223
|
+
})
|
|
1224
|
+
for (const id of nodeIds) {
|
|
1225
|
+
this.graph.deleteNode(id)
|
|
1226
|
+
}
|
|
1227
|
+
return this.wrapNode(vector.id)
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
// --- Viewport ---
|
|
1231
|
+
|
|
1232
|
+
private _viewport = { x: 0, y: 0, zoom: 1 }
|
|
1233
|
+
|
|
1234
|
+
get viewport(): { center: Vector; zoom: number; scrollAndZoomIntoView: (nodes: readonly { absoluteBoundingBox: Rect }[]) => void } {
|
|
1235
|
+
return {
|
|
1236
|
+
center: { x: this._viewport.x, y: this._viewport.y },
|
|
1237
|
+
zoom: this._viewport.zoom,
|
|
1238
|
+
scrollAndZoomIntoView: (nodes) => {
|
|
1239
|
+
let minX = Infinity
|
|
1240
|
+
let minY = Infinity
|
|
1241
|
+
let maxX = -Infinity
|
|
1242
|
+
let maxY = -Infinity
|
|
1243
|
+
for (const node of nodes) {
|
|
1244
|
+
const b = node.absoluteBoundingBox
|
|
1245
|
+
minX = Math.min(minX, b.x)
|
|
1246
|
+
minY = Math.min(minY, b.y)
|
|
1247
|
+
maxX = Math.max(maxX, b.x + b.width)
|
|
1248
|
+
maxY = Math.max(maxY, b.y + b.height)
|
|
1249
|
+
}
|
|
1250
|
+
if (minX === Infinity) return
|
|
1251
|
+
|
|
1252
|
+
const padding = 80
|
|
1253
|
+
const contentW = maxX - minX + padding * 2
|
|
1254
|
+
const contentH = maxY - minY + padding * 2
|
|
1255
|
+
const viewW = typeof window !== 'undefined' ? window.innerWidth : 1280
|
|
1256
|
+
const viewH = typeof window !== 'undefined' ? window.innerHeight : 720
|
|
1257
|
+
const zoom = Math.min(viewW / contentW, viewH / contentH, 1)
|
|
1258
|
+
this._viewport = { x: (minX + maxX) / 2, y: (minY + maxY) / 2, zoom }
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
set viewport(v: { center: Vector; zoom: number }) {
|
|
1264
|
+
this._viewport = { x: v.center.x, y: v.center.y, zoom: v.zoom }
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
createImage(data: Uint8Array): { hash: string } {
|
|
1268
|
+
const hash = computeImageHash(data)
|
|
1269
|
+
this.graph.images.set(hash, data)
|
|
1270
|
+
return { hash }
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
// --- Stubs ---
|
|
1274
|
+
|
|
1275
|
+
async loadFontAsync(_fontName: FigmaFontName): Promise<void> {
|
|
1276
|
+
// No-op: we don't gate text editing on font loading
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
notify(message: string): { cancel: () => void } {
|
|
1280
|
+
if (typeof console !== 'undefined') console.log(`[figma.notify] ${message}`)
|
|
1281
|
+
// eslint-disable-next-line no-empty-function
|
|
1282
|
+
return { cancel() {} }
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1285
|
+
// eslint-disable-next-line no-empty-function
|
|
1286
|
+
commitUndo(): void {}
|
|
1287
|
+
// eslint-disable-next-line no-empty-function
|
|
1288
|
+
triggerUndo(): void {}
|
|
1289
|
+
|
|
1290
|
+
exportImage?: (
|
|
1291
|
+
nodeIds: string[],
|
|
1292
|
+
options: { scale?: number; format?: 'PNG' | 'JPG' | 'WEBP'; quality?: number }
|
|
1293
|
+
) => Promise<Uint8Array | null>
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1296
|
+
export { FigmaNodeProxy }
|
|
1297
|
+
export type { FigmaFontName }
|