@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
|
@@ -0,0 +1,682 @@
|
|
|
1
|
+
import type { SceneGraph, SceneNode, GeometryPath } from '../scene-graph'
|
|
2
|
+
import { guidToString, convertOverrideToProps, resolveGeometryPaths } from './kiwi-convert'
|
|
3
|
+
import { copyFills, copyStrokes, copyEffects, copyStyleRuns, copyGeometryPaths } from '../copy'
|
|
4
|
+
import type { GUID } from './codec'
|
|
5
|
+
import type { Matrix, Vector } from '../types'
|
|
6
|
+
|
|
7
|
+
interface SymbolOverride {
|
|
8
|
+
guidPath?: { guids?: GUID[] }
|
|
9
|
+
overriddenSymbolID?: GUID
|
|
10
|
+
componentPropAssignments?: ComponentPropAssignment[]
|
|
11
|
+
[key: string]: unknown
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface SymbolData {
|
|
15
|
+
symbolID?: GUID
|
|
16
|
+
symbolOverrides?: SymbolOverride[]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface ComponentPropRef {
|
|
20
|
+
defID?: GUID
|
|
21
|
+
componentPropNodeField: string
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
interface ComponentPropAssignment {
|
|
25
|
+
defID?: GUID
|
|
26
|
+
value: { boolValue?: boolean; textValue?: string; guidValue?: GUID }
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface DerivedSymbolOverride {
|
|
30
|
+
guidPath?: { guids?: GUID[] }
|
|
31
|
+
size?: Vector
|
|
32
|
+
transform?: Matrix
|
|
33
|
+
fillGeometry?: Array<{ windingRule?: string; commandsBlob?: number }>
|
|
34
|
+
strokeGeometry?: Array<{ windingRule?: string; commandsBlob?: number }>
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface InstanceNodeChange {
|
|
38
|
+
type?: string
|
|
39
|
+
guid?: GUID
|
|
40
|
+
overrideKey?: GUID
|
|
41
|
+
symbolData?: SymbolData
|
|
42
|
+
componentPropRefs?: ComponentPropRef[]
|
|
43
|
+
componentPropAssignments?: ComponentPropAssignment[]
|
|
44
|
+
derivedSymbolData?: DerivedSymbolOverride[]
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Populate empty instances from their components and apply symbol overrides.
|
|
49
|
+
*
|
|
50
|
+
* Shared between .fig file import and clipboard paste. Both paths produce
|
|
51
|
+
* a SceneGraph with INSTANCE nodes whose componentId references have been
|
|
52
|
+
* remapped to graph node IDs but whose children may be missing and whose
|
|
53
|
+
* overrides have not yet been applied.
|
|
54
|
+
*
|
|
55
|
+
* @param graph – the SceneGraph (mutated in place)
|
|
56
|
+
* @param changeMap – figmaGuid → raw kiwi node change (for overrideKey + symbolData)
|
|
57
|
+
* @param guidToNodeId – figmaGuid → graph node ID
|
|
58
|
+
*/
|
|
59
|
+
export function populateAndApplyOverrides(
|
|
60
|
+
graph: SceneGraph,
|
|
61
|
+
changeMap: Map<string, InstanceNodeChange>,
|
|
62
|
+
guidToNodeId: Map<string, string>,
|
|
63
|
+
blobs: Uint8Array[] = []
|
|
64
|
+
): void {
|
|
65
|
+
// Work-queue population: seed with empty instances, then discover newly
|
|
66
|
+
// cloned nested instances by walking the subtree (avoids full graph scan per round).
|
|
67
|
+
const populateQueue: string[] = []
|
|
68
|
+
for (const node of graph.getAllNodes()) {
|
|
69
|
+
if (node.type === 'INSTANCE' && node.componentId && node.childIds.length === 0) {
|
|
70
|
+
populateQueue.push(node.id)
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function collectEmptyInstances(parentId: string, out: string[]) {
|
|
75
|
+
const parent = graph.getNode(parentId)
|
|
76
|
+
if (!parent) return
|
|
77
|
+
for (const childId of parent.childIds) {
|
|
78
|
+
const child = graph.getNode(childId)
|
|
79
|
+
if (!child) continue
|
|
80
|
+
if (child.type === 'INSTANCE' && child.componentId && child.childIds.length === 0) {
|
|
81
|
+
out.push(child.id)
|
|
82
|
+
} else if (child.childIds.length > 0) {
|
|
83
|
+
collectEmptyInstances(childId, out)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
while (populateQueue.length > 0) {
|
|
89
|
+
const nodeId = populateQueue.pop()
|
|
90
|
+
if (!nodeId) continue
|
|
91
|
+
const node = graph.getNode(nodeId)
|
|
92
|
+
if (node?.type !== 'INSTANCE' || !node.componentId || node.childIds.length > 0) continue
|
|
93
|
+
const comp = graph.getNode(node.componentId)
|
|
94
|
+
if (comp && comp.childIds.length > 0) {
|
|
95
|
+
graph.populateInstanceChildren(nodeId, node.componentId)
|
|
96
|
+
collectEmptyInstances(nodeId, populateQueue)
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Build overrideKey → figmaGuid map
|
|
101
|
+
const overrideKeyToGuid = new Map<string, string>()
|
|
102
|
+
for (const [id, nc] of changeMap) {
|
|
103
|
+
if (nc.overrideKey) overrideKeyToGuid.set(guidToString(nc.overrideKey), id)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Reverse map: graph node ID → figma GUID (used by getComponentRoot kiwi fallback)
|
|
107
|
+
const nodeIdToGuid = new Map<string, string>()
|
|
108
|
+
for (const [figmaId, nodeId] of guidToNodeId) {
|
|
109
|
+
nodeIdToGuid.set(nodeId, figmaId)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Pre-compute componentId root for every node while all internal page nodes
|
|
113
|
+
// are still alive. After overrides, instance swaps delete intermediate clones,
|
|
114
|
+
// breaking the chain. DSD resolution uses this to match across clone levels.
|
|
115
|
+
const preComputedRoot = new Map<string, string>()
|
|
116
|
+
function getPreComputedRoot(nodeId: string, depth = 0): string {
|
|
117
|
+
if (preComputedRoot.has(nodeId)) return preComputedRoot.get(nodeId) ?? nodeId
|
|
118
|
+
if (depth > 20) return nodeId
|
|
119
|
+
const node = graph.getNode(nodeId)
|
|
120
|
+
if (node?.componentId && node.componentId !== nodeId) {
|
|
121
|
+
const root = getPreComputedRoot(node.componentId, depth + 1)
|
|
122
|
+
preComputedRoot.set(nodeId, root)
|
|
123
|
+
return root
|
|
124
|
+
}
|
|
125
|
+
preComputedRoot.set(nodeId, nodeId)
|
|
126
|
+
return nodeId
|
|
127
|
+
}
|
|
128
|
+
for (const node of graph.getAllNodes()) {
|
|
129
|
+
if (node.componentId) getPreComputedRoot(node.id)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Component root resolution (walks componentId chain to the ultimate source)
|
|
133
|
+
const componentIdRoot = new Map<string, string>()
|
|
134
|
+
function getComponentRoot(nodeId: string, depth = 0): string {
|
|
135
|
+
if (componentIdRoot.has(nodeId)) return componentIdRoot.get(nodeId) ?? nodeId
|
|
136
|
+
if (depth > 20) {
|
|
137
|
+
componentIdRoot.set(nodeId, nodeId)
|
|
138
|
+
return nodeId
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Try graph first
|
|
142
|
+
const node = graph.getNode(nodeId)
|
|
143
|
+
if (node?.componentId) {
|
|
144
|
+
const root = getComponentRoot(node.componentId, depth + 1)
|
|
145
|
+
componentIdRoot.set(nodeId, root)
|
|
146
|
+
return root
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// For deleted nodes (internal page), resolve via kiwi symbolData
|
|
150
|
+
const figmaId = nodeIdToGuid.get(nodeId)
|
|
151
|
+
if (figmaId) {
|
|
152
|
+
const nc = changeMap.get(figmaId)
|
|
153
|
+
const symId = nc?.symbolData?.symbolID
|
|
154
|
+
if (symId) {
|
|
155
|
+
const compNodeId = guidToNodeId.get(guidToString(symId))
|
|
156
|
+
if (compNodeId && compNodeId !== nodeId) {
|
|
157
|
+
const root = getComponentRoot(compNodeId, depth + 1)
|
|
158
|
+
componentIdRoot.set(nodeId, root)
|
|
159
|
+
return root
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
componentIdRoot.set(nodeId, nodeId)
|
|
165
|
+
return nodeId
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function findNodeByComponentId(parentId: string, componentId: string): string | null {
|
|
169
|
+
const parent = graph.getNode(parentId)
|
|
170
|
+
if (!parent) return null
|
|
171
|
+
|
|
172
|
+
// Pass 1: exact componentId match on direct children
|
|
173
|
+
for (const childId of parent.childIds) {
|
|
174
|
+
const child = graph.getNode(childId)
|
|
175
|
+
if (child?.componentId === componentId) return childId
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Pass 2: root match — but only if exactly one child shares the root
|
|
179
|
+
// (multiple siblings with the same root are ambiguous)
|
|
180
|
+
const targetRoot = preComputedRoot.get(componentId) ?? getComponentRoot(componentId)
|
|
181
|
+
if (targetRoot) {
|
|
182
|
+
let rootMatch: string | null = null
|
|
183
|
+
let ambiguous = false
|
|
184
|
+
for (const childId of parent.childIds) {
|
|
185
|
+
const child = graph.getNode(childId)
|
|
186
|
+
if (!child?.componentId) continue
|
|
187
|
+
const childRoot = preComputedRoot.get(child.componentId) ?? getComponentRoot(child.componentId)
|
|
188
|
+
if (childRoot === targetRoot) {
|
|
189
|
+
if (rootMatch) { ambiguous = true; break }
|
|
190
|
+
rootMatch = childId
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
if (rootMatch && !ambiguous) return rootMatch
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Pass 3: recurse into children
|
|
197
|
+
for (const childId of parent.childIds) {
|
|
198
|
+
const deep = findNodeByComponentId(childId, componentId)
|
|
199
|
+
if (deep) return deep
|
|
200
|
+
}
|
|
201
|
+
return null
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function resolveOverrideTarget(instanceId: string, guids: GUID[]): string | null {
|
|
205
|
+
let currentId = instanceId
|
|
206
|
+
for (const guid of guids) {
|
|
207
|
+
const key = guidToString(guid)
|
|
208
|
+
const figmaGuid = overrideKeyToGuid.get(key) ?? key
|
|
209
|
+
const remapped = guidToNodeId.get(figmaGuid)
|
|
210
|
+
if (!remapped) return null
|
|
211
|
+
|
|
212
|
+
// The override may target the current node itself (when it's an instance
|
|
213
|
+
// cloned from the component the override points to)
|
|
214
|
+
const current = graph.getNode(currentId)
|
|
215
|
+
if (current?.componentId === remapped) {
|
|
216
|
+
continue
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const found = findNodeByComponentId(currentId, remapped)
|
|
220
|
+
if (!found) return null
|
|
221
|
+
currentId = found
|
|
222
|
+
}
|
|
223
|
+
return currentId
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Apply component property assignments (boolean visibility, instance swap).
|
|
227
|
+
// Component children reference property definitions via componentPropRefs.
|
|
228
|
+
// Instances set values via componentPropAssignments. After cloning, we walk
|
|
229
|
+
// each instance's descendants and apply the assignments.
|
|
230
|
+
|
|
231
|
+
function findPropRefs(nodeId: string, propRefsMap: Map<string, ComponentPropRef[]>): ComponentPropRef[] | undefined {
|
|
232
|
+
let sourceId: string | undefined = nodeId
|
|
233
|
+
for (let depth = 0; sourceId && depth < 10; depth++) {
|
|
234
|
+
const figmaId = nodeIdToGuid.get(sourceId)
|
|
235
|
+
if (figmaId) {
|
|
236
|
+
const refs = propRefsMap.get(figmaId)
|
|
237
|
+
if (refs) return refs
|
|
238
|
+
}
|
|
239
|
+
const node = graph.getNode(sourceId)
|
|
240
|
+
const nextId = node?.componentId ?? undefined
|
|
241
|
+
if (nextId === sourceId) break
|
|
242
|
+
sourceId = nextId
|
|
243
|
+
}
|
|
244
|
+
return undefined
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function repopulateInstance(nodeId: string, compId: string) {
|
|
248
|
+
const node = graph.getNode(nodeId)
|
|
249
|
+
if (node?.type !== 'INSTANCE') return
|
|
250
|
+
|
|
251
|
+
for (const childId of Array.from(node.childIds)) graph.deleteNode(childId)
|
|
252
|
+
graph.updateNode(nodeId, { componentId: compId })
|
|
253
|
+
const comp = graph.getNode(compId)
|
|
254
|
+
if (comp && comp.childIds.length > 0) {
|
|
255
|
+
graph.populateInstanceChildren(nodeId, compId)
|
|
256
|
+
}
|
|
257
|
+
componentIdRoot.clear()
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function assignmentsToValueMap(assignments: ComponentPropAssignment[]): Map<string, ComponentPropAssignment['value']> {
|
|
261
|
+
const valueByDef = new Map<string, ComponentPropAssignment['value']>()
|
|
262
|
+
for (const a of assignments) {
|
|
263
|
+
if (a.defID) valueByDef.set(guidToString(a.defID), a.value)
|
|
264
|
+
}
|
|
265
|
+
return valueByDef
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
function applyInstanceDirectAssignments(
|
|
269
|
+
assignmentSources: Map<string, ComponentPropAssignment[]>,
|
|
270
|
+
propRefsMap: Map<string, ComponentPropRef[]>
|
|
271
|
+
) {
|
|
272
|
+
for (const node of graph.getAllNodes()) {
|
|
273
|
+
if (node.type !== 'INSTANCE') continue
|
|
274
|
+
// Apply assignments from the instance's own kiwi data first
|
|
275
|
+
const ownFigmaId = nodeIdToGuid.get(node.id)
|
|
276
|
+
if (ownFigmaId) {
|
|
277
|
+
const ownAssignments = assignmentSources.get(ownFigmaId)
|
|
278
|
+
if (ownAssignments) {
|
|
279
|
+
applyPropAssignments(node.id, assignmentsToValueMap(ownAssignments), propRefsMap)
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Also apply from cloned instance sources — after population, cloned
|
|
284
|
+
// instances have componentId pointing to the original kiwi node
|
|
285
|
+
if (!node.componentId) continue
|
|
286
|
+
const sourceFigmaId = nodeIdToGuid.get(node.componentId)
|
|
287
|
+
if (!sourceFigmaId) continue
|
|
288
|
+
const assignments = assignmentSources.get(sourceFigmaId)
|
|
289
|
+
if (!assignments) continue
|
|
290
|
+
|
|
291
|
+
applyPropAssignments(node.id, assignmentsToValueMap(assignments), propRefsMap)
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function applySymbolOverrideAssignments(propRefsMap: Map<string, ComponentPropRef[]>) {
|
|
296
|
+
for (const [figmaId, nc] of changeMap) {
|
|
297
|
+
const instanceNodeId = guidToNodeId.get(figmaId)
|
|
298
|
+
if (!instanceNodeId) continue
|
|
299
|
+
if (graph.getNode(instanceNodeId)?.type !== 'INSTANCE') continue
|
|
300
|
+
|
|
301
|
+
const overrides = nc.symbolData?.symbolOverrides
|
|
302
|
+
if (!overrides) continue
|
|
303
|
+
for (const ov of overrides) {
|
|
304
|
+
if (!ov.componentPropAssignments?.length) continue
|
|
305
|
+
|
|
306
|
+
const guids = ov.guidPath?.guids
|
|
307
|
+
if (!guids?.length) continue
|
|
308
|
+
|
|
309
|
+
const targetId = resolveOverrideTarget(instanceNodeId, guids)
|
|
310
|
+
if (!targetId) continue
|
|
311
|
+
|
|
312
|
+
applyPropAssignments(targetId, assignmentsToValueMap(ov.componentPropAssignments), propRefsMap)
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function applyComponentProperties() {
|
|
318
|
+
const propRefsMap = new Map<string, ComponentPropRef[]>()
|
|
319
|
+
for (const [figmaId, nc] of changeMap) {
|
|
320
|
+
if (nc.componentPropRefs?.length) {
|
|
321
|
+
propRefsMap.set(figmaId, nc.componentPropRefs)
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
if (propRefsMap.size === 0) return
|
|
325
|
+
|
|
326
|
+
const assignmentSources = new Map<string, ComponentPropAssignment[]>()
|
|
327
|
+
for (const [figmaId, nc] of changeMap) {
|
|
328
|
+
if (nc.componentPropAssignments?.length) {
|
|
329
|
+
assignmentSources.set(figmaId, nc.componentPropAssignments)
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
applyInstanceDirectAssignments(assignmentSources, propRefsMap)
|
|
334
|
+
applySymbolOverrideAssignments(propRefsMap)
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function applyPropAssignments(
|
|
338
|
+
parentId: string,
|
|
339
|
+
valueByDef: Map<string, ComponentPropAssignment['value']>,
|
|
340
|
+
propRefsMap: Map<string, ComponentPropRef[]>
|
|
341
|
+
) {
|
|
342
|
+
const parent = graph.getNode(parentId)
|
|
343
|
+
if (!parent) return
|
|
344
|
+
|
|
345
|
+
for (const childId of parent.childIds) {
|
|
346
|
+
const child = graph.getNode(childId)
|
|
347
|
+
if (!child?.componentId) {
|
|
348
|
+
applyPropAssignments(childId, valueByDef, propRefsMap)
|
|
349
|
+
continue
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const refs = findPropRefs(child.componentId, propRefsMap)
|
|
353
|
+
if (refs) {
|
|
354
|
+
for (const ref of refs) {
|
|
355
|
+
if (!ref.defID) continue
|
|
356
|
+
const val = valueByDef.get(guidToString(ref.defID))
|
|
357
|
+
if (!val) continue
|
|
358
|
+
|
|
359
|
+
if (ref.componentPropNodeField === 'VISIBLE' && val.boolValue !== undefined) {
|
|
360
|
+
graph.updateNode(childId, { visible: val.boolValue })
|
|
361
|
+
} else if (ref.componentPropNodeField === 'OVERRIDDEN_SYMBOL_ID') {
|
|
362
|
+
const swapId = val.textValue ?? (val.guidValue ? guidToString(val.guidValue) : undefined)
|
|
363
|
+
if (!swapId) continue
|
|
364
|
+
const newCompId = guidToNodeId.get(swapId)
|
|
365
|
+
if (newCompId) repopulateInstance(childId, newCompId)
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
applyPropAssignments(childId, valueByDef, propRefsMap)
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
// Apply derivedSymbolData — pre-computed sizes for the current set of
|
|
375
|
+
// component property values. Uses the same guidPath resolution as
|
|
376
|
+
// symbolOverrides.
|
|
377
|
+
function scaleGeometryBlobs(geom: GeometryPath[], sx: number, sy: number): GeometryPath[] {
|
|
378
|
+
if (sx === 1 && sy === 1) return geom
|
|
379
|
+
return geom.map((g) => {
|
|
380
|
+
const src = g.commandsBlob
|
|
381
|
+
const scaled = new Uint8Array(src.length)
|
|
382
|
+
scaled.set(src)
|
|
383
|
+
const dv = new DataView(scaled.buffer, scaled.byteOffset, scaled.byteLength)
|
|
384
|
+
let o = 0
|
|
385
|
+
while (o < scaled.length) {
|
|
386
|
+
const cmd = scaled[o++]
|
|
387
|
+
if (cmd === 0) continue
|
|
388
|
+
const coords = cmd === 1 || cmd === 2 ? 1 : (cmd === 4 ? 3 : -1)
|
|
389
|
+
if (coords < 0) {
|
|
390
|
+
console.warn(`scaleGeometryBlobs: unknown path command ${cmd} at offset ${o - 1}`)
|
|
391
|
+
break
|
|
392
|
+
}
|
|
393
|
+
for (let i = 0; i < coords; i++) {
|
|
394
|
+
dv.setFloat32(o, dv.getFloat32(o, true) * sx, true)
|
|
395
|
+
dv.setFloat32(o + 4, dv.getFloat32(o + 4, true) * sy, true)
|
|
396
|
+
o += 8
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
return { windingRule: g.windingRule, commandsBlob: scaled }
|
|
400
|
+
})
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function resolveDsdGeometry(
|
|
404
|
+
d: DerivedSymbolOverride,
|
|
405
|
+
target: SceneNode
|
|
406
|
+
): Pick<Partial<SceneNode>, 'fillGeometry' | 'strokeGeometry'> {
|
|
407
|
+
const result: Pick<Partial<SceneNode>, 'fillGeometry' | 'strokeGeometry'> = {}
|
|
408
|
+
const fg = resolveGeometryPaths(d.fillGeometry, blobs)
|
|
409
|
+
const sg = resolveGeometryPaths(d.strokeGeometry, blobs)
|
|
410
|
+
if (fg.length > 0) {
|
|
411
|
+
result.fillGeometry = fg
|
|
412
|
+
} else if (d.size && target.fillGeometry.length > 0 && target.width > 0 && target.height > 0) {
|
|
413
|
+
result.fillGeometry = scaleGeometryBlobs(target.fillGeometry, d.size.x / target.width, d.size.y / target.height)
|
|
414
|
+
}
|
|
415
|
+
if (sg.length > 0) {
|
|
416
|
+
result.strokeGeometry = sg
|
|
417
|
+
} else if (d.size && target.strokeGeometry.length > 0 && target.width > 0 && target.height > 0) {
|
|
418
|
+
result.strokeGeometry = scaleGeometryBlobs(target.strokeGeometry, d.size.x / target.width, d.size.y / target.height)
|
|
419
|
+
}
|
|
420
|
+
return result
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function resolveDsdUpdates(): { dsdModified: Set<string>; dsdSizeSet: Set<string> } {
|
|
424
|
+
const dsdModified = new Set<string>()
|
|
425
|
+
const dsdSizeSet = new Set<string>()
|
|
426
|
+
|
|
427
|
+
for (const [ncId, nc] of changeMap) {
|
|
428
|
+
if (nc.type !== 'INSTANCE') continue
|
|
429
|
+
const derived = nc.derivedSymbolData
|
|
430
|
+
if (!derived?.length) continue
|
|
431
|
+
|
|
432
|
+
const nodeId = guidToNodeId.get(ncId)
|
|
433
|
+
if (!nodeId) continue
|
|
434
|
+
|
|
435
|
+
for (const d of derived) {
|
|
436
|
+
const guids = d.guidPath?.guids
|
|
437
|
+
if (!guids?.length) continue
|
|
438
|
+
|
|
439
|
+
const targetId = resolveOverrideTarget(nodeId, guids)
|
|
440
|
+
if (!targetId) continue
|
|
441
|
+
|
|
442
|
+
const target = graph.getNode(targetId)
|
|
443
|
+
if (!target) continue
|
|
444
|
+
|
|
445
|
+
const updates: Partial<SceneNode> = {}
|
|
446
|
+
if (d.size) {
|
|
447
|
+
updates.width = d.size.x
|
|
448
|
+
updates.height = d.size.y
|
|
449
|
+
}
|
|
450
|
+
if (d.transform) {
|
|
451
|
+
updates.x = d.transform.m02
|
|
452
|
+
updates.y = d.transform.m12
|
|
453
|
+
}
|
|
454
|
+
Object.assign(updates, resolveDsdGeometry(d, target))
|
|
455
|
+
|
|
456
|
+
if (Object.keys(updates).length > 0) {
|
|
457
|
+
graph.updateNode(targetId, updates)
|
|
458
|
+
dsdModified.add(targetId)
|
|
459
|
+
if (d.size) dsdSizeSet.add(targetId)
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return { dsdModified, dsdSizeSet }
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
// Propagate DSD changes through clone chains — each clone should match
|
|
468
|
+
// its source for size/position/geometry. Nodes whose size was explicitly
|
|
469
|
+
// set by DSD keep their own values; others inherit from their source.
|
|
470
|
+
function propagateDsdChanges(dsdModified: Set<string>, dsdSizeSet: Set<string>) {
|
|
471
|
+
if (dsdModified.size === 0) return
|
|
472
|
+
|
|
473
|
+
const clonesOf = buildClonesMap()
|
|
474
|
+
|
|
475
|
+
const queue = [...dsdModified]
|
|
476
|
+
const visited = new Set<string>()
|
|
477
|
+
for (let sourceId = queue.shift(); sourceId !== undefined; sourceId = queue.shift()) {
|
|
478
|
+
const source = graph.getNode(sourceId)
|
|
479
|
+
if (!source) continue
|
|
480
|
+
const clones = clonesOf.get(sourceId)
|
|
481
|
+
if (!clones) continue
|
|
482
|
+
for (const cloneId of clones) {
|
|
483
|
+
if (visited.has(cloneId)) continue
|
|
484
|
+
visited.add(cloneId)
|
|
485
|
+
const clone = graph.getNode(cloneId)
|
|
486
|
+
if (!clone) continue
|
|
487
|
+
if (!dsdSizeSet.has(cloneId)) {
|
|
488
|
+
const cu: Partial<SceneNode> = {}
|
|
489
|
+
if (source.width !== clone.width) cu.width = source.width
|
|
490
|
+
if (source.height !== clone.height) cu.height = source.height
|
|
491
|
+
if (source.x !== clone.x) cu.x = source.x
|
|
492
|
+
if (source.y !== clone.y) cu.y = source.y
|
|
493
|
+
if (source.fillGeometry !== clone.fillGeometry) cu.fillGeometry = copyGeometryPaths(source.fillGeometry)
|
|
494
|
+
if (source.strokeGeometry !== clone.strokeGeometry) cu.strokeGeometry = copyGeometryPaths(source.strokeGeometry)
|
|
495
|
+
if (Object.keys(cu).length > 0) graph.updateNode(cloneId, cu)
|
|
496
|
+
}
|
|
497
|
+
queue.push(cloneId)
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
function applyDerivedSymbolData() {
|
|
503
|
+
const { dsdModified, dsdSizeSet } = resolveDsdUpdates()
|
|
504
|
+
propagateDsdChanges(dsdModified, dsdSizeSet)
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
function applySymbolOverrides(): Set<string> {
|
|
508
|
+
const overriddenNodes = new Set<string>()
|
|
509
|
+
componentIdRoot.clear()
|
|
510
|
+
|
|
511
|
+
for (const [ncId, nc] of changeMap) {
|
|
512
|
+
if (nc.type !== 'INSTANCE') continue
|
|
513
|
+
const sd = nc.symbolData
|
|
514
|
+
if (!sd?.symbolOverrides?.length) continue
|
|
515
|
+
|
|
516
|
+
const nodeId = guidToNodeId.get(ncId)
|
|
517
|
+
if (!nodeId) continue
|
|
518
|
+
|
|
519
|
+
for (const ov of sd.symbolOverrides) {
|
|
520
|
+
const guids = ov.guidPath?.guids
|
|
521
|
+
if (!guids?.length) continue
|
|
522
|
+
|
|
523
|
+
const targetId = resolveOverrideTarget(nodeId, guids)
|
|
524
|
+
if (!targetId) continue
|
|
525
|
+
|
|
526
|
+
overriddenNodes.add(targetId)
|
|
527
|
+
|
|
528
|
+
if (ov.overriddenSymbolID) {
|
|
529
|
+
const newCompId = guidToNodeId.get(guidToString(ov.overriddenSymbolID))
|
|
530
|
+
if (newCompId) repopulateInstance(targetId, newCompId)
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const { guidPath: _, overriddenSymbolID: _s, componentPropAssignments: _c, ...fields } = ov
|
|
534
|
+
if (Object.keys(fields).length === 0) continue
|
|
535
|
+
|
|
536
|
+
const updates = convertOverrideToProps(fields as Record<string, unknown>)
|
|
537
|
+
if (Object.keys(updates).length > 0) {
|
|
538
|
+
graph.updateNode(targetId, updates)
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
return overriddenNodes
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function syncNodeProps(source: SceneNode, target: SceneNode) {
|
|
546
|
+
const updates: Partial<SceneNode> = {}
|
|
547
|
+
if (source.text !== target.text) updates.text = source.text
|
|
548
|
+
if (source.visible !== target.visible) updates.visible = source.visible
|
|
549
|
+
if (source.opacity !== target.opacity) updates.opacity = source.opacity
|
|
550
|
+
if (source.fills !== target.fills) updates.fills = copyFills(source.fills)
|
|
551
|
+
if (source.strokes !== target.strokes) updates.strokes = copyStrokes(source.strokes)
|
|
552
|
+
if (source.effects !== target.effects) updates.effects = copyEffects(source.effects)
|
|
553
|
+
if (source.styleRuns !== target.styleRuns) updates.styleRuns = copyStyleRuns(source.styleRuns)
|
|
554
|
+
if (source.layoutGrow !== target.layoutGrow) updates.layoutGrow = source.layoutGrow
|
|
555
|
+
if (source.textAutoResize !== target.textAutoResize) updates.textAutoResize = source.textAutoResize
|
|
556
|
+
if (source.locked !== target.locked) updates.locked = source.locked
|
|
557
|
+
if (Object.keys(updates).length > 0) graph.updateNode(target.id, updates)
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
function syncChildrenDeep(sourceId: string, targetId: string, skip?: Set<string>) {
|
|
561
|
+
const src = graph.getNode(sourceId)
|
|
562
|
+
const tgt = graph.getNode(targetId)
|
|
563
|
+
if (!src || !tgt) return
|
|
564
|
+
const len = Math.min(src.childIds.length, tgt.childIds.length)
|
|
565
|
+
for (let i = 0; i < len; i++) {
|
|
566
|
+
if (skip?.has(tgt.childIds[i])) continue
|
|
567
|
+
const srcNode = graph.getNode(src.childIds[i])
|
|
568
|
+
const tgtNode = graph.getNode(tgt.childIds[i])
|
|
569
|
+
if (!srcNode || !tgtNode || srcNode.type !== tgtNode.type) continue
|
|
570
|
+
syncNodeProps(srcNode, tgtNode)
|
|
571
|
+
syncChildrenDeep(src.childIds[i], tgt.childIds[i], skip)
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
function buildClonesMap(): Map<string, string[]> {
|
|
576
|
+
const clonesOf = new Map<string, string[]>()
|
|
577
|
+
for (const node of graph.getAllNodes()) {
|
|
578
|
+
if (!node.componentId) continue
|
|
579
|
+
let arr = clonesOf.get(node.componentId)
|
|
580
|
+
if (!arr) {
|
|
581
|
+
arr = []
|
|
582
|
+
clonesOf.set(node.componentId, arr)
|
|
583
|
+
}
|
|
584
|
+
arr.push(node.id)
|
|
585
|
+
}
|
|
586
|
+
return clonesOf
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
function expandSeedsToParents(seeds: Set<string>): Set<string> {
|
|
590
|
+
const expandedSeeds = new Set(seeds)
|
|
591
|
+
for (const seedId of seeds) {
|
|
592
|
+
let cur = graph.getNode(seedId)
|
|
593
|
+
while (cur?.parentId) {
|
|
594
|
+
const parent = graph.getNode(cur.parentId)
|
|
595
|
+
if (!parent) break
|
|
596
|
+
if (parent.type === 'INSTANCE' || parent.type === 'COMPONENT') {
|
|
597
|
+
expandedSeeds.add(parent.id)
|
|
598
|
+
}
|
|
599
|
+
cur = parent
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
return expandedSeeds
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
function buildNeedsSyncSet(expandedSeeds: Set<string>, clonesOf: Map<string, string[]>): Set<string> {
|
|
606
|
+
const needsSync = new Set<string>()
|
|
607
|
+
const queue = [...expandedSeeds]
|
|
608
|
+
for (let id = queue.pop(); id !== undefined; id = queue.pop()) {
|
|
609
|
+
const clones = clonesOf.get(id)
|
|
610
|
+
if (!clones) continue
|
|
611
|
+
for (const cloneId of clones) {
|
|
612
|
+
if (needsSync.has(cloneId)) continue
|
|
613
|
+
needsSync.add(cloneId)
|
|
614
|
+
queue.push(cloneId)
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
return needsSync
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
function syncCloneFromSource(sourceId: string, source: SceneNode, node: SceneNode, seeds: Set<string>) {
|
|
621
|
+
syncNodeProps(source, node)
|
|
622
|
+
if (source.childIds.length !== node.childIds.length) {
|
|
623
|
+
const childIds = [...node.childIds]
|
|
624
|
+
for (const childId of childIds) graph.deleteNode(childId)
|
|
625
|
+
if (source.childIds.length > 0) {
|
|
626
|
+
graph.populateInstanceChildren(node.id, sourceId)
|
|
627
|
+
}
|
|
628
|
+
} else if (source.childIds.length > 0 && node.childIds.length > 0) {
|
|
629
|
+
syncChildrenDeep(sourceId, node.id, seeds)
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
function propagateOverridesTransitively(seeds: Set<string>) {
|
|
634
|
+
if (seeds.size === 0) return
|
|
635
|
+
|
|
636
|
+
const clonesOf = buildClonesMap()
|
|
637
|
+
const expandedSeeds = expandSeedsToParents(seeds)
|
|
638
|
+
const needsSync = buildNeedsSyncSet(expandedSeeds, clonesOf)
|
|
639
|
+
|
|
640
|
+
const visited = new Set<string>()
|
|
641
|
+
const syncQueue = [...expandedSeeds]
|
|
642
|
+
for (let sourceId = syncQueue.shift(); sourceId !== undefined; sourceId = syncQueue.shift()) {
|
|
643
|
+
const clones = clonesOf.get(sourceId)
|
|
644
|
+
if (!clones) continue
|
|
645
|
+
const source = graph.getNode(sourceId)
|
|
646
|
+
if (!source) continue
|
|
647
|
+
|
|
648
|
+
for (const cloneId of clones) {
|
|
649
|
+
if (!needsSync.has(cloneId) || visited.has(cloneId)) continue
|
|
650
|
+
visited.add(cloneId)
|
|
651
|
+
const node = graph.getNode(cloneId)
|
|
652
|
+
if (!node) continue
|
|
653
|
+
|
|
654
|
+
// Don't overwrite nodes directly targeted by symbolOverrides
|
|
655
|
+
if (seeds.has(cloneId)) {
|
|
656
|
+
syncQueue.push(cloneId)
|
|
657
|
+
continue
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
syncCloneFromSource(sourceId, source, node, seeds)
|
|
661
|
+
syncQueue.push(cloneId)
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// Order matters:
|
|
667
|
+
// 1. symbolOverrides — set property values and swap instances
|
|
668
|
+
// 2. transitive sync — propagate overrides through clone chains (may
|
|
669
|
+
// repopulate INSTANCE children, wiping any earlier property changes)
|
|
670
|
+
// 3. componentProperties — toggle visibility / swap via prop assignments
|
|
671
|
+
// (must run AFTER sync so repopulated children aren't lost)
|
|
672
|
+
// 4. derivedSymbolData — apply Figma's pre-computed sizes last
|
|
673
|
+
const overriddenNodes = applySymbolOverrides()
|
|
674
|
+
|
|
675
|
+
propagateOverridesTransitively(overriddenNodes)
|
|
676
|
+
|
|
677
|
+
applyComponentProperties()
|
|
678
|
+
|
|
679
|
+
// DSD resolution runs AFTER overrides so guidPaths can reach children
|
|
680
|
+
// of instance-swapped nodes (repopulateInstance replaces children).
|
|
681
|
+
applyDerivedSymbolData()
|
|
682
|
+
}
|