Merge remote-tracking branch 'origin/master' into feat/configurable-snapping-guides
This commit is contained in:
commit
73f0883521
|
|
@ -2,6 +2,10 @@
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Upgrade CanvasKit to 0.41 and migrate renderer geometry to immutable paths built through `PathBuilder`.
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Snap vector points, moved layers, and resized edges to nearby geometry, sibling layer bounds, canvas and frame layout guides, and whole-pixel coordinates with visible alignment guides, fractional-coordinate preservation when pixel snapping is off, and persistent geometry, object, and pixel-grid controls in General settings and the Preferences menu.
|
- Snap vector points, moved layers, and resized edges to nearby geometry, sibling layer bounds, canvas and frame layout guides, and whole-pixel coordinates with visible alignment guides, fractional-coordinate preservation when pixel snapping is off, and persistent geometry, object, and pixel-grid controls in General settings and the Preferences menu.
|
||||||
|
|
|
||||||
94
bun.lock
94
bun.lock
|
|
@ -49,7 +49,7 @@
|
||||||
"@xmldom/xmldom": "^0.9.11",
|
"@xmldom/xmldom": "^0.9.11",
|
||||||
"ai": "^7.0.66",
|
"ai": "^7.0.66",
|
||||||
"aws4fetch": "^1.0.20",
|
"aws4fetch": "^1.0.20",
|
||||||
"canvaskit-wasm": "^0.40.0",
|
"canvaskit-wasm": "^0.41.1",
|
||||||
"culori": "^4.0.2",
|
"culori": "^4.0.2",
|
||||||
"dedent": "^1.7.2",
|
"dedent": "^1.7.2",
|
||||||
"es-toolkit": "^1.51.0",
|
"es-toolkit": "^1.51.0",
|
||||||
|
|
@ -152,7 +152,7 @@
|
||||||
"@open-pencil/mcp": "workspace:*",
|
"@open-pencil/mcp": "workspace:*",
|
||||||
"@open-pencil/scene-graph": "workspace:*",
|
"@open-pencil/scene-graph": "workspace:*",
|
||||||
"agentfmt": "^0.1.3",
|
"agentfmt": "^0.1.3",
|
||||||
"canvaskit-wasm": "^0.40.0",
|
"canvaskit-wasm": "^0.41.1",
|
||||||
"citty": "^0.1.6",
|
"citty": "^0.1.6",
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
@ -172,7 +172,7 @@
|
||||||
"@tauri-apps/api": "^2.11.1",
|
"@tauri-apps/api": "^2.11.1",
|
||||||
"@xmldom/xmldom": "^0.9.11",
|
"@xmldom/xmldom": "^0.9.11",
|
||||||
"acorn": "^8.18.0",
|
"acorn": "^8.18.0",
|
||||||
"canvaskit-wasm": "^0.40.0",
|
"canvaskit-wasm": "^0.41.1",
|
||||||
"culori": "^4.0.2",
|
"culori": "^4.0.2",
|
||||||
"destr": "^2.0.5",
|
"destr": "^2.0.5",
|
||||||
"diff": "^8.0.4",
|
"diff": "^8.0.4",
|
||||||
|
|
@ -339,7 +339,7 @@
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@open-pencil/core": "workspace:*",
|
"@open-pencil/core": "workspace:*",
|
||||||
"canvaskit-wasm": "^0.40.0",
|
"canvaskit-wasm": ">=0.41.1",
|
||||||
"vue": "^3.5.41",
|
"vue": "^3.5.41",
|
||||||
},
|
},
|
||||||
"optionalPeers": [
|
"optionalPeers": [
|
||||||
|
|
@ -366,9 +366,9 @@
|
||||||
|
|
||||||
"@ai-sdk/deepseek": ["@ai-sdk/deepseek@3.0.28", "", { "dependencies": { "@ai-sdk/provider": "4.0.7", "@ai-sdk/provider-utils": "5.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ySiafZL/1KQq8NF49eGWmVRYP4ezBjxAwAlMK+hhTV+9ee37LcCxlSIbURe4C4KFq8kYaTFKsTGI2poLFLOu0w=="],
|
"@ai-sdk/deepseek": ["@ai-sdk/deepseek@3.0.28", "", { "dependencies": { "@ai-sdk/provider": "4.0.7", "@ai-sdk/provider-utils": "5.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ySiafZL/1KQq8NF49eGWmVRYP4ezBjxAwAlMK+hhTV+9ee37LcCxlSIbURe4C4KFq8kYaTFKsTGI2poLFLOu0w=="],
|
||||||
|
|
||||||
"@ai-sdk/gateway": ["@ai-sdk/gateway@4.0.52", "", { "dependencies": { "@ai-sdk/provider": "4.0.7", "@ai-sdk/provider-utils": "5.0.27", "@vercel/oidc": "3.2.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-SXUM8jzzuTUJRq+EOgPd5to6DSx0EKslVn+IVZHbUEX6k/3vCPNrvjckbK26HnNxHU/STxm+zTSJteqrO+7Z0w=="],
|
"@ai-sdk/gateway": ["@ai-sdk/gateway@4.0.53", "", { "dependencies": { "@ai-sdk/provider": "4.0.7", "@ai-sdk/provider-utils": "5.0.27", "@vercel/oidc": "3.2.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-4ZgwJjv/lGA7ywlD/3oYg6XMkIy1VvVKiSRYB83PyLDApwMGXSF+oT7D5lPYJFhNE5Vr3W2H+SwCFuTsbfgn9w=="],
|
||||||
|
|
||||||
"@ai-sdk/google": ["@ai-sdk/google@4.0.44", "", { "dependencies": { "@ai-sdk/provider": "4.0.7", "@ai-sdk/provider-utils": "5.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-bmRTDg06jQD+eX8nf214pET9+Oe8O1+lUIRGbWsGXj9IN2UJkpl1O1x7cvtiboyTtKSLvSRdVtItUfSl8sQ2GA=="],
|
"@ai-sdk/google": ["@ai-sdk/google@4.0.45", "", { "dependencies": { "@ai-sdk/provider": "4.0.7", "@ai-sdk/provider-utils": "5.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-1oLHhc2twSQzm7O8j/HaRWLfBh+tPjQP55d8yXmrZvvopoH6/P7WaDznVJqjouGSof429lR+tYdINkjvUl+8Qg=="],
|
||||||
|
|
||||||
"@ai-sdk/openai": ["@ai-sdk/openai@4.0.42", "", { "dependencies": { "@ai-sdk/provider": "4.0.7", "@ai-sdk/provider-utils": "5.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZxDca6jJalYuXrIGVrw6dnkpz1Io9AWy+/b/wVWIbjigHCbd+zWLpPi8NnK0OFU+U3YCpP+KWfUvEnG5pFhltA=="],
|
"@ai-sdk/openai": ["@ai-sdk/openai@4.0.42", "", { "dependencies": { "@ai-sdk/provider": "4.0.7", "@ai-sdk/provider-utils": "5.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ZxDca6jJalYuXrIGVrw6dnkpz1Io9AWy+/b/wVWIbjigHCbd+zWLpPi8NnK0OFU+U3YCpP+KWfUvEnG5pFhltA=="],
|
||||||
|
|
||||||
|
|
@ -378,7 +378,7 @@
|
||||||
|
|
||||||
"@ai-sdk/valibot": ["@ai-sdk/valibot@3.0.27", "", { "dependencies": { "@ai-sdk/provider-utils": "5.0.27" }, "peerDependencies": { "@valibot/to-json-schema": "^1.3.0", "valibot": "^1.1.0" } }, "sha512-c77tkUqvaivemWbJjjVDCCbSfeRGd/Eg0t0GHQdlsS5GDBog9D7D9Ig/BiTvx0jDnKdGp0qQFs4k4NCP/JILUg=="],
|
"@ai-sdk/valibot": ["@ai-sdk/valibot@3.0.27", "", { "dependencies": { "@ai-sdk/provider-utils": "5.0.27" }, "peerDependencies": { "@valibot/to-json-schema": "^1.3.0", "valibot": "^1.1.0" } }, "sha512-c77tkUqvaivemWbJjjVDCCbSfeRGd/Eg0t0GHQdlsS5GDBog9D7D9Ig/BiTvx0jDnKdGp0qQFs4k4NCP/JILUg=="],
|
||||||
|
|
||||||
"@ai-sdk/vue": ["@ai-sdk/vue@4.0.66", "", { "dependencies": { "@ai-sdk/provider-utils": "5.0.27", "ai": "7.0.66", "swrv": "^1.2.0" }, "peerDependencies": { "vue": "^3.3.4" } }, "sha512-FS+Ir4GUzyAV1fFVwUe1HrrEIsB8XKZO71IrV5ONhXv86PH2DUpFWKOxngssVcAWHtZeEwL8u/7L2KHtNChKpg=="],
|
"@ai-sdk/vue": ["@ai-sdk/vue@4.0.67", "", { "dependencies": { "@ai-sdk/provider-utils": "5.0.27", "ai": "7.0.67", "swrv": "^1.2.0" }, "peerDependencies": { "vue": "^3.3.4" } }, "sha512-81vFZPlH8zxeloo8rOJsh/JI4hxT+4P9VyXzJLO5C3vezbH5suniW+4Ch09gTtblN6Zz2Sqe8PRAc9r2IQEOEA=="],
|
||||||
|
|
||||||
"@andrewbranch/untar.js": ["@andrewbranch/untar.js@1.0.4", "", {}, "sha512-pVXSwPsLuw8IGLo2Di0EaOfsk+ntVvpkk942J/sHYIkwvtKUakEcPh7HBgZ6tuimgzKSEHgCvO4XgQ05DEbwDw=="],
|
"@andrewbranch/untar.js": ["@andrewbranch/untar.js@1.0.4", "", {}, "sha512-pVXSwPsLuw8IGLo2Di0EaOfsk+ntVvpkk942J/sHYIkwvtKUakEcPh7HBgZ6tuimgzKSEHgCvO4XgQ05DEbwDw=="],
|
||||||
|
|
||||||
|
|
@ -584,7 +584,7 @@
|
||||||
|
|
||||||
"@chainsafe/as-chacha20poly1305": ["@chainsafe/as-chacha20poly1305@0.1.0", "", {}, "sha512-BpNcL8/lji/GM3+vZ/bgRWqJ1q5kwvTFmGPk7pxm/QQZDbaMI98waOHjEymTjq2JmdD/INdNBFOVSyJofXg7ew=="],
|
"@chainsafe/as-chacha20poly1305": ["@chainsafe/as-chacha20poly1305@0.1.0", "", {}, "sha512-BpNcL8/lji/GM3+vZ/bgRWqJ1q5kwvTFmGPk7pxm/QQZDbaMI98waOHjEymTjq2JmdD/INdNBFOVSyJofXg7ew=="],
|
||||||
|
|
||||||
"@chainsafe/as-sha256": ["@chainsafe/as-sha256@1.2.4", "", {}, "sha512-3GXDysZOKD6cTYbm48lEdXdUbS7cafjXQZfgHOspTByhoGR/JM3KBXyF3vE6bf63ImjNPyoEZwnQcpYPQ6k3bQ=="],
|
"@chainsafe/as-sha256": ["@chainsafe/as-sha256@1.2.5", "", {}, "sha512-8LzmWxBC/2O5BgbP+aRom/FaDJMrM04VZMlVIivYTc6yNQKYrONmIv27m3q/1VBgxrfrNNqmibitb2hE2tQzIw=="],
|
||||||
|
|
||||||
"@chainsafe/is-ip": ["@chainsafe/is-ip@2.1.0", "", {}, "sha512-KIjt+6IfysQ4GCv66xihEitBjvhU/bixbbbFxdJ1sqCp4uJ0wuZiYBPhksZoy4lfaF0k9cwNzY5upEW/VWdw3w=="],
|
"@chainsafe/is-ip": ["@chainsafe/is-ip@2.1.0", "", {}, "sha512-KIjt+6IfysQ4GCv66xihEitBjvhU/bixbbbFxdJ1sqCp4uJ0wuZiYBPhksZoy4lfaF0k9cwNzY5upEW/VWdw3w=="],
|
||||||
|
|
||||||
|
|
@ -804,7 +804,7 @@
|
||||||
|
|
||||||
"@hono/node-server": ["@hono/node-server@1.19.17", "", { "peerDependencies": { "hono": "^4" } }, "sha512-dSneS5qhiauZWGDCeK4o695Xd9nUNjviSZCMQrj10eetr8Uln1ucn6bbphOM6UynAMMtNIzZNSpL9vnASJwrPQ=="],
|
"@hono/node-server": ["@hono/node-server@1.19.17", "", { "peerDependencies": { "hono": "^4" } }, "sha512-dSneS5qhiauZWGDCeK4o695Xd9nUNjviSZCMQrj10eetr8Uln1ucn6bbphOM6UynAMMtNIzZNSpL9vnASJwrPQ=="],
|
||||||
|
|
||||||
"@iconify-json/lucide": ["@iconify-json/lucide@1.2.123", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-0CozmpKXEOEEhltrfT2zt+/t1hez67Y+hM2VJWoIcBKdBrb83VYuKf+b5A0QU9HfQm+RNn2GjFWlTOwi+Ss6IA=="],
|
"@iconify-json/lucide": ["@iconify-json/lucide@1.2.124", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-mO6JyBVNER7uXEkW2bXiN9Rrm6w91IXxwnNmIMbu2KZX0ZPcVZH1xDUTw94pryxESUIpBhinkOUIZIav+TA9ng=="],
|
||||||
|
|
||||||
"@iconify-json/simple-icons": ["@iconify-json/simple-icons@1.2.93", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-/XhANjfGYOuqvSR3TmUnkQkINvQ4GVjVuukvymRbxtVFBvIq/yiXJqCDycKcQPT401OYT9H2vIY6ihAlz1QIAw=="],
|
"@iconify-json/simple-icons": ["@iconify-json/simple-icons@1.2.93", "", { "dependencies": { "@iconify/types": "*" } }, "sha512-/XhANjfGYOuqvSR3TmUnkQkINvQ4GVjVuukvymRbxtVFBvIq/yiXJqCDycKcQPT401OYT9H2vIY6ihAlz1QIAw=="],
|
||||||
|
|
||||||
|
|
@ -906,7 +906,7 @@
|
||||||
|
|
||||||
"@libp2p/identify": ["@libp2p/identify@3.0.36", "", { "dependencies": { "@libp2p/crypto": "^5.1.6", "@libp2p/interface": "^2.10.4", "@libp2p/interface-internal": "^2.3.17", "@libp2p/peer-id": "^5.1.7", "@libp2p/peer-record": "^8.0.33", "@libp2p/utils": "^6.7.0", "@multiformats/multiaddr": "^12.4.4", "@multiformats/multiaddr-matcher": "^1.7.2", "it-drain": "^3.0.9", "it-parallel": "^3.0.11", "it-protobuf-stream": "^2.0.2", "main-event": "^1.0.1", "protons-runtime": "^5.5.0", "uint8arraylist": "^2.4.8", "uint8arrays": "^5.1.0" } }, "sha512-swpgKzZ8SihHeguIEf3LxYlEcD7C9cSB7DE1XGTuCxNXkXksv2ieQTSiJ2xURMRw0nwe0wEGS5vzmshJh3kzrA=="],
|
"@libp2p/identify": ["@libp2p/identify@3.0.36", "", { "dependencies": { "@libp2p/crypto": "^5.1.6", "@libp2p/interface": "^2.10.4", "@libp2p/interface-internal": "^2.3.17", "@libp2p/peer-id": "^5.1.7", "@libp2p/peer-record": "^8.0.33", "@libp2p/utils": "^6.7.0", "@multiformats/multiaddr": "^12.4.4", "@multiformats/multiaddr-matcher": "^1.7.2", "it-drain": "^3.0.9", "it-parallel": "^3.0.11", "it-protobuf-stream": "^2.0.2", "main-event": "^1.0.1", "protons-runtime": "^5.5.0", "uint8arraylist": "^2.4.8", "uint8arrays": "^5.1.0" } }, "sha512-swpgKzZ8SihHeguIEf3LxYlEcD7C9cSB7DE1XGTuCxNXkXksv2ieQTSiJ2xURMRw0nwe0wEGS5vzmshJh3kzrA=="],
|
||||||
|
|
||||||
"@libp2p/interface": ["@libp2p/interface@2.10.4", "", { "dependencies": { "@multiformats/multiaddr": "^12.4.4", "it-pushable": "^3.2.3", "it-stream-types": "^2.0.2", "main-event": "^1.0.1", "multiformats": "^13.3.6", "progress-events": "^1.0.1", "uint8arraylist": "^2.4.8" } }, "sha512-FX3uujZgjH9bb7mDSNR54j3JzJnF/ngnQH20GQ1wPk5irIeHDvmzRlUj3bJ3hHQmdB2MxLZNT6e39O1es10LFA=="],
|
"@libp2p/interface": ["@libp2p/interface@2.11.0", "", { "dependencies": { "@multiformats/dns": "^1.0.6", "@multiformats/multiaddr": "^12.4.4", "it-pushable": "^3.2.3", "it-stream-types": "^2.0.2", "main-event": "^1.0.1", "multiformats": "^13.3.6", "progress-events": "^1.0.1", "uint8arraylist": "^2.4.8" } }, "sha512-0MUFKoXWHTQW3oWIgSHApmYMUKWO/Y02+7Hpyp+n3z+geD4Xo2Rku2gYWmxcq+Pyjkz6Q9YjDWz3Yb2SoV2E8Q=="],
|
||||||
|
|
||||||
"@libp2p/interface-internal": ["@libp2p/interface-internal@2.3.19", "", { "dependencies": { "@libp2p/interface": "^2.11.0", "@libp2p/peer-collections": "^6.0.35", "@multiformats/multiaddr": "^12.4.4", "progress-events": "^1.0.1" } }, "sha512-v335EB0i5CaNF+0SqT01CTBp0VyjJizpy46KprcshFFjX16UQ8+/QzoTZqmot9WiAmAzwR0b87oKmlAE9cpxzQ=="],
|
"@libp2p/interface-internal": ["@libp2p/interface-internal@2.3.19", "", { "dependencies": { "@libp2p/interface": "^2.11.0", "@libp2p/peer-collections": "^6.0.35", "@multiformats/multiaddr": "^12.4.4", "progress-events": "^1.0.1" } }, "sha512-v335EB0i5CaNF+0SqT01CTBp0VyjJizpy46KprcshFFjX16UQ8+/QzoTZqmot9WiAmAzwR0b87oKmlAE9cpxzQ=="],
|
||||||
|
|
||||||
|
|
@ -1002,8 +1002,6 @@
|
||||||
|
|
||||||
"@openrouter/ai-sdk-provider": ["@openrouter/ai-sdk-provider@3.0.0", "", { "peerDependencies": { "ai": "^7.0.0", "zod": "^3.25.76 || ^4.1.8" } }, "sha512-m9XTSWoODH2RM5OsZpaGiN7QRR8cdP5paBWq699Tu3JVmGPBKT8xF8XwV0ZBVVsjikD/JgWfak4VSsTR4wAVbg=="],
|
"@openrouter/ai-sdk-provider": ["@openrouter/ai-sdk-provider@3.0.0", "", { "peerDependencies": { "ai": "^7.0.0", "zod": "^3.25.76 || ^4.1.8" } }, "sha512-m9XTSWoODH2RM5OsZpaGiN7QRR8cdP5paBWq699Tu3JVmGPBKT8xF8XwV0ZBVVsjikD/JgWfak4VSsTR4wAVbg=="],
|
||||||
|
|
||||||
"@opentelemetry/api": ["@opentelemetry/api@1.9.1", "", {}, "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q=="],
|
|
||||||
|
|
||||||
"@oxc-parser/binding-android-arm-eabi": ["@oxc-parser/binding-android-arm-eabi@0.137.0", "", { "os": "android", "cpu": "arm" }, "sha512-KDs+0VPdEmasOkpuJHW9V5WCF+cvYdMQv2Jd+aJXt+cxIx12NToRQRbXaRwUEDsZw+/jMk81Ve8ZFbjUkJTOwA=="],
|
"@oxc-parser/binding-android-arm-eabi": ["@oxc-parser/binding-android-arm-eabi@0.137.0", "", { "os": "android", "cpu": "arm" }, "sha512-KDs+0VPdEmasOkpuJHW9V5WCF+cvYdMQv2Jd+aJXt+cxIx12NToRQRbXaRwUEDsZw+/jMk81Ve8ZFbjUkJTOwA=="],
|
||||||
|
|
||||||
"@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.137.0", "", { "os": "android", "cpu": "arm64" }, "sha512-WhALNzfy3x/RfC6bsqX+csavuUY0yHHE7XfgPE5M542uhoBZUUoGTPG+nkMbGoG4+gcfss5s7urMyn5QBHu0sw=="],
|
"@oxc-parser/binding-android-arm64": ["@oxc-parser/binding-android-arm64@0.137.0", "", { "os": "android", "cpu": "arm64" }, "sha512-WhALNzfy3x/RfC6bsqX+csavuUY0yHHE7XfgPE5M542uhoBZUUoGTPG+nkMbGoG4+gcfss5s7urMyn5QBHu0sw=="],
|
||||||
|
|
@ -1330,25 +1328,25 @@
|
||||||
|
|
||||||
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
||||||
|
|
||||||
"@storybook/addon-a11y": ["@storybook/addon-a11y@10.5.8", "", { "dependencies": { "@storybook/global": "^5.0.0", "axe-core": "^4.2.0" }, "peerDependencies": { "storybook": "^10.5.8" } }, "sha512-yunl+sKa29NaUC3I4yjESwk6ED8waEgmmvIJzNAJvdhb7thFzZYYEld68RzKmOVcGBkD3snK5eZ/Xf0l4VWliQ=="],
|
"@storybook/addon-a11y": ["@storybook/addon-a11y@10.5.9", "", { "dependencies": { "@storybook/global": "^5.0.0", "axe-core": "^4.2.0" }, "peerDependencies": { "storybook": "^10.5.9" } }, "sha512-MvXkoJIVRcZrqhWi+wynYAmFkvTWm5aHdJfYohhgPeEJVDRF91zejtOsN7zPRE/lQvBDY+IiomKxeRN3UhWNVw=="],
|
||||||
|
|
||||||
"@storybook/addon-docs": ["@storybook/addon-docs@10.5.8", "", { "dependencies": { "@mdx-js/react": "^3.0.0", "@storybook/csf-plugin": "10.5.8", "@storybook/icons": "^2.0.2", "@storybook/react-dom-shim": "10.5.8", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "ts-dedent": "^2.0.0" }, "peerDependencies": { "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "storybook": "^10.5.8" }, "optionalPeers": ["@types/react"] }, "sha512-NlHiMKW/UvW/uL8HXFDCEVwoH3qZeGYZ/qlWax4d7H471b/T54MBq2KcB4ZrdA785FfIH3numAJdBb5jwn00Mg=="],
|
"@storybook/addon-docs": ["@storybook/addon-docs@10.5.9", "", { "dependencies": { "@mdx-js/react": "^3.0.0", "@storybook/csf-plugin": "10.5.9", "@storybook/icons": "^2.0.2", "@storybook/react-dom-shim": "10.5.9", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "ts-dedent": "^2.0.0" }, "peerDependencies": { "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "storybook": "^10.5.9" }, "optionalPeers": ["@types/react"] }, "sha512-8sFsMkZYrrdqCLdV+hnwTwDF7RaBsBPRwl4wfc8ve9Q/7Yhi5REe/Xjvd8x1yn6fBPPw9tnID9dx6Agdnr81fw=="],
|
||||||
|
|
||||||
"@storybook/addon-themes": ["@storybook/addon-themes@10.5.8", "", { "dependencies": { "ts-dedent": "^2.0.0" }, "peerDependencies": { "storybook": "^10.5.8" } }, "sha512-MYTLkN/5t02R0DJikVJUIRWnoyDqDwJprXnagUEFRT5aiO75glG7rY3uikB8n+7vXL/N9fTkgjIxER0SShkvYg=="],
|
"@storybook/addon-themes": ["@storybook/addon-themes@10.5.9", "", { "dependencies": { "ts-dedent": "^2.0.0" }, "peerDependencies": { "storybook": "^10.5.9" } }, "sha512-/OZ6/4dS9N/N3vDzaQxMBotIPrrn80tLJFd23QDvSYeTyAEomH6x3JnXUwyhvlVhTQcYkhrUCOLdNPYW/wn67w=="],
|
||||||
|
|
||||||
"@storybook/builder-vite": ["@storybook/builder-vite@10.5.8", "", { "dependencies": { "@storybook/csf-plugin": "10.5.8", "ts-dedent": "^2.0.0" }, "peerDependencies": { "storybook": "^10.5.8", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-UeRnn7yT55WmBlHNOQzLrvN7vsHEvVgIukhKDO+4cMbGXN87wZkbxhx6NstpuXRH8OxGqwKS0SZNVp+SC1ftLQ=="],
|
"@storybook/builder-vite": ["@storybook/builder-vite@10.5.9", "", { "dependencies": { "@storybook/csf-plugin": "10.5.9", "ts-dedent": "^2.0.0" }, "peerDependencies": { "storybook": "^10.5.9", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-Zg4JbGQiHFPGlFJ9HM+XPgzKmU/RFPCymhohVRJhBBYfmgaQgz0flWWzscseCDpl638MNd8/r/H+nwuoBgSYDg=="],
|
||||||
|
|
||||||
"@storybook/csf-plugin": ["@storybook/csf-plugin@10.5.8", "", { "dependencies": { "unplugin": "^2.3.5" }, "peerDependencies": { "esbuild": "*", "rollup": "*", "storybook": "^10.5.8", "vite": "*", "webpack": "*" }, "optionalPeers": ["esbuild", "rollup", "vite", "webpack"] }, "sha512-/FHiMyOWWEXfwK/lM0WxmkP9GLzbSJJuzGtfeuNWSOVDnvAMbjavitxfHb5wSbWKIQo0XYC1EJ2Y7x91XNYP4w=="],
|
"@storybook/csf-plugin": ["@storybook/csf-plugin@10.5.9", "", { "dependencies": { "unplugin": "^2.3.5" }, "peerDependencies": { "esbuild": "*", "rollup": "*", "storybook": "^10.5.9", "vite": "*", "webpack": "*" }, "optionalPeers": ["esbuild", "rollup", "vite", "webpack"] }, "sha512-4H5QIHQVtQYCuL43GCRLGjNQhZpQg9gL03ja0DV80kO2Dn9LEt6ol87bSnSjn4VDgcAXtgTzXFvRLknfVgAAqg=="],
|
||||||
|
|
||||||
"@storybook/global": ["@storybook/global@5.0.0", "", {}, "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ=="],
|
"@storybook/global": ["@storybook/global@5.0.0", "", {}, "sha512-FcOqPAXACP0I3oJ/ws6/rrPT9WGhu915Cg8D02a9YxLo0DE9zI+a9A5gRGvmQ09fiWPukqI8ZAEoQEdWUKMQdQ=="],
|
||||||
|
|
||||||
"@storybook/icons": ["@storybook/icons@2.1.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Fxh9vYpX9bQqFeHRiY8h2ApeRGDzRSMLwJwNZ/AIRqnyOKHxRKL+yFe+ctEkVJmuptRE9u1Hrn8ZZNHyfDKKNg=="],
|
"@storybook/icons": ["@storybook/icons@2.1.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Fxh9vYpX9bQqFeHRiY8h2ApeRGDzRSMLwJwNZ/AIRqnyOKHxRKL+yFe+ctEkVJmuptRE9u1Hrn8ZZNHyfDKKNg=="],
|
||||||
|
|
||||||
"@storybook/react-dom-shim": ["@storybook/react-dom-shim@10.5.8", "", { "peerDependencies": { "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "@types/react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "storybook": "^10.5.8" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-N8D13/Xny+V3kfe1KBgsAHS0nKWXLLdgOOXS9poKdYzVwVCN+CGEGBxWX0zMMtdCptqa6/57em9coPlZMoO+bg=="],
|
"@storybook/react-dom-shim": ["@storybook/react-dom-shim@10.5.9", "", { "peerDependencies": { "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "@types/react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "storybook": "^10.5.9" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-7qZD6CSa64p1m/zX9tG4ALcEHlEk0Bx+5++4RL3MFlRCgCFfAomXsCHTzF0RyF8cI4vl+hS7Y0ryjQchVs6UQA=="],
|
||||||
|
|
||||||
"@storybook/vue3": ["@storybook/vue3@10.5.8", "", { "dependencies": { "@storybook/global": "^5.0.0", "type-fest": "^5.6.0", "vue-component-type-helpers": "^3.2.9" }, "peerDependencies": { "storybook": "^10.5.8", "vue": "^3.0.0" } }, "sha512-R8XZDb4iHjRcfbamYJcss/gTacWXX0K9mVXMBSi+vQNxHFguhLua5yT50UX2WYSW7rXtEZIgnzTldMoBnaLIwQ=="],
|
"@storybook/vue3": ["@storybook/vue3@10.5.9", "", { "dependencies": { "@storybook/global": "^5.0.0", "type-fest": "^5.6.0", "vue-component-type-helpers": "^3.2.9" }, "peerDependencies": { "storybook": "^10.5.9", "vue": "^3.0.0" } }, "sha512-4VXkJmVRTntxIcIIBEOmWzWUy9ecwCap2Cnt13ioffCGwT6Yzk0fOW4niXSJFX7fO2b13Dtn747Nep7kH9TFqg=="],
|
||||||
|
|
||||||
"@storybook/vue3-vite": ["@storybook/vue3-vite@10.5.8", "", { "dependencies": { "@storybook/builder-vite": "10.5.8", "@storybook/vue3": "10.5.8", "magic-string": "^0.30.0", "typescript": "^5.9.3", "vue-component-meta": "^3.2.7", "vue-docgen-api": "^4.75.1" }, "peerDependencies": { "storybook": "^10.5.8", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-TdChq6KWgrT/ohK9idiV9K5JTQKY7IKBeFvtprdCnsjwrdk26VQwT7LZRrj7V8DsBKKrrbACUOdvJkYaOZOWrA=="],
|
"@storybook/vue3-vite": ["@storybook/vue3-vite@10.5.9", "", { "dependencies": { "@storybook/builder-vite": "10.5.9", "@storybook/vue3": "10.5.9", "magic-string": "^0.30.0", "typescript": "^5.9.3", "vue-component-meta": "^3.2.7", "vue-docgen-api": "^4.75.1" }, "peerDependencies": { "storybook": "^10.5.9", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-RzuKgQSkTnXhy9UsguYZOmDT36uyejmwYEEitqXs8rKlR2fW7XZqP4Ur0FfT0IYQUX6RE3f0oBJWtDvd5WG5aQ=="],
|
||||||
|
|
||||||
"@stream-markdown/code": ["@stream-markdown/code@1.0.4", "", { "dependencies": { "@stream-markdown/core": "1.0.4", "shiki": "^4.0.2" } }, "sha512-hxyNhHbPayz/FWjcH8HVqWmzOEUALEByGj7rpWY3mOqHcdKpETGBAs1FH7RJ/SFMLwO8wr/Ps8dxxGfzPjTtoA=="],
|
"@stream-markdown/code": ["@stream-markdown/code@1.0.4", "", { "dependencies": { "@stream-markdown/core": "1.0.4", "shiki": "^4.0.2" } }, "sha512-hxyNhHbPayz/FWjcH8HVqWmzOEUALEByGj7rpWY3mOqHcdKpETGBAs1FH7RJ/SFMLwO8wr/Ps8dxxGfzPjTtoA=="],
|
||||||
|
|
||||||
|
|
@ -1406,11 +1404,11 @@
|
||||||
|
|
||||||
"@tanstack/table-core": ["@tanstack/table-core@8.21.3", "", {}, "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg=="],
|
"@tanstack/table-core": ["@tanstack/table-core@8.21.3", "", {}, "sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg=="],
|
||||||
|
|
||||||
"@tanstack/virtual-core": ["@tanstack/virtual-core@3.17.7", "", {}, "sha512-bp+v10y65sp2H7WpWfIMyxTNfl8ZVfxFTLRjPIFRryi6FV/J33z4IS53WO4pTk36KlvJ4iLiQz+oaydDC1xbcA=="],
|
"@tanstack/virtual-core": ["@tanstack/virtual-core@3.17.8", "", {}, "sha512-BfEvehNpOT75r5Ksc5xW6NZuXujTfb7nlSEyVu4XHG3gdxNg1KqXruWbDewXOUaUYIo4oRbSfkjIajz4MAT8tA=="],
|
||||||
|
|
||||||
"@tanstack/vue-table": ["@tanstack/vue-table@8.21.3", "", { "dependencies": { "@tanstack/table-core": "8.21.3" }, "peerDependencies": { "vue": ">=3.2" } }, "sha512-rusRyd77c5tDPloPskctMyPLFEQUeBzxdQ+2Eow4F7gDPlPOB1UnnhzfpdvqZ8ZyX2rRNGmqNnQWm87OI2OQPw=="],
|
"@tanstack/vue-table": ["@tanstack/vue-table@8.21.3", "", { "dependencies": { "@tanstack/table-core": "8.21.3" }, "peerDependencies": { "vue": ">=3.2" } }, "sha512-rusRyd77c5tDPloPskctMyPLFEQUeBzxdQ+2Eow4F7gDPlPOB1UnnhzfpdvqZ8ZyX2rRNGmqNnQWm87OI2OQPw=="],
|
||||||
|
|
||||||
"@tanstack/vue-virtual": ["@tanstack/vue-virtual@3.13.35", "", { "dependencies": { "@tanstack/virtual-core": "3.17.7" }, "peerDependencies": { "vue": "^2.7.0 || ^3.0.0" } }, "sha512-lOfSPvgPdlaH6Qy+CyIc3XpycitaSQ9GECndGpTuDiu+uDA1am+90yWXwzDSd/20ZM196ggWJLS+Qb6WjVd/OA=="],
|
"@tanstack/vue-virtual": ["@tanstack/vue-virtual@3.13.36", "", { "dependencies": { "@tanstack/virtual-core": "3.17.8" }, "peerDependencies": { "vue": "^2.7.0 || ^3.0.0" } }, "sha512-gKpExv4RbB9luVG+SucTXoqPZv/gzu/Yvz6BNO+8kpNxJ2x+I/ulryzl5W9BRciahZGp5Tls3Dp5XP1ztVGbMw=="],
|
||||||
|
|
||||||
"@tauri-apps/api": ["@tauri-apps/api@2.11.1", "", {}, "sha512-M2FPuYND2m+wh5hfW9ZpSdxMPdEJovPBWwoHJmwUpysTYNHaOkVFN419m/K0LIgjb/7KU2vBgsUepJWugQCvAA=="],
|
"@tauri-apps/api": ["@tauri-apps/api@2.11.1", "", {}, "sha512-M2FPuYND2m+wh5hfW9ZpSdxMPdEJovPBWwoHJmwUpysTYNHaOkVFN419m/K0LIgjb/7KU2vBgsUepJWugQCvAA=="],
|
||||||
|
|
||||||
|
|
@ -1456,7 +1454,7 @@
|
||||||
|
|
||||||
"@testing-library/jest-dom": ["@testing-library/jest-dom@6.9.1", "", { "dependencies": { "@adobe/css-tools": "^4.4.0", "aria-query": "^5.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.6.3", "picocolors": "^1.1.1", "redent": "^3.0.0" } }, "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA=="],
|
"@testing-library/jest-dom": ["@testing-library/jest-dom@6.9.1", "", { "dependencies": { "@adobe/css-tools": "^4.4.0", "aria-query": "^5.0.0", "css.escape": "^1.5.1", "dom-accessibility-api": "^0.6.3", "picocolors": "^1.1.1", "redent": "^3.0.0" } }, "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA=="],
|
||||||
|
|
||||||
"@testing-library/user-event": ["@testing-library/user-event@14.6.4", "", { "peerDependencies": { "@testing-library/dom": ">=7.21.4" } }, "sha512-QCGwP6QrjypBLwyj5cuyfVamkaIEy/XGY+1VDehbtbQqOggYmTFpFOdWR5mPz14vX8vXLMVjDHlRNBcClyO9ew=="],
|
"@testing-library/user-event": ["@testing-library/user-event@14.6.5", "", { "peerDependencies": { "@testing-library/dom": ">=7.21.4" } }, "sha512-FhqjldLTpteueBaKflhNFlMT3+PM0O5fiBUivht6b9CZ1eesJyy7+g3Jr7XwJzt/Hip3ZG5hWwK1MX1FuDiE4w=="],
|
||||||
|
|
||||||
"@tootallnate/quickjs-emscripten": ["@tootallnate/quickjs-emscripten@0.23.0", "", {}, "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA=="],
|
"@tootallnate/quickjs-emscripten": ["@tootallnate/quickjs-emscripten@0.23.0", "", {}, "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA=="],
|
||||||
|
|
||||||
|
|
@ -1562,7 +1560,7 @@
|
||||||
|
|
||||||
"@types/lodash.debounce": ["@types/lodash.debounce@4.0.9", "", { "dependencies": { "@types/lodash": "*" } }, "sha512-Ma5JcgTREwpLRwMM+XwBR7DaWe96nC38uCBDFKZWbNKD+osjVzdpnUSwBcqCptrp16sSOLBAUb50Car5I0TCsQ=="],
|
"@types/lodash.debounce": ["@types/lodash.debounce@4.0.9", "", { "dependencies": { "@types/lodash": "*" } }, "sha512-Ma5JcgTREwpLRwMM+XwBR7DaWe96nC38uCBDFKZWbNKD+osjVzdpnUSwBcqCptrp16sSOLBAUb50Car5I0TCsQ=="],
|
||||||
|
|
||||||
"@types/markdown-it": ["@types/markdown-it@14.1.2", "", { "dependencies": { "@types/linkify-it": "^5", "@types/mdurl": "^2" } }, "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog=="],
|
"@types/markdown-it": ["@types/markdown-it@14.2.0", "", { "dependencies": { "@types/linkify-it": "^5", "@types/mdurl": "^2" } }, "sha512-NoQ2yGlLWj4wpxMs+TYmRKk3thDrQ97agr7sFqfLsAlvoS8SNQuTrlObhFqG9iugdTtgOE9jpJ6FNM4ZGsa5xQ=="],
|
||||||
|
|
||||||
"@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="],
|
"@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="],
|
||||||
|
|
||||||
|
|
@ -1662,7 +1660,7 @@
|
||||||
|
|
||||||
"@vitest/spy": ["@vitest/spy@3.2.4", "", { "dependencies": { "tinyspy": "^4.0.3" } }, "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw=="],
|
"@vitest/spy": ["@vitest/spy@3.2.4", "", { "dependencies": { "tinyspy": "^4.0.3" } }, "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw=="],
|
||||||
|
|
||||||
"@vitest/utils": ["@vitest/utils@4.1.10", "", { "dependencies": { "@vitest/pretty-format": "4.1.10", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA=="],
|
"@vitest/utils": ["@vitest/utils@4.1.11", "", { "dependencies": { "@vitest/pretty-format": "4.1.11", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ=="],
|
||||||
|
|
||||||
"@volar/language-core": ["@volar/language-core@2.4.28", "", { "dependencies": { "@volar/source-map": "2.4.28" } }, "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ=="],
|
"@volar/language-core": ["@volar/language-core@2.4.28", "", { "dependencies": { "@volar/source-map": "2.4.28" } }, "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ=="],
|
||||||
|
|
||||||
|
|
@ -1820,7 +1818,7 @@
|
||||||
|
|
||||||
"@yuku-toolchain/types": ["@yuku-toolchain/types@0.8.7", "", {}, "sha512-2Z53dNxAJL6UvFoIrDZvYf3zlO8s4VJK4O2hhaB4mXVwwpX/7ajtss3cmfqKvamlNLWyt9FSWs4eoYdlbxpnHA=="],
|
"@yuku-toolchain/types": ["@yuku-toolchain/types@0.8.7", "", {}, "sha512-2Z53dNxAJL6UvFoIrDZvYf3zlO8s4VJK4O2hhaB4mXVwwpX/7ajtss3cmfqKvamlNLWyt9FSWs4eoYdlbxpnHA=="],
|
||||||
|
|
||||||
"@zip.js/zip.js": ["@zip.js/zip.js@2.8.51", "", {}, "sha512-xCEMRBwBh6JPMQKy5D/RE0Ra9NJvrvjcCHNXo+NzMYCdZy3R0oAX9zJKRb1c393HNMbLYfoD2MRSPgB8L6Jskw=="],
|
"@zip.js/zip.js": ["@zip.js/zip.js@2.8.52", "", {}, "sha512-ZVXpmXRROrjz/0Glm9homDpSUAiavgpdnR+0tGlTtvtIsqs/d7f7qqbkOxrRKfUaNML68YXb4reIA3vZjul3uQ=="],
|
||||||
|
|
||||||
"abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="],
|
"abort-controller": ["abort-controller@3.0.0", "", { "dependencies": { "event-target-shim": "^5.0.0" } }, "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg=="],
|
||||||
|
|
||||||
|
|
@ -1834,7 +1832,7 @@
|
||||||
|
|
||||||
"agentfmt": ["agentfmt@0.1.3", "", { "dependencies": { "picocolors": "^1.1.1" } }, "sha512-BVSZr8ovigxjYewuBx42Ep4RJj00HURaQYUQ+id41sgb7r0PMUSEWsnD/+h96xj6t6v2WVyPuGPH0K6RtjftKQ=="],
|
"agentfmt": ["agentfmt@0.1.3", "", { "dependencies": { "picocolors": "^1.1.1" } }, "sha512-BVSZr8ovigxjYewuBx42Ep4RJj00HURaQYUQ+id41sgb7r0PMUSEWsnD/+h96xj6t6v2WVyPuGPH0K6RtjftKQ=="],
|
||||||
|
|
||||||
"ai": ["ai@7.0.66", "", { "dependencies": { "@ai-sdk/gateway": "4.0.52", "@ai-sdk/provider": "4.0.7", "@ai-sdk/provider-utils": "5.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-wBUyoCYF3GVr+62nelBgR8YbpTSsMZrzFyOOjiwijylNSM2TFCW35C+Pml2vc59/WLMpyhS/LWZ55M+B9DAcSg=="],
|
"ai": ["ai@7.0.67", "", { "dependencies": { "@ai-sdk/gateway": "4.0.53", "@ai-sdk/provider": "4.0.7", "@ai-sdk/provider-utils": "5.0.27" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-83Y/OFx7rylrrgzCsaDPlGeL3QC8qrFQ51LBs6MXm2JVxQLLkrvKmPa1/hOzgyCHM8dsB/2rE1a6OGPNRpmTLQ=="],
|
||||||
|
|
||||||
"ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="],
|
"ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="],
|
||||||
|
|
||||||
|
|
@ -1988,7 +1986,7 @@
|
||||||
|
|
||||||
"caniuse-lite": ["caniuse-lite@1.0.30001809", "", {}, "sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ=="],
|
"caniuse-lite": ["caniuse-lite@1.0.30001809", "", {}, "sha512-xxWVywk6a6Arlk+hymeycyn/VgqEfLDxupvhH/xiY5SJ/18kmi9o6MiO320DCUzypORHLtvh0I4i04tUhCNHNQ=="],
|
||||||
|
|
||||||
"canvaskit-wasm": ["canvaskit-wasm@0.40.0", "", { "dependencies": { "@webgpu/types": "0.1.21" } }, "sha512-Od2o+ZmoEw9PBdN/yCGvzfu0WVqlufBPEWNG452wY7E9aT8RBE+ChpZF526doOlg7zumO4iCS+RAeht4P0Gbpw=="],
|
"canvaskit-wasm": ["canvaskit-wasm@0.41.1", "", { "dependencies": { "@webgpu/types": "0.1.21" } }, "sha512-gO2rNMIE0lOQ8MaarM4qNeq2zZAEknAObKP2XAKidMSAY8P5sURGdFkrx1TSdHuBFqTf5w35JqjuUzjibqkD5g=="],
|
||||||
|
|
||||||
"canvg": ["canvg@3.0.11", "", { "dependencies": { "@babel/runtime": "^7.12.5", "@types/raf": "^3.4.0", "core-js": "^3.8.3", "raf": "^3.4.1", "regenerator-runtime": "^0.13.7", "rgbcolor": "^1.0.1", "stackblur-canvas": "^2.0.0", "svg-pathdata": "^6.0.3" } }, "sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA=="],
|
"canvg": ["canvg@3.0.11", "", { "dependencies": { "@babel/runtime": "^7.12.5", "@types/raf": "^3.4.0", "core-js": "^3.8.3", "raf": "^3.4.1", "regenerator-runtime": "^0.13.7", "rgbcolor": "^1.0.1", "stackblur-canvas": "^2.0.0", "svg-pathdata": "^6.0.3" } }, "sha512-5ON+q7jCTgMp9cjpu4Jo6XbvfYwSB2Ow3kzHKfIyJfaCAOHLbdKPQqGKgfED/R5B+3TFFfe8pegYA+b423SRyA=="],
|
||||||
|
|
||||||
|
|
@ -2304,7 +2302,7 @@
|
||||||
|
|
||||||
"ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
|
"ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="],
|
||||||
|
|
||||||
"electron-to-chromium": ["electron-to-chromium@1.5.408", "", {}, "sha512-SLoprcYpJ/OH2v2ps0+N5biv9H4/KBT3+YmmDew64TwK5y9j2wv7pMOFY7IorVkyMtEyLSCRlXKLsNlakeAlPw=="],
|
"electron-to-chromium": ["electron-to-chromium@1.5.409", "", {}, "sha512-ChI4N44d0B4A6C8prnNjMOaGgE59fUyEVYcRYm2XEXIjMbbvF5i9UL1cblDbpGqiU0uS8FE8UcKxqZqTXdmzbQ=="],
|
||||||
|
|
||||||
"elkjs": ["elkjs@0.11.1", "", {}, "sha512-zxxR9k+rx5ktMwT/FwyLdPCrq7xN6e4VGGHH8hA01vVYKjTFik7nHOxBnAYtrgYUB1RpAiLvA1/U2YraWxyKKg=="],
|
"elkjs": ["elkjs@0.11.1", "", {}, "sha512-zxxR9k+rx5ktMwT/FwyLdPCrq7xN6e4VGGHH8hA01vVYKjTFik7nHOxBnAYtrgYUB1RpAiLvA1/U2YraWxyKKg=="],
|
||||||
|
|
||||||
|
|
@ -2582,7 +2580,7 @@
|
||||||
|
|
||||||
"highlight.js": ["highlight.js@10.7.3", "", {}, "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="],
|
"highlight.js": ["highlight.js@10.7.3", "", {}, "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A=="],
|
||||||
|
|
||||||
"hono": ["hono@4.13.2", "", {}, "sha512-JydRilDRkYBQMt9qR9U92mXxmbGqsqSn/IKOrh4e7/gEbn+0zSr8igTu0obwJoNGN4sez28DIql7FBHWydoJpA=="],
|
"hono": ["hono@4.13.3", "", {}, "sha512-r8AO2mYHoLxSHkgafNeC/BXyb2vWRxD3jem4Ts+ptav8oTG5FIRifAjuJEmZI4bSvvc2ns0GxmIYiZnHqN3mMw=="],
|
||||||
|
|
||||||
"hookable": ["hookable@6.1.1", "", {}, "sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ=="],
|
"hookable": ["hookable@6.1.1", "", {}, "sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ=="],
|
||||||
|
|
||||||
|
|
@ -3630,7 +3628,7 @@
|
||||||
|
|
||||||
"stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="],
|
"stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="],
|
||||||
|
|
||||||
"storybook": ["storybook@10.5.8", "", { "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.2", "@testing-library/dom": "^10.4.1", "@testing-library/jest-dom": "6.9.1", "@testing-library/user-event": "^14.6.1", "@vitest/expect": "3.2.4", "@vitest/spy": "3.2.4", "@webcontainer/env": "^1.1.1", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0 || ^0.28.0", "jsonc-parser": "^3.3.1", "open": "^10.2.0", "oxc-parser": "^0.127.0", "oxc-resolver": "^11.19.1", "recast": "^0.23.5", "semver": "^7.7.3", "use-sync-external-store": "^1.5.0", "ws": "^8.21.1" }, "peerDependencies": { "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "prettier": "^2 || ^3", "vite-plus": "^0.1.15 || ^0.2.0" }, "optionalPeers": ["@types/react", "prettier", "vite-plus"], "bin": "./dist/bin/dispatcher.js" }, "sha512-rR4oFMSiWBSqI0lvsJPtcQUPj8+hzj3TkLu+Mw61Wo6YxPSb5FsLSHai0jZnuaIdKIlmu25KCfwlSQl4e1uvnA=="],
|
"storybook": ["storybook@10.5.9", "", { "dependencies": { "@storybook/global": "^5.0.0", "@storybook/icons": "^2.0.2", "@testing-library/dom": "^10.4.1", "@testing-library/jest-dom": "6.9.1", "@testing-library/user-event": "^14.6.1", "@vitest/expect": "3.2.4", "@vitest/spy": "3.2.4", "@webcontainer/env": "^1.1.1", "esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.26.0 || ^0.27.0 || ^0.28.0", "jsonc-parser": "^3.3.1", "open": "^10.2.0", "oxc-parser": "^0.127.0", "oxc-resolver": "^11.19.1", "recast": "^0.23.5", "semver": "^7.7.3", "use-sync-external-store": "^1.5.0", "ws": "^8.21.1" }, "peerDependencies": { "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "prettier": "^2 || ^3", "vite-plus": "^0.1.15 || ^0.2.0" }, "optionalPeers": ["@types/react", "prettier", "vite-plus"], "bin": "./dist/bin/dispatcher.js" }, "sha512-UfdMKSjEhIKr8LbqYyIE5r7vT/drL/PxN75YaouJ+UG0FssEy6cf49OdTF3kstAqVMHskc+zEqyRoiQHZXHwgA=="],
|
||||||
|
|
||||||
"stream-buffers": ["stream-buffers@3.0.3", "", {}, "sha512-pqMqwQCso0PBJt2PQmDO0cFj0lyqmiwOMiMSkVtRokl7e+ZTRYgDHKnuZNbqjiJXgsg4nuqtD/zxuo9KqTp0Yw=="],
|
"stream-buffers": ["stream-buffers@3.0.3", "", {}, "sha512-pqMqwQCso0PBJt2PQmDO0cFj0lyqmiwOMiMSkVtRokl7e+ZTRYgDHKnuZNbqjiJXgsg4nuqtD/zxuo9KqTp0Yw=="],
|
||||||
|
|
||||||
|
|
@ -3886,7 +3884,7 @@
|
||||||
|
|
||||||
"utrie": ["utrie@1.0.2", "", { "dependencies": { "base64-arraybuffer": "^1.0.2" } }, "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw=="],
|
"utrie": ["utrie@1.0.2", "", { "dependencies": { "base64-arraybuffer": "^1.0.2" } }, "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw=="],
|
||||||
|
|
||||||
"uuid": ["uuid@14.0.1", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-6ZxzVpzDXDa3bJWaHilVayA+BH/1zmxCJoVgvmqJnid/gPoKHxUrS/aC/T6LGQtNHT+XHG9fXPJB4d+IrU30Ew=="],
|
"uuid": ["uuid@14.0.2", "", { "bin": { "uuid": "dist-node/bin/uuid" } }, "sha512-xZe/16rV4aa+HGSOCiY2YeLT1OybRLrrkL/Rqaq7p7GMVXjFh+6wN4oMYgjFmnSnhY8t6Xpdl2l9qmnHYuMHwQ=="],
|
||||||
|
|
||||||
"valibot": ["valibot@1.4.2", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-gjdCvJ6d3RyHAneqxMYMW9QMCwYMb3jpOO0IyHZV1bnRHFBHrX3VkIILt5XYR0WhwHiH7Mty8ovuPZ/O3gamrg=="],
|
"valibot": ["valibot@1.4.2", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-gjdCvJ6d3RyHAneqxMYMW9QMCwYMb3jpOO0IyHZV1bnRHFBHrX3VkIILt5XYR0WhwHiH7Mty8ovuPZ/O3gamrg=="],
|
||||||
|
|
||||||
|
|
@ -4128,22 +4126,6 @@
|
||||||
|
|
||||||
"@libp2p/crypto/uint8arrays": ["uint8arrays@6.1.1", "", { "dependencies": { "multiformats": "^14.0.0" } }, "sha512-iz7JN0XCSZYA111lhFG2Ui9EhFvTNekqSRHw3lvMHq+dzwWy1OQftxFQREEh4rffU0oSoXdQHsk2TiHKVm4fsA=="],
|
"@libp2p/crypto/uint8arrays": ["uint8arrays@6.1.1", "", { "dependencies": { "multiformats": "^14.0.0" } }, "sha512-iz7JN0XCSZYA111lhFG2Ui9EhFvTNekqSRHw3lvMHq+dzwWy1OQftxFQREEh4rffU0oSoXdQHsk2TiHKVm4fsA=="],
|
||||||
|
|
||||||
"@libp2p/interface-internal/@libp2p/interface": ["@libp2p/interface@2.11.0", "", { "dependencies": { "@multiformats/dns": "^1.0.6", "@multiformats/multiaddr": "^12.4.4", "it-pushable": "^3.2.3", "it-stream-types": "^2.0.2", "main-event": "^1.0.1", "multiformats": "^13.3.6", "progress-events": "^1.0.1", "uint8arraylist": "^2.4.8" } }, "sha512-0MUFKoXWHTQW3oWIgSHApmYMUKWO/Y02+7Hpyp+n3z+geD4Xo2Rku2gYWmxcq+Pyjkz6Q9YjDWz3Yb2SoV2E8Q=="],
|
|
||||||
|
|
||||||
"@libp2p/logger/@libp2p/interface": ["@libp2p/interface@2.11.0", "", { "dependencies": { "@multiformats/dns": "^1.0.6", "@multiformats/multiaddr": "^12.4.4", "it-pushable": "^3.2.3", "it-stream-types": "^2.0.2", "main-event": "^1.0.1", "multiformats": "^13.3.6", "progress-events": "^1.0.1", "uint8arraylist": "^2.4.8" } }, "sha512-0MUFKoXWHTQW3oWIgSHApmYMUKWO/Y02+7Hpyp+n3z+geD4Xo2Rku2gYWmxcq+Pyjkz6Q9YjDWz3Yb2SoV2E8Q=="],
|
|
||||||
|
|
||||||
"@libp2p/multistream-select/@libp2p/interface": ["@libp2p/interface@2.11.0", "", { "dependencies": { "@multiformats/dns": "^1.0.6", "@multiformats/multiaddr": "^12.4.4", "it-pushable": "^3.2.3", "it-stream-types": "^2.0.2", "main-event": "^1.0.1", "multiformats": "^13.3.6", "progress-events": "^1.0.1", "uint8arraylist": "^2.4.8" } }, "sha512-0MUFKoXWHTQW3oWIgSHApmYMUKWO/Y02+7Hpyp+n3z+geD4Xo2Rku2gYWmxcq+Pyjkz6Q9YjDWz3Yb2SoV2E8Q=="],
|
|
||||||
|
|
||||||
"@libp2p/peer-collections/@libp2p/interface": ["@libp2p/interface@2.11.0", "", { "dependencies": { "@multiformats/dns": "^1.0.6", "@multiformats/multiaddr": "^12.4.4", "it-pushable": "^3.2.3", "it-stream-types": "^2.0.2", "main-event": "^1.0.1", "multiformats": "^13.3.6", "progress-events": "^1.0.1", "uint8arraylist": "^2.4.8" } }, "sha512-0MUFKoXWHTQW3oWIgSHApmYMUKWO/Y02+7Hpyp+n3z+geD4Xo2Rku2gYWmxcq+Pyjkz6Q9YjDWz3Yb2SoV2E8Q=="],
|
|
||||||
|
|
||||||
"@libp2p/peer-id/@libp2p/interface": ["@libp2p/interface@2.11.0", "", { "dependencies": { "@multiformats/dns": "^1.0.6", "@multiformats/multiaddr": "^12.4.4", "it-pushable": "^3.2.3", "it-stream-types": "^2.0.2", "main-event": "^1.0.1", "multiformats": "^13.3.6", "progress-events": "^1.0.1", "uint8arraylist": "^2.4.8" } }, "sha512-0MUFKoXWHTQW3oWIgSHApmYMUKWO/Y02+7Hpyp+n3z+geD4Xo2Rku2gYWmxcq+Pyjkz6Q9YjDWz3Yb2SoV2E8Q=="],
|
|
||||||
|
|
||||||
"@libp2p/peer-record/@libp2p/interface": ["@libp2p/interface@2.11.0", "", { "dependencies": { "@multiformats/dns": "^1.0.6", "@multiformats/multiaddr": "^12.4.4", "it-pushable": "^3.2.3", "it-stream-types": "^2.0.2", "main-event": "^1.0.1", "multiformats": "^13.3.6", "progress-events": "^1.0.1", "uint8arraylist": "^2.4.8" } }, "sha512-0MUFKoXWHTQW3oWIgSHApmYMUKWO/Y02+7Hpyp+n3z+geD4Xo2Rku2gYWmxcq+Pyjkz6Q9YjDWz3Yb2SoV2E8Q=="],
|
|
||||||
|
|
||||||
"@libp2p/peer-store/@libp2p/interface": ["@libp2p/interface@2.11.0", "", { "dependencies": { "@multiformats/dns": "^1.0.6", "@multiformats/multiaddr": "^12.4.4", "it-pushable": "^3.2.3", "it-stream-types": "^2.0.2", "main-event": "^1.0.1", "multiformats": "^13.3.6", "progress-events": "^1.0.1", "uint8arraylist": "^2.4.8" } }, "sha512-0MUFKoXWHTQW3oWIgSHApmYMUKWO/Y02+7Hpyp+n3z+geD4Xo2Rku2gYWmxcq+Pyjkz6Q9YjDWz3Yb2SoV2E8Q=="],
|
|
||||||
|
|
||||||
"@libp2p/utils/@libp2p/interface": ["@libp2p/interface@2.11.0", "", { "dependencies": { "@multiformats/dns": "^1.0.6", "@multiformats/multiaddr": "^12.4.4", "it-pushable": "^3.2.3", "it-stream-types": "^2.0.2", "main-event": "^1.0.1", "multiformats": "^13.3.6", "progress-events": "^1.0.1", "uint8arraylist": "^2.4.8" } }, "sha512-0MUFKoXWHTQW3oWIgSHApmYMUKWO/Y02+7Hpyp+n3z+geD4Xo2Rku2gYWmxcq+Pyjkz6Q9YjDWz3Yb2SoV2E8Q=="],
|
|
||||||
|
|
||||||
"@markmend/core/marked": ["marked@18.0.10", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-FJeH4bRpYoXiggcgriCGItKCSv3xkngJc4QCZ/rkQCogU3VYaLxYJoZl8Nw/b4+x7iij/pd+09mZ6A1dXzpL0A=="],
|
"@markmend/core/marked": ["marked@18.0.10", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-FJeH4bRpYoXiggcgriCGItKCSv3xkngJc4QCZ/rkQCogU3VYaLxYJoZl8Nw/b4+x7iij/pd+09mZ6A1dXzpL0A=="],
|
||||||
|
|
||||||
"@multiformats/dns/@libp2p/interface": ["@libp2p/interface@3.2.5", "", { "dependencies": { "@multiformats/dns": "^1.0.6", "@multiformats/multiaddr": "^13.0.3", "main-event": "^1.0.1", "multiformats": "^14.0.0", "progress-events": "^1.1.0", "uint8arraylist": "^3.0.2" } }, "sha512-RdTchTdakBBc4ShKKsvoME/bJYsrCoVDpdYQVdd4TQ30TCb8QwWKGClqAtw7gfLNuaUKm41xz06kASW6AZpbDA=="],
|
"@multiformats/dns/@libp2p/interface": ["@libp2p/interface@3.2.5", "", { "dependencies": { "@multiformats/dns": "^1.0.6", "@multiformats/multiaddr": "^13.0.3", "main-event": "^1.0.1", "multiformats": "^14.0.0", "progress-events": "^1.1.0", "uint8arraylist": "^3.0.2" } }, "sha512-RdTchTdakBBc4ShKKsvoME/bJYsrCoVDpdYQVdd4TQ30TCb8QwWKGClqAtw7gfLNuaUKm41xz06kASW6AZpbDA=="],
|
||||||
|
|
@ -4162,9 +4144,9 @@
|
||||||
|
|
||||||
"@tailwindcss/node/lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="],
|
"@tailwindcss/node/lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.11.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" }, "bundled": true }, "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ=="],
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.11.3", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.3", "tslib": "^2.4.0" }, "bundled": true }, "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.11.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw=="],
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.11.3", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA=="],
|
||||||
|
|
||||||
"@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="],
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.2", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA=="],
|
||||||
|
|
||||||
|
|
@ -4186,7 +4168,7 @@
|
||||||
|
|
||||||
"@vitest/snapshot/pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="],
|
"@vitest/snapshot/pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="],
|
||||||
|
|
||||||
"@vitest/utils/@vitest/pretty-format": ["@vitest/pretty-format@4.1.10", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q=="],
|
"@vitest/utils/@vitest/pretty-format": ["@vitest/pretty-format@4.1.11", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw=="],
|
||||||
|
|
||||||
"@vitest/utils/tinyrainbow": ["tinyrainbow@3.1.1", "", {}, "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw=="],
|
"@vitest/utils/tinyrainbow": ["tinyrainbow@3.1.1", "", {}, "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw=="],
|
||||||
|
|
||||||
|
|
@ -4204,6 +4186,8 @@
|
||||||
|
|
||||||
"@waku/enr/@noble/secp256k1": ["@noble/secp256k1@1.7.2", "", {}, "sha512-/qzwYl5eFLH8OWIecQWM31qld2g1NfjgylK+TNhqtaUKP37Nm+Y+z30Fjhw0Ct8p9yCQEm2N3W/AckdIb3SMcQ=="],
|
"@waku/enr/@noble/secp256k1": ["@noble/secp256k1@1.7.2", "", {}, "sha512-/qzwYl5eFLH8OWIecQWM31qld2g1NfjgylK+TNhqtaUKP37Nm+Y+z30Fjhw0Ct8p9yCQEm2N3W/AckdIb3SMcQ=="],
|
||||||
|
|
||||||
|
"@waku/sds/@libp2p/interface": ["@libp2p/interface@2.10.4", "", { "dependencies": { "@multiformats/multiaddr": "^12.4.4", "it-pushable": "^3.2.3", "it-stream-types": "^2.0.2", "main-event": "^1.0.1", "multiformats": "^13.3.6", "progress-events": "^1.0.1", "uint8arraylist": "^2.4.8" } }, "sha512-FX3uujZgjH9bb7mDSNR54j3JzJnF/ngnQH20GQ1wPk5irIeHDvmzRlUj3bJ3hHQmdB2MxLZNT6e39O1es10LFA=="],
|
||||||
|
|
||||||
"@waku/utils/chai": ["chai@4.5.0", "", { "dependencies": { "assertion-error": "^1.1.0", "check-error": "^1.0.3", "deep-eql": "^4.1.3", "get-func-name": "^2.0.2", "loupe": "^2.3.6", "pathval": "^1.1.1", "type-detect": "^4.1.0" } }, "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw=="],
|
"@waku/utils/chai": ["chai@4.5.0", "", { "dependencies": { "assertion-error": "^1.1.0", "check-error": "^1.0.3", "deep-eql": "^4.1.3", "get-func-name": "^2.0.2", "loupe": "^2.3.6", "pathval": "^1.1.1", "type-detect": "^4.1.0" } }, "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw=="],
|
||||||
|
|
||||||
"@wdio/cli/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
|
"@wdio/cli/chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
|
||||||
|
|
@ -4292,7 +4276,7 @@
|
||||||
|
|
||||||
"execa/@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@4.0.0", "", {}, "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ=="],
|
"execa/@sindresorhus/merge-streams": ["@sindresorhus/merge-streams@4.0.0", "", {}, "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ=="],
|
||||||
|
|
||||||
"expect-webdriverio/@vitest/snapshot": ["@vitest/snapshot@4.1.10", "", { "dependencies": { "@vitest/pretty-format": "4.1.10", "@vitest/utils": "4.1.10", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw=="],
|
"expect-webdriverio/@vitest/snapshot": ["@vitest/snapshot@4.1.11", "", { "dependencies": { "@vitest/pretty-format": "4.1.11", "@vitest/utils": "4.1.11", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog=="],
|
||||||
|
|
||||||
"extract-zip/get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="],
|
"extract-zip/get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="],
|
||||||
|
|
||||||
|
|
@ -4554,6 +4538,8 @@
|
||||||
|
|
||||||
"@tailwindcss/node/lightningcss/lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="],
|
"@tailwindcss/node/lightningcss/lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="],
|
||||||
|
|
||||||
|
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g=="],
|
||||||
|
|
||||||
"@testing-library/dom/pretty-format/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
"@testing-library/dom/pretty-format/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||||
|
|
||||||
"@testing-library/dom/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
|
"@testing-library/dom/pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="],
|
||||||
|
|
@ -4562,8 +4548,6 @@
|
||||||
|
|
||||||
"@waku/enr/@libp2p/peer-id/@libp2p/crypto": ["@libp2p/crypto@5.1.22", "", { "dependencies": { "@libp2p/interface": "^3.2.5", "@noble/curves": "^2.0.1", "@noble/hashes": "^2.0.1", "multiformats": "^14.0.0", "protons-runtime": "^7.0.0", "uint8arraylist": "^3.0.2", "uint8arrays": "^6.1.1" } }, "sha512-yVk4BefSiEz044kjsiLSEoJTbhRoyamqx4kFI9LnX8/asr4wnqDWKTXcn6mSx/RVNEzmDO70l3vOvcMCl4aLCQ=="],
|
"@waku/enr/@libp2p/peer-id/@libp2p/crypto": ["@libp2p/crypto@5.1.22", "", { "dependencies": { "@libp2p/interface": "^3.2.5", "@noble/curves": "^2.0.1", "@noble/hashes": "^2.0.1", "multiformats": "^14.0.0", "protons-runtime": "^7.0.0", "uint8arraylist": "^3.0.2", "uint8arrays": "^6.1.1" } }, "sha512-yVk4BefSiEz044kjsiLSEoJTbhRoyamqx4kFI9LnX8/asr4wnqDWKTXcn6mSx/RVNEzmDO70l3vOvcMCl4aLCQ=="],
|
||||||
|
|
||||||
"@waku/enr/@libp2p/peer-id/@libp2p/interface": ["@libp2p/interface@2.11.0", "", { "dependencies": { "@multiformats/dns": "^1.0.6", "@multiformats/multiaddr": "^12.4.4", "it-pushable": "^3.2.3", "it-stream-types": "^2.0.2", "main-event": "^1.0.1", "multiformats": "^13.3.6", "progress-events": "^1.0.1", "uint8arraylist": "^2.4.8" } }, "sha512-0MUFKoXWHTQW3oWIgSHApmYMUKWO/Y02+7Hpyp+n3z+geD4Xo2Rku2gYWmxcq+Pyjkz6Q9YjDWz3Yb2SoV2E8Q=="],
|
|
||||||
|
|
||||||
"@waku/utils/chai/assertion-error": ["assertion-error@1.1.0", "", {}, "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw=="],
|
"@waku/utils/chai/assertion-error": ["assertion-error@1.1.0", "", {}, "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw=="],
|
||||||
|
|
||||||
"@waku/utils/chai/check-error": ["check-error@1.0.3", "", { "dependencies": { "get-func-name": "^2.0.2" } }, "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg=="],
|
"@waku/utils/chai/check-error": ["check-error@1.0.3", "", { "dependencies": { "get-func-name": "^2.0.2" } }, "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg=="],
|
||||||
|
|
@ -4686,7 +4670,7 @@
|
||||||
|
|
||||||
"edgedriver/which/isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="],
|
"edgedriver/which/isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="],
|
||||||
|
|
||||||
"expect-webdriverio/@vitest/snapshot/@vitest/pretty-format": ["@vitest/pretty-format@4.1.10", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q=="],
|
"expect-webdriverio/@vitest/snapshot/@vitest/pretty-format": ["@vitest/pretty-format@4.1.11", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw=="],
|
||||||
|
|
||||||
"filelist/minimatch/brace-expansion": ["brace-expansion@2.1.4", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg=="],
|
"filelist/minimatch/brace-expansion": ["brace-expansion@2.1.4", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg=="],
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@
|
||||||
"@xmldom/xmldom": "^0.9.11",
|
"@xmldom/xmldom": "^0.9.11",
|
||||||
"ai": "^7.0.66",
|
"ai": "^7.0.66",
|
||||||
"aws4fetch": "^1.0.20",
|
"aws4fetch": "^1.0.20",
|
||||||
"canvaskit-wasm": "^0.40.0",
|
"canvaskit-wasm": "^0.41.1",
|
||||||
"culori": "^4.0.2",
|
"culori": "^4.0.2",
|
||||||
"dedent": "^1.7.2",
|
"dedent": "^1.7.2",
|
||||||
"es-toolkit": "^1.51.0",
|
"es-toolkit": "^1.51.0",
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@
|
||||||
"@open-pencil/mcp": "workspace:*",
|
"@open-pencil/mcp": "workspace:*",
|
||||||
"@open-pencil/scene-graph": "workspace:*",
|
"@open-pencil/scene-graph": "workspace:*",
|
||||||
"agentfmt": "^0.1.3",
|
"agentfmt": "^0.1.3",
|
||||||
"canvaskit-wasm": "^0.40.0",
|
"canvaskit-wasm": "^0.41.1",
|
||||||
"citty": "^0.1.6"
|
"citty": "^0.1.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
||||||
|
|
@ -181,7 +181,7 @@
|
||||||
"@tauri-apps/api": "^2.11.1",
|
"@tauri-apps/api": "^2.11.1",
|
||||||
"@xmldom/xmldom": "^0.9.11",
|
"@xmldom/xmldom": "^0.9.11",
|
||||||
"acorn": "^8.18.0",
|
"acorn": "^8.18.0",
|
||||||
"canvaskit-wasm": "^0.40.0",
|
"canvaskit-wasm": "^0.41.1",
|
||||||
"culori": "^4.0.2",
|
"culori": "^4.0.2",
|
||||||
"destr": "^2.0.5",
|
"destr": "^2.0.5",
|
||||||
"diff": "^8.0.4",
|
"diff": "^8.0.4",
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import type { Canvas, Path, PathOp } from 'canvaskit-wasm'
|
import type { Canvas, Path, PathBuilder, PathOp } from 'canvaskit-wasm'
|
||||||
|
|
||||||
import type { SceneGraph, SceneNode } from '@open-pencil/scene-graph'
|
import type { SceneGraph, SceneNode } from '@open-pencil/scene-graph'
|
||||||
|
|
||||||
|
|
@ -63,12 +63,13 @@ export function canMakeBooleanSourceNode(node: SceneNode, graph: SceneGraph): bo
|
||||||
}
|
}
|
||||||
|
|
||||||
function lineStrokePath(r: SkiaRenderer, node: SceneNode): Path | null {
|
function lineStrokePath(r: SkiaRenderer, node: SceneNode): Path | null {
|
||||||
const path = new r.ck.Path()
|
const path = new r.ck.PathBuilder()
|
||||||
path.moveTo(0, 0)
|
path.moveTo(0, 0)
|
||||||
path.lineTo(node.width, node.height)
|
path.lineTo(node.width, node.height)
|
||||||
const stroke = node.strokes.find((item) => item.visible)
|
const stroke = node.strokes.find((item) => item.visible)
|
||||||
const outline = path.stroke({ width: stroke?.weight ?? 1 })
|
const source = path.detachAndDelete()
|
||||||
if (outline !== path) path.delete()
|
const outline = source.makeStroked({ width: stroke?.weight ?? 1 })
|
||||||
|
source.delete()
|
||||||
return outline
|
return outline
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,12 +90,13 @@ export function nodeHasVisibleStroke(node: SceneNode): boolean {
|
||||||
return node.strokes.some((stroke) => stroke.visible && stroke.weight > 0)
|
return node.strokes.some((stroke) => stroke.visible && stroke.weight > 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
function addVisibleStrokeOutlines(target: Path, source: Path, node: SceneNode): void {
|
function addVisibleStrokeOutlines(target: PathBuilder, source: Path, node: SceneNode): void {
|
||||||
for (const stroke of node.strokes) {
|
for (const stroke of node.strokes) {
|
||||||
if (!stroke.visible || stroke.weight <= 0) continue
|
if (!stroke.visible || stroke.weight <= 0) continue
|
||||||
const outline = source.stroke({ width: stroke.weight })
|
const outline = source.makeStroked({ width: stroke.weight })
|
||||||
if (!outline) continue
|
if (!outline) continue
|
||||||
target.addPath(outline)
|
target.addPath(outline)
|
||||||
|
outline.delete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,7 +113,7 @@ function appendVisibleChildPaths(
|
||||||
r: SkiaRenderer,
|
r: SkiaRenderer,
|
||||||
graph: SceneGraph,
|
graph: SceneGraph,
|
||||||
parent: SceneNode,
|
parent: SceneNode,
|
||||||
target: Path,
|
target: PathBuilder,
|
||||||
makeChildPath: (child: SceneNode) => Path | null,
|
makeChildPath: (child: SceneNode) => Path | null,
|
||||||
failOnMissing: boolean
|
failOnMissing: boolean
|
||||||
): boolean | null {
|
): boolean | null {
|
||||||
|
|
@ -124,8 +126,7 @@ function appendVisibleChildPaths(
|
||||||
if (failOnMissing) return null
|
if (failOnMissing) return null
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
childPath.transform(nodePathTransform(r, child))
|
target.addPath(childPath, nodePathTransform(r, child))
|
||||||
target.addPath(childPath)
|
|
||||||
childPath.delete()
|
childPath.delete()
|
||||||
hasPath = true
|
hasPath = true
|
||||||
}
|
}
|
||||||
|
|
@ -133,7 +134,7 @@ function appendVisibleChildPaths(
|
||||||
}
|
}
|
||||||
|
|
||||||
function containerSourcePath(r: SkiaRenderer, node: SceneNode, graph: SceneGraph): Path | null {
|
function containerSourcePath(r: SkiaRenderer, node: SceneNode, graph: SceneGraph): Path | null {
|
||||||
const path = new r.ck.Path()
|
const path = new r.ck.PathBuilder()
|
||||||
let hasPath = false
|
let hasPath = false
|
||||||
|
|
||||||
if (nodeHasVisibleFill(node) || nodeHasVisibleStroke(node)) {
|
if (nodeHasVisibleFill(node) || nodeHasVisibleStroke(node)) {
|
||||||
|
|
@ -164,7 +165,7 @@ function containerSourcePath(r: SkiaRenderer, node: SceneNode, graph: SceneGraph
|
||||||
path.delete()
|
path.delete()
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return path
|
return path.detachAndDelete()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeBooleanSourcePath(
|
export function makeBooleanSourcePath(
|
||||||
|
|
@ -179,8 +180,12 @@ export function makeBooleanSourcePath(
|
||||||
|
|
||||||
const path = baseShapePath(r, node)
|
const path = baseShapePath(r, node)
|
||||||
if (!path) return null
|
if (!path) return null
|
||||||
if (nodeHasVisibleStroke(node)) addVisibleStrokeOutlines(path, path, node)
|
if (!nodeHasVisibleStroke(node)) return path
|
||||||
return path
|
const combined = new r.ck.PathBuilder()
|
||||||
|
combined.addPath(path)
|
||||||
|
addVisibleStrokeOutlines(combined, path, node)
|
||||||
|
path.delete()
|
||||||
|
return combined.detachAndDelete()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function hasVisibleStrokeSourceNode(node: SceneNode, graph: SceneGraph): boolean {
|
export function hasVisibleStrokeSourceNode(node: SceneNode, graph: SceneGraph): boolean {
|
||||||
|
|
@ -199,7 +204,7 @@ export function makeStrokeOutlinePath(
|
||||||
): Path | null {
|
): Path | null {
|
||||||
if (!canMakeBooleanSourcePath(node)) return null
|
if (!canMakeBooleanSourcePath(node)) return null
|
||||||
if (canContainFlattenableChildren(node)) {
|
if (canContainFlattenableChildren(node)) {
|
||||||
const path = new r.ck.Path()
|
const path = new r.ck.PathBuilder()
|
||||||
let hasPath = false
|
let hasPath = false
|
||||||
if (nodeHasVisibleStroke(node)) {
|
if (nodeHasVisibleStroke(node)) {
|
||||||
const ownPath = baseShapePath(r, node)
|
const ownPath = baseShapePath(r, node)
|
||||||
|
|
@ -218,7 +223,7 @@ export function makeStrokeOutlinePath(
|
||||||
(child) => makeStrokeOutlinePath(r, child, graph),
|
(child) => makeStrokeOutlinePath(r, child, graph),
|
||||||
false
|
false
|
||||||
) ?? false
|
) ?? false
|
||||||
if (hasPath) return path
|
if (hasPath) return path.detachAndDelete()
|
||||||
path.delete()
|
path.delete()
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
@ -230,16 +235,19 @@ export function makeStrokeOutlinePath(
|
||||||
: baseShapePath(r, node)
|
: baseShapePath(r, node)
|
||||||
if (!path) return null
|
if (!path) return null
|
||||||
if (node.type === 'LINE') return path
|
if (node.type === 'LINE') return path
|
||||||
const outline = new r.ck.Path()
|
const outline = new r.ck.PathBuilder()
|
||||||
addVisibleStrokeOutlines(outline, path, node)
|
addVisibleStrokeOutlines(outline, path, node)
|
||||||
return outline
|
path.delete()
|
||||||
|
return outline.detachAndDelete()
|
||||||
}
|
}
|
||||||
|
|
||||||
function transformedShapePath(r: SkiaRenderer, child: SceneNode, graph: SceneGraph): Path | null {
|
function transformedShapePath(r: SkiaRenderer, child: SceneNode, graph: SceneGraph): Path | null {
|
||||||
const path = makeBooleanSourcePath(r, child, graph)
|
const path = makeBooleanSourcePath(r, child, graph)
|
||||||
if (!path) return null
|
if (!path) return null
|
||||||
path.transform(nodePathTransform(r, child))
|
const transformed = new r.ck.PathBuilder()
|
||||||
return path
|
transformed.addPath(path, nodePathTransform(r, child))
|
||||||
|
path.delete()
|
||||||
|
return transformed.detachAndDelete()
|
||||||
}
|
}
|
||||||
|
|
||||||
function operationForNode(r: SkiaRenderer, node: SceneNode): PathOp {
|
function operationForNode(r: SkiaRenderer, node: SceneNode): PathOp {
|
||||||
|
|
@ -251,9 +259,9 @@ function makeImportedFillGeometryPath(r: SkiaRenderer, node: SceneNode): Path |
|
||||||
if (typeof r.getFillGeometry !== 'function') return null
|
if (typeof r.getFillGeometry !== 'function') return null
|
||||||
const fillGeometry = r.getFillGeometry(node)
|
const fillGeometry = r.getFillGeometry(node)
|
||||||
if (!fillGeometry) return null
|
if (!fillGeometry) return null
|
||||||
const result = new r.ck.Path()
|
const result = new r.ck.PathBuilder()
|
||||||
for (const path of fillGeometry) result.addPath(path)
|
for (const path of fillGeometry) result.addPath(path)
|
||||||
return result
|
return result.detachAndDelete()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeBooleanOperationPath(
|
export function makeBooleanOperationPath(
|
||||||
|
|
@ -271,17 +279,18 @@ export function makeBooleanOperationPath(
|
||||||
|
|
||||||
if (childPaths.length === 0) return makeImportedFillGeometryPath(r, node)
|
if (childPaths.length === 0) return makeImportedFillGeometryPath(r, node)
|
||||||
|
|
||||||
const result = childPaths[0]
|
let result = childPaths[0]
|
||||||
const operation = operationForNode(r, node)
|
const operation = operationForNode(r, node)
|
||||||
for (let index = 1; index < childPaths.length; index++) {
|
for (let index = 1; index < childPaths.length; index++) {
|
||||||
const path = childPaths[index]
|
const path = childPaths[index]
|
||||||
const didApply = result.op(path, operation)
|
const combined = r.ck.Path.MakeFromOp(result, path, operation)
|
||||||
|
result.delete()
|
||||||
path.delete()
|
path.delete()
|
||||||
if (!didApply) {
|
if (!combined) {
|
||||||
result.delete()
|
|
||||||
for (const remaining of childPaths.slice(index + 1)) remaining.delete()
|
for (const remaining of childPaths.slice(index + 1)) remaining.delete()
|
||||||
return makeImportedFillGeometryPath(r, node)
|
return makeImportedFillGeometryPath(r, node)
|
||||||
}
|
}
|
||||||
|
result = combined
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -488,18 +488,19 @@ export function makeArcPath(r: SkiaRenderer, node: SceneNode) {
|
||||||
const endDeg = arc.endingAngle * (180 / Math.PI)
|
const endDeg = arc.endingAngle * (180 / Math.PI)
|
||||||
const sweepDeg = endDeg - startDeg
|
const sweepDeg = endDeg - startDeg
|
||||||
|
|
||||||
const path = new r.ck.Path()
|
const path = new r.ck.PathBuilder()
|
||||||
const oval = r.ck.LTRBRect(0, 0, node.width, node.height)
|
const oval = r.ck.LTRBRect(0, 0, node.width, node.height)
|
||||||
|
|
||||||
if (arc.innerRadius > 0) {
|
if (arc.innerRadius > 0) {
|
||||||
path.addArc(oval, startDeg, sweepDeg)
|
path.addArc(oval, startDeg, sweepDeg)
|
||||||
const innerOval = r.ck.LTRBRect(cx - innerRx, cy - innerRy, cx + innerRx, cy + innerRy)
|
const innerOval = r.ck.LTRBRect(cx - innerRx, cy - innerRy, cx + innerRx, cy + innerRy)
|
||||||
const innerPath = new r.ck.Path()
|
const innerPath = new r.ck.PathBuilder()
|
||||||
innerPath.addArc(innerOval, startDeg + sweepDeg, -sweepDeg)
|
innerPath.addArc(innerOval, startDeg + sweepDeg, -sweepDeg)
|
||||||
path.addPath(innerPath)
|
const immutableInnerPath = innerPath.detachAndDelete()
|
||||||
|
path.addPath(immutableInnerPath)
|
||||||
|
immutableInnerPath.delete()
|
||||||
path.close()
|
path.close()
|
||||||
innerPath.delete()
|
return path.detachAndDelete()
|
||||||
return path
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const isFullCircle = Math.abs(sweepDeg) >= 359.99
|
const isFullCircle = Math.abs(sweepDeg) >= 359.99
|
||||||
|
|
@ -510,7 +511,7 @@ export function makeArcPath(r: SkiaRenderer, node: SceneNode) {
|
||||||
path.addArc(oval, startDeg, sweepDeg)
|
path.addArc(oval, startDeg, sweepDeg)
|
||||||
path.close()
|
path.close()
|
||||||
}
|
}
|
||||||
return path
|
return path.detachAndDelete()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function drawArc(r: SkiaRenderer, canvas: Canvas, node: SceneNode, paint: Paint): void {
|
export function drawArc(r: SkiaRenderer, canvas: Canvas, node: SceneNode, paint: Paint): void {
|
||||||
|
|
|
||||||
|
|
@ -22,15 +22,14 @@ function nodesToVectorProps(
|
||||||
nodes: SceneNode[],
|
nodes: SceneNode[],
|
||||||
makeNodePath: NodePathFactory
|
makeNodePath: NodePathFactory
|
||||||
): VectorFlattenProps | null {
|
): VectorFlattenProps | null {
|
||||||
const path = new renderer.ck.Path()
|
const path = new renderer.ck.PathBuilder()
|
||||||
for (const node of nodes) {
|
for (const node of nodes) {
|
||||||
const nodePath = makeNodePath(renderer, graph, node)
|
const nodePath = makeNodePath(renderer, graph, node)
|
||||||
if (!nodePath) {
|
if (!nodePath) {
|
||||||
path.delete()
|
path.delete()
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
nodePath.transform(nodePathTransform(renderer, node))
|
path.addPath(nodePath, nodePathTransform(renderer, node))
|
||||||
path.addPath(nodePath)
|
|
||||||
nodePath.delete()
|
nodePath.delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,8 +40,9 @@ function nodesToVectorProps(
|
||||||
}
|
}
|
||||||
|
|
||||||
path.transform(renderer.ck.Matrix.translated(-bounds[0], -bounds[1]))
|
path.transform(renderer.ck.Matrix.translated(-bounds[0], -bounds[1]))
|
||||||
const vectorNetwork = parseSVGPath(path.toSVGString())
|
const immutablePath = path.detachAndDelete()
|
||||||
path.delete()
|
const vectorNetwork = parseSVGPath(immutablePath.toSVGString())
|
||||||
|
immutablePath.delete()
|
||||||
|
|
||||||
return {
|
return {
|
||||||
name: 'Flatten',
|
name: 'Flatten',
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ export function drawComponentLabels(r: SkiaRenderer, canvas: Canvas, graph: Scen
|
||||||
if (node.type === 'COMPONENT_SET') {
|
if (node.type === 'COMPONENT_SET') {
|
||||||
const s = iconR * 0.45
|
const s = iconR * 0.45
|
||||||
const gap = iconR * 0.2
|
const gap = iconR * 0.2
|
||||||
const path = new r.ck.Path()
|
const path = new r.ck.PathBuilder()
|
||||||
for (const [dx, dy] of [
|
for (const [dx, dy] of [
|
||||||
[-1, -1],
|
[-1, -1],
|
||||||
[1, -1],
|
[1, -1],
|
||||||
|
|
@ -153,17 +153,19 @@ export function drawComponentLabels(r: SkiaRenderer, canvas: Canvas, graph: Scen
|
||||||
path.lineTo(cx - s, cy)
|
path.lineTo(cx - s, cy)
|
||||||
path.close()
|
path.close()
|
||||||
}
|
}
|
||||||
canvas.drawPath(path, r.auxFill)
|
const immutablePath = path.detachAndDelete()
|
||||||
path.delete()
|
canvas.drawPath(immutablePath, r.auxFill)
|
||||||
|
immutablePath.delete()
|
||||||
} else {
|
} else {
|
||||||
const path = new r.ck.Path()
|
const path = new r.ck.PathBuilder()
|
||||||
path.moveTo(iconCx, iconCy - iconR)
|
path.moveTo(iconCx, iconCy - iconR)
|
||||||
path.lineTo(iconCx + iconR, iconCy)
|
path.lineTo(iconCx + iconR, iconCy)
|
||||||
path.lineTo(iconCx, iconCy + iconR)
|
path.lineTo(iconCx, iconCy + iconR)
|
||||||
path.lineTo(iconCx - iconR, iconCy)
|
path.lineTo(iconCx - iconR, iconCy)
|
||||||
path.close()
|
path.close()
|
||||||
canvas.drawPath(path, r.auxFill)
|
const immutablePath = path.detachAndDelete()
|
||||||
path.delete()
|
canvas.drawPath(immutablePath, r.auxFill)
|
||||||
|
immutablePath.delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.drawText(displayText, labelX + iconS + COMPONENT_LABEL_ICON_GAP, labelY, r.auxFill, font)
|
canvas.drawText(displayText, labelX + iconS + COMPONENT_LABEL_ICON_GAP, labelY, r.auxFill, font)
|
||||||
|
|
|
||||||
|
|
@ -415,17 +415,18 @@ function drawHandleDiamond(
|
||||||
strokePaint: Paint
|
strokePaint: Paint
|
||||||
): void {
|
): void {
|
||||||
const s = PEN_HANDLE_RADIUS
|
const s = PEN_HANDLE_RADIUS
|
||||||
const path = new r.ck.Path()
|
const path = new r.ck.PathBuilder()
|
||||||
path.moveTo(x, y - s)
|
path.moveTo(x, y - s)
|
||||||
path.lineTo(x + s, y)
|
path.lineTo(x + s, y)
|
||||||
path.lineTo(x, y + s)
|
path.lineTo(x, y + s)
|
||||||
path.lineTo(x - s, y)
|
path.lineTo(x - s, y)
|
||||||
path.close()
|
path.close()
|
||||||
|
|
||||||
|
const immutablePath = path.detachAndDelete()
|
||||||
// Draw stroke first (outset) then fill on top
|
// Draw stroke first (outset) then fill on top
|
||||||
canvas.drawPath(path, strokePaint)
|
canvas.drawPath(immutablePath, strokePaint)
|
||||||
canvas.drawPath(path, fillPaint)
|
canvas.drawPath(immutablePath, fillPaint)
|
||||||
path.delete()
|
immutablePath.delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ function drawStripedRect(
|
||||||
r.auxFill.setColor(canvasColor(r, fill))
|
r.auxFill.setColor(canvasColor(r, fill))
|
||||||
canvas.drawRect(rect, r.auxFill)
|
canvas.drawRect(rect, r.auxFill)
|
||||||
|
|
||||||
const path = new r.ck.Path()
|
const path = new r.ck.PathBuilder()
|
||||||
const left = rect[0]
|
const left = rect[0]
|
||||||
const top = rect[1]
|
const top = rect[1]
|
||||||
const right = rect[2]
|
const right = rect[2]
|
||||||
|
|
@ -98,9 +98,10 @@ function drawStripedRect(
|
||||||
r.auxStroke.setPathEffect(null)
|
r.auxStroke.setPathEffect(null)
|
||||||
canvas.save()
|
canvas.save()
|
||||||
canvas.clipRect(rect, r.ck.ClipOp.Intersect, true)
|
canvas.clipRect(rect, r.ck.ClipOp.Intersect, true)
|
||||||
canvas.drawPath(path, r.auxStroke)
|
const immutablePath = path.detachAndDelete()
|
||||||
|
canvas.drawPath(immutablePath, r.auxStroke)
|
||||||
canvas.restore()
|
canvas.restore()
|
||||||
path.delete()
|
immutablePath.delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawValuePill(r: SkiaRenderer, canvas: Canvas, text: string, x: number, y: number) {
|
function drawValuePill(r: SkiaRenderer, canvas: Canvas, text: string, x: number, y: number) {
|
||||||
|
|
|
||||||
|
|
@ -194,14 +194,15 @@ function drawTargetOutline(r: SkiaRenderer, canvas: Canvas, graph: SceneGraph, t
|
||||||
0,
|
0,
|
||||||
target.height
|
target.height
|
||||||
])
|
])
|
||||||
const path = new r.ck.Path()
|
const path = new r.ck.PathBuilder()
|
||||||
path.moveTo(points[0], points[1])
|
path.moveTo(points[0], points[1])
|
||||||
path.lineTo(points[2], points[3])
|
path.lineTo(points[2], points[3])
|
||||||
path.lineTo(points[4], points[5])
|
path.lineTo(points[4], points[5])
|
||||||
path.lineTo(points[6], points[7])
|
path.lineTo(points[6], points[7])
|
||||||
path.close()
|
path.close()
|
||||||
canvas.drawPath(path, r.auxStroke)
|
const immutablePath = path.detachAndDelete()
|
||||||
path.delete()
|
canvas.drawPath(immutablePath, r.auxStroke)
|
||||||
|
immutablePath.delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function drawMeasurements(
|
export function drawMeasurements(
|
||||||
|
|
|
||||||
|
|
@ -230,17 +230,18 @@ function drawTextPathSelection(
|
||||||
// the path (replaces the flat, path-blind text-edit selection rects).
|
// the path (replaces the flat, path-blind text-edit selection rects).
|
||||||
const bandPoly = pathTextSelectionBand(data, box, node.derivedTextGlyphs, sampled)
|
const bandPoly = pathTextSelectionBand(data, box, node.derivedTextGlyphs, sampled)
|
||||||
if (bandPoly && bandPoly.length >= 6) {
|
if (bandPoly && bandPoly.length >= 6) {
|
||||||
const band = new r.ck.Path()
|
const band = new r.ck.PathBuilder()
|
||||||
band.moveTo(bandPoly[0], bandPoly[1])
|
band.moveTo(bandPoly[0], bandPoly[1])
|
||||||
for (let i = 2; i < bandPoly.length; i += 2) band.lineTo(bandPoly[i], bandPoly[i + 1])
|
for (let i = 2; i < bandPoly.length; i += 2) band.lineTo(bandPoly[i], bandPoly[i + 1])
|
||||||
band.close()
|
band.close()
|
||||||
|
const immutableBand = band.detachAndDelete()
|
||||||
r.auxFill.setColor(r.selColor(0.16))
|
r.auxFill.setColor(r.selColor(0.16))
|
||||||
canvas.drawPath(band, r.auxFill)
|
canvas.drawPath(immutableBand, r.auxFill)
|
||||||
r.auxStroke.setStrokeWidth(1 / r.zoom)
|
r.auxStroke.setStrokeWidth(1 / r.zoom)
|
||||||
r.auxStroke.setColor(r.selColor())
|
r.auxStroke.setColor(r.selColor())
|
||||||
r.auxStroke.setPathEffect(null)
|
r.auxStroke.setPathEffect(null)
|
||||||
canvas.drawPath(band, r.auxStroke)
|
canvas.drawPath(immutableBand, r.auxStroke)
|
||||||
band.delete()
|
immutableBand.delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Faint dashed bounds + resize/rotate handles from the fitted path box.
|
// Faint dashed bounds + resize/rotate handles from the fitted path box.
|
||||||
|
|
@ -256,7 +257,7 @@ function drawTextPathSelection(
|
||||||
drawBoundsHandles(r, canvas, box.x, box.y, box.x + box.width, box.y + box.height)
|
drawBoundsHandles(r, canvas, box.x, box.y, box.x + box.width, box.y + box.height)
|
||||||
|
|
||||||
// The path curve itself, sampled from the headless path metrics only for drawing.
|
// The path curve itself, sampled from the headless path metrics only for drawing.
|
||||||
const path = new r.ck.Path()
|
const path = new r.ck.PathBuilder()
|
||||||
const overlaySteps = Math.max(64, Math.min(1024, Math.ceil(sampled.length)))
|
const overlaySteps = Math.max(64, Math.min(1024, Math.ceil(sampled.length)))
|
||||||
const first = pointAtArc(sampled, 0)
|
const first = pointAtArc(sampled, 0)
|
||||||
path.moveTo(first.x, first.y)
|
path.moveTo(first.x, first.y)
|
||||||
|
|
@ -265,8 +266,9 @@ function drawTextPathSelection(
|
||||||
path.lineTo(point.x, point.y)
|
path.lineTo(point.x, point.y)
|
||||||
}
|
}
|
||||||
if (sampled.closed) path.close()
|
if (sampled.closed) path.close()
|
||||||
canvas.drawPath(path, r.selectionPaint)
|
const immutablePath = path.detachAndDelete()
|
||||||
path.delete()
|
canvas.drawPath(immutablePath, r.selectionPaint)
|
||||||
|
immutablePath.delete()
|
||||||
|
|
||||||
// Center crosshair at the fitted path box center (screen-constant size).
|
// Center crosshair at the fitted path box center (screen-constant size).
|
||||||
const cx = box.x + box.width / 2
|
const cx = box.x + box.width / 2
|
||||||
|
|
@ -367,14 +369,16 @@ export function drawParentFrameOutlines(
|
||||||
parent.height
|
parent.height
|
||||||
])
|
])
|
||||||
|
|
||||||
const path = new r.ck.Path()
|
const path = new r.ck.PathBuilder()
|
||||||
path.moveTo(pts[0], pts[1])
|
path.moveTo(pts[0], pts[1])
|
||||||
path.lineTo(pts[2], pts[3])
|
path.lineTo(pts[2], pts[3])
|
||||||
path.lineTo(pts[4], pts[5])
|
path.lineTo(pts[4], pts[5])
|
||||||
path.lineTo(pts[6], pts[7])
|
path.lineTo(pts[6], pts[7])
|
||||||
path.close()
|
path.close()
|
||||||
|
|
||||||
canvas.drawPath(path, r.parentOutlinePaint)
|
const immutablePath = path.detachAndDelete()
|
||||||
|
canvas.drawPath(immutablePath, r.parentOutlinePaint)
|
||||||
|
immutablePath.delete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ function buildSegmentsPath(
|
||||||
toScreen: ToScreenFn
|
toScreen: ToScreenFn
|
||||||
): InstanceType<typeof r.ck.Path> {
|
): InstanceType<typeof r.ck.Path> {
|
||||||
const { vertices, segments } = penState
|
const { vertices, segments } = penState
|
||||||
const path = new r.ck.Path()
|
const path = new r.ck.PathBuilder()
|
||||||
for (const seg of segments) {
|
for (const seg of segments) {
|
||||||
const s = toScreen(vertices[seg.start].x, vertices[seg.start].y)
|
const s = toScreen(vertices[seg.start].x, vertices[seg.start].y)
|
||||||
const e = toScreen(vertices[seg.end].x, vertices[seg.end].y)
|
const e = toScreen(vertices[seg.end].x, vertices[seg.end].y)
|
||||||
|
|
@ -43,7 +43,7 @@ function buildSegmentsPath(
|
||||||
path.cubicTo(cp1.x, cp1.y, cp2.x, cp2.y, e.x, e.y)
|
path.cubicTo(cp1.x, cp1.y, cp2.x, cp2.y, e.x, e.y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return path
|
return path.detachAndDelete()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Build a Path for the preview line from last vertex to cursor */
|
/** Build a Path for the preview line from last vertex to cursor */
|
||||||
|
|
@ -56,7 +56,7 @@ function buildCursorPath(
|
||||||
if (vertices.length === 0) return null
|
if (vertices.length === 0) return null
|
||||||
|
|
||||||
if (penState.pendingClose && vertices.length > 2) {
|
if (penState.pendingClose && vertices.length > 2) {
|
||||||
const path = new r.ck.Path()
|
const path = new r.ck.PathBuilder()
|
||||||
const last = toScreen(vertices[vertices.length - 1].x, vertices[vertices.length - 1].y)
|
const last = toScreen(vertices[vertices.length - 1].x, vertices[vertices.length - 1].y)
|
||||||
const first = toScreen(vertices[0].x, vertices[0].y)
|
const first = toScreen(vertices[0].x, vertices[0].y)
|
||||||
path.moveTo(last.x, last.y)
|
path.moveTo(last.x, last.y)
|
||||||
|
|
@ -67,12 +67,12 @@ function buildCursorPath(
|
||||||
} else {
|
} else {
|
||||||
path.lineTo(first.x, first.y)
|
path.lineTo(first.x, first.y)
|
||||||
}
|
}
|
||||||
return path
|
return path.detachAndDelete()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursorX == null || cursorY == null) return null
|
if (cursorX == null || cursorY == null) return null
|
||||||
|
|
||||||
const path = new r.ck.Path()
|
const path = new r.ck.PathBuilder()
|
||||||
const last = toScreen(vertices[vertices.length - 1].x, vertices[vertices.length - 1].y)
|
const last = toScreen(vertices[vertices.length - 1].x, vertices[vertices.length - 1].y)
|
||||||
const cursor = toScreen(cursorX, cursorY)
|
const cursor = toScreen(cursorX, cursorY)
|
||||||
path.moveTo(last.x, last.y)
|
path.moveTo(last.x, last.y)
|
||||||
|
|
@ -85,7 +85,7 @@ function buildCursorPath(
|
||||||
} else {
|
} else {
|
||||||
path.lineTo(cursor.x, cursor.y)
|
path.lineTo(cursor.x, cursor.y)
|
||||||
}
|
}
|
||||||
return path
|
return path.detachAndDelete()
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawPenPaths(
|
function drawPenPaths(
|
||||||
|
|
@ -234,19 +234,20 @@ export function drawRemoteCursors(
|
||||||
0,
|
0,
|
||||||
node.height
|
node.height
|
||||||
])
|
])
|
||||||
const box = new r.ck.Path()
|
const box = new r.ck.PathBuilder()
|
||||||
box.moveTo(c[0] * r.zoom + r.panX, c[1] * r.zoom + r.panY)
|
box.moveTo(c[0] * r.zoom + r.panX, c[1] * r.zoom + r.panY)
|
||||||
for (let i = 2; i < c.length; i += 2) {
|
for (let i = 2; i < c.length; i += 2) {
|
||||||
box.lineTo(c[i] * r.zoom + r.panX, c[i + 1] * r.zoom + r.panY)
|
box.lineTo(c[i] * r.zoom + r.panX, c[i + 1] * r.zoom + r.panY)
|
||||||
}
|
}
|
||||||
box.close()
|
box.close()
|
||||||
canvas.drawPath(box, r.auxStroke)
|
const immutableBox = box.detachAndDelete()
|
||||||
box.delete()
|
canvas.drawPath(immutableBox, r.auxStroke)
|
||||||
|
immutableBox.delete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const S = CURSOR_SIZE
|
const S = CURSOR_SIZE
|
||||||
const path = new r.ck.Path()
|
const path = new r.ck.PathBuilder()
|
||||||
path.moveTo(screenX, screenY)
|
path.moveTo(screenX, screenY)
|
||||||
path.lineTo(screenX, screenY + S * 1.35)
|
path.lineTo(screenX, screenY + S * 1.35)
|
||||||
path.lineTo(screenX + S * 0.38, screenY + S * 1.0)
|
path.lineTo(screenX + S * 0.38, screenY + S * 1.0)
|
||||||
|
|
@ -256,14 +257,15 @@ export function drawRemoteCursors(
|
||||||
path.lineTo(screenX + S * 1.0, screenY + S * 0.82)
|
path.lineTo(screenX + S * 1.0, screenY + S * 0.82)
|
||||||
path.close()
|
path.close()
|
||||||
|
|
||||||
|
const immutablePath = path.detachAndDelete()
|
||||||
r.auxStroke.setColor(r.ck.Color4f(1, 1, 1, 1))
|
r.auxStroke.setColor(r.ck.Color4f(1, 1, 1, 1))
|
||||||
r.auxStroke.setStrokeWidth(2)
|
r.auxStroke.setStrokeWidth(2)
|
||||||
r.auxStroke.setPathEffect(null)
|
r.auxStroke.setPathEffect(null)
|
||||||
canvas.drawPath(path, r.auxStroke)
|
canvas.drawPath(immutablePath, r.auxStroke)
|
||||||
|
|
||||||
r.auxFill.setColor(r.ck.Color4f(cr, g, b, 1))
|
r.auxFill.setColor(r.ck.Color4f(cr, g, b, 1))
|
||||||
canvas.drawPath(path, r.auxFill)
|
canvas.drawPath(immutablePath, r.auxFill)
|
||||||
path.delete()
|
immutablePath.delete()
|
||||||
|
|
||||||
if (cursor.name) {
|
if (cursor.name) {
|
||||||
const font = r.labelFont
|
const font = r.labelFont
|
||||||
|
|
|
||||||
|
|
@ -461,7 +461,7 @@ function vectorStrokePaths(r: SkiaRenderer, node: SceneNode): Path[] | null {
|
||||||
const start = node.vectorNetwork.vertices[segment.start]
|
const start = node.vectorNetwork.vertices[segment.start]
|
||||||
const end = node.vectorNetwork.vertices[segment.end]
|
const end = node.vectorNetwork.vertices[segment.end]
|
||||||
|
|
||||||
const path = new r.ck.Path()
|
const path = new r.ck.PathBuilder()
|
||||||
path.moveTo(start.x, start.y)
|
path.moveTo(start.x, start.y)
|
||||||
const isStraight =
|
const isStraight =
|
||||||
Math.abs(segment.tangentStart.x) < 0.001 &&
|
Math.abs(segment.tangentStart.x) < 0.001 &&
|
||||||
|
|
@ -480,7 +480,7 @@ function vectorStrokePaths(r: SkiaRenderer, node: SceneNode): Path[] | null {
|
||||||
end.y
|
end.y
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
paths.push(path)
|
paths.push(path.detachAndDelete())
|
||||||
}
|
}
|
||||||
|
|
||||||
if (paths.length === 0) return null
|
if (paths.length === 0) return null
|
||||||
|
|
@ -527,7 +527,7 @@ function drawVectorPathStrokes(
|
||||||
if (!outlines) {
|
if (!outlines) {
|
||||||
outlines = []
|
outlines = []
|
||||||
for (const vp of vectorPaths) {
|
for (const vp of vectorPaths) {
|
||||||
const outline = vp.copy().stroke(strokeOpts)
|
const outline = vp.makeStroked(strokeOpts)
|
||||||
if (outline) outlines.push(outline)
|
if (outline) outlines.push(outline)
|
||||||
}
|
}
|
||||||
if (outlineCacheKey) r.vectorStrokeOutlineCache.set(outlineCacheKey, outlines)
|
if (outlineCacheKey) r.vectorStrokeOutlineCache.set(outlineCacheKey, outlines)
|
||||||
|
|
|
||||||
|
|
@ -141,15 +141,17 @@ function effectLayerBounds(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function applySpreadToPath(r: SkiaRenderer, path: Path, spread: number): boolean {
|
function pathWithSpread(r: SkiaRenderer, path: Path, spread: number): Path | null {
|
||||||
if (spread === 0) return true
|
if (spread === 0) return path.copy()
|
||||||
const ring = path.copy()
|
const ring = path.makeStroked({ width: Math.abs(spread) * 2, join: r.ck.StrokeJoin.Round })
|
||||||
try {
|
if (!ring) return null
|
||||||
if (!ring.stroke({ width: Math.abs(spread) * 2, join: r.ck.StrokeJoin.Round })) return false
|
const result = r.ck.Path.MakeFromOp(
|
||||||
return path.op(ring, spread > 0 ? r.ck.PathOp.Union : r.ck.PathOp.Difference)
|
path,
|
||||||
} finally {
|
ring,
|
||||||
ring.delete()
|
spread > 0 ? r.ck.PathOp.Union : r.ck.PathOp.Difference
|
||||||
}
|
)
|
||||||
|
ring.delete()
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawPathShape(
|
function drawPathShape(
|
||||||
|
|
@ -160,11 +162,13 @@ function drawPathShape(
|
||||||
spread = 0
|
spread = 0
|
||||||
): void {
|
): void {
|
||||||
const path = makeNodeShapePath(r, node, r.ltrb(0, 0, node.width, node.height), hasRadius)
|
const path = makeNodeShapePath(r, node, r.ltrb(0, 0, node.width, node.height), hasRadius)
|
||||||
|
const spreadPath = pathWithSpread(r, path, spread)
|
||||||
|
path.delete()
|
||||||
|
if (!spreadPath) return
|
||||||
try {
|
try {
|
||||||
applySpreadToPath(r, path, spread)
|
canvas.drawPath(spreadPath, r.auxFill)
|
||||||
canvas.drawPath(path, r.auxFill)
|
|
||||||
} finally {
|
} finally {
|
||||||
path.delete()
|
spreadPath.delete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -173,12 +177,12 @@ function drawShadowGeometryPath(r: SkiaRenderer, canvas: Canvas, path: Path, spr
|
||||||
canvas.drawPath(path, r.auxFill)
|
canvas.drawPath(path, r.auxFill)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const copy = path.copy()
|
const spreadPath = pathWithSpread(r, path, spread)
|
||||||
|
if (!spreadPath) return
|
||||||
try {
|
try {
|
||||||
applySpreadToPath(r, copy, spread)
|
canvas.drawPath(spreadPath, r.auxFill)
|
||||||
canvas.drawPath(copy, r.auxFill)
|
|
||||||
} finally {
|
} finally {
|
||||||
copy.delete()
|
spreadPath.delete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -420,9 +424,10 @@ function drawShapeInnerShadow(
|
||||||
if (shadowShapeChild) drawChildTransform(canvas, shadowShapeChild)
|
if (shadowShapeChild) drawChildTransform(canvas, shadowShapeChild)
|
||||||
|
|
||||||
if (shapeNode.type === 'ELLIPSE') {
|
if (shapeNode.type === 'ELLIPSE') {
|
||||||
const path = new r.ck.Path()
|
const builder = new r.ck.PathBuilder()
|
||||||
|
builder.addOval(shapeRect)
|
||||||
|
const path = builder.detachAndDelete()
|
||||||
try {
|
try {
|
||||||
path.addOval(shapeRect)
|
|
||||||
canvas.clipPath(path, r.ck.ClipOp.Intersect, true)
|
canvas.clipPath(path, r.ck.ClipOp.Intersect, true)
|
||||||
} finally {
|
} finally {
|
||||||
path.delete()
|
path.delete()
|
||||||
|
|
@ -454,66 +459,55 @@ function drawShapeInnerShadow(
|
||||||
Math.max(shapeNode.width + expand, shapeNode.width + expand + localOffsetX + spreadPadding),
|
Math.max(shapeNode.width + expand, shapeNode.width + expand + localOffsetX + spreadPadding),
|
||||||
Math.max(shapeNode.height + expand, shapeNode.height + expand + localOffsetY + spreadPadding)
|
Math.max(shapeNode.height + expand, shapeNode.height + expand + localOffsetY + spreadPadding)
|
||||||
)
|
)
|
||||||
const bigPath = new r.ck.Path()
|
const bigPathBuilder = new r.ck.PathBuilder()
|
||||||
try {
|
bigPathBuilder.addRect(big)
|
||||||
bigPath.addRect(big)
|
const bigPath = bigPathBuilder.detachAndDelete()
|
||||||
if (shapeNode.type === 'ELLIPSE') {
|
let innerPath: Path | null = null
|
||||||
const innerPath = new r.ck.Path()
|
if (shapeNode.type === 'ELLIPSE') {
|
||||||
try {
|
const builder = new r.ck.PathBuilder()
|
||||||
const offsetRect = r.ck.LTRBRect(
|
const offsetRect = r.ck.LTRBRect(
|
||||||
localOffsetX + sp,
|
localOffsetX + sp,
|
||||||
localOffsetY + sp,
|
localOffsetY + sp,
|
||||||
shapeNode.width + localOffsetX - sp,
|
shapeNode.width + localOffsetX - sp,
|
||||||
shapeNode.height + localOffsetY - sp
|
shapeNode.height + localOffsetY - sp
|
||||||
)
|
)
|
||||||
innerPath.addOval(offsetRect)
|
builder.addOval(offsetRect)
|
||||||
bigPath.op(innerPath, r.ck.PathOp.Difference)
|
innerPath = builder.detachAndDelete()
|
||||||
} finally {
|
} else if (isPathShape(shapeNode)) {
|
||||||
innerPath.delete()
|
const sourcePath = makeNodeShapePath(r, shapeNode, shapeRect, shapeHasRadius)
|
||||||
}
|
const transformedBuilder = new r.ck.PathBuilder()
|
||||||
} else if (isPathShape(shapeNode)) {
|
transformedBuilder.addPath(sourcePath, r.ck.Matrix.translated(localOffsetX, localOffsetY))
|
||||||
const innerPath = makeNodeShapePath(r, shapeNode, shapeRect, shapeHasRadius)
|
sourcePath.delete()
|
||||||
try {
|
const transformed = transformedBuilder.detachAndDelete()
|
||||||
innerPath.transform(r.ck.Matrix.translated(localOffsetX, localOffsetY))
|
innerPath = pathWithSpread(r, transformed, -sp)
|
||||||
applySpreadToPath(r, innerPath, -sp)
|
transformed.delete()
|
||||||
bigPath.op(innerPath, r.ck.PathOp.Difference)
|
} else if (nodeHasSmoothCorners(shapeNode)) {
|
||||||
} finally {
|
innerPath = makeSmoothRRectPath(r, shapeNode, -sp, localOffsetX, localOffsetY)
|
||||||
innerPath.delete()
|
} else if (shapeHasRadius) {
|
||||||
}
|
const builder = new r.ck.PathBuilder()
|
||||||
} else if (nodeHasSmoothCorners(shapeNode)) {
|
builder.addRRect(r.makeRRectWithOffset(shapeNode, localOffsetX, localOffsetY, sp))
|
||||||
const innerPath = makeSmoothRRectPath(r, shapeNode, -sp, localOffsetX, localOffsetY)
|
innerPath = builder.detachAndDelete()
|
||||||
try {
|
} else {
|
||||||
bigPath.op(innerPath, r.ck.PathOp.Difference)
|
const builder = new r.ck.PathBuilder()
|
||||||
} finally {
|
builder.addRect(
|
||||||
innerPath.delete()
|
r.ck.LTRBRect(
|
||||||
}
|
localOffsetX + sp,
|
||||||
} else if (shapeHasRadius) {
|
localOffsetY + sp,
|
||||||
const innerPath = new r.ck.Path()
|
shapeNode.width + localOffsetX - sp,
|
||||||
try {
|
shapeNode.height + localOffsetY - sp
|
||||||
innerPath.addRRect(r.makeRRectWithOffset(shapeNode, localOffsetX, localOffsetY, sp))
|
)
|
||||||
bigPath.op(innerPath, r.ck.PathOp.Difference)
|
)
|
||||||
} finally {
|
innerPath = builder.detachAndDelete()
|
||||||
innerPath.delete()
|
}
|
||||||
}
|
|
||||||
} else {
|
const shadowPath = innerPath
|
||||||
const innerPath = new r.ck.Path()
|
? r.ck.Path.MakeFromOp(bigPath, innerPath, r.ck.PathOp.Difference)
|
||||||
try {
|
: null
|
||||||
innerPath.addRect(
|
innerPath?.delete()
|
||||||
r.ck.LTRBRect(
|
bigPath.delete()
|
||||||
localOffsetX + sp,
|
if (shadowPath) {
|
||||||
localOffsetY + sp,
|
canvas.drawPath(shadowPath, r.auxFill)
|
||||||
shapeNode.width + localOffsetX - sp,
|
shadowPath.delete()
|
||||||
shapeNode.height + localOffsetY - sp
|
|
||||||
)
|
|
||||||
)
|
|
||||||
bigPath.op(innerPath, r.ck.PathOp.Difference)
|
|
||||||
} finally {
|
|
||||||
innerPath.delete()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
canvas.drawPath(bigPath, r.auxFill)
|
|
||||||
} finally {
|
|
||||||
bigPath.delete()
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
canvas.restore()
|
canvas.restore()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import type { Canvas, Path } from 'canvaskit-wasm'
|
import type { Canvas, Path, PathBuilder } from 'canvaskit-wasm'
|
||||||
|
|
||||||
import type { SceneNode } from '@open-pencil/scene-graph'
|
import type { SceneNode } from '@open-pencil/scene-graph'
|
||||||
import { polygonVertices } from '@open-pencil/scene-graph/geometry'
|
import { polygonVertices } from '@open-pencil/scene-graph/geometry'
|
||||||
|
|
@ -170,7 +170,7 @@ function smoothCornerPathParams(corner: SmoothCorner, smoothing: number): Smooth
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawTopRightSmoothCorner(
|
function drawTopRightSmoothCorner(
|
||||||
path: Path,
|
path: PathBuilder,
|
||||||
corner: SmoothCornerPathParams,
|
corner: SmoothCornerPathParams,
|
||||||
x: number,
|
x: number,
|
||||||
y: number
|
y: number
|
||||||
|
|
@ -207,7 +207,7 @@ function drawTopRightSmoothCorner(
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawBottomRightSmoothCorner(
|
function drawBottomRightSmoothCorner(
|
||||||
path: Path,
|
path: PathBuilder,
|
||||||
corner: SmoothCornerPathParams,
|
corner: SmoothCornerPathParams,
|
||||||
x: number,
|
x: number,
|
||||||
y: number
|
y: number
|
||||||
|
|
@ -244,7 +244,7 @@ function drawBottomRightSmoothCorner(
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawBottomLeftSmoothCorner(
|
function drawBottomLeftSmoothCorner(
|
||||||
path: Path,
|
path: PathBuilder,
|
||||||
corner: SmoothCornerPathParams,
|
corner: SmoothCornerPathParams,
|
||||||
x: number,
|
x: number,
|
||||||
y: number
|
y: number
|
||||||
|
|
@ -280,7 +280,12 @@ function drawBottomLeftSmoothCorner(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function drawTopLeftSmoothCorner(path: Path, corner: SmoothCornerPathParams, x: number, y: number) {
|
function drawTopLeftSmoothCorner(
|
||||||
|
path: PathBuilder,
|
||||||
|
corner: SmoothCornerPathParams,
|
||||||
|
x: number,
|
||||||
|
y: number
|
||||||
|
) {
|
||||||
if (corner.radius === 0) {
|
if (corner.radius === 0) {
|
||||||
path.lineTo(x, y - corner.p)
|
path.lineTo(x, y - corner.p)
|
||||||
return
|
return
|
||||||
|
|
@ -319,7 +324,7 @@ export function makeSmoothRRectPath(
|
||||||
offsetX = 0,
|
offsetX = 0,
|
||||||
offsetY = 0
|
offsetY = 0
|
||||||
): Path {
|
): Path {
|
||||||
const path = new r.ck.Path()
|
const path = new r.ck.PathBuilder()
|
||||||
const left = offsetX - spread
|
const left = offsetX - spread
|
||||||
const top = offsetY - spread
|
const top = offsetY - spread
|
||||||
const right = offsetX + node.width + spread
|
const right = offsetX + node.width + spread
|
||||||
|
|
@ -328,7 +333,7 @@ export function makeSmoothRRectPath(
|
||||||
const height = bottom - top
|
const height = bottom - top
|
||||||
if (width <= 0 || height <= 0) {
|
if (width <= 0 || height <= 0) {
|
||||||
path.addRect(r.ck.LTRBRect(left, top, Math.max(left, right), Math.max(top, bottom)))
|
path.addRect(r.ck.LTRBRect(left, top, Math.max(left, right), Math.max(top, bottom)))
|
||||||
return path
|
return path.detachAndDelete()
|
||||||
}
|
}
|
||||||
|
|
||||||
const smoothing = Math.max(0, Math.min(node.cornerSmoothing, 1))
|
const smoothing = Math.max(0, Math.min(node.cornerSmoothing, 1))
|
||||||
|
|
@ -345,7 +350,7 @@ export function makeSmoothRRectPath(
|
||||||
bottomLeftCorner.radius === 0
|
bottomLeftCorner.radius === 0
|
||||||
) {
|
) {
|
||||||
path.addRect(r.ck.LTRBRect(left, top, right, bottom))
|
path.addRect(r.ck.LTRBRect(left, top, right, bottom))
|
||||||
return path
|
return path.detachAndDelete()
|
||||||
}
|
}
|
||||||
|
|
||||||
path.moveTo(right - topRightCorner.p, top)
|
path.moveTo(right - topRightCorner.p, top)
|
||||||
|
|
@ -357,7 +362,7 @@ export function makeSmoothRRectPath(
|
||||||
path.lineTo(left, top + topLeftCorner.p)
|
path.lineTo(left, top + topLeftCorner.p)
|
||||||
drawTopLeftSmoothCorner(path, topLeftCorner, left, top + topLeftCorner.p)
|
drawTopLeftSmoothCorner(path, topLeftCorner, left, top + topLeftCorner.p)
|
||||||
path.close()
|
path.close()
|
||||||
return path
|
return path.detachAndDelete()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeNodeShapePath(
|
export function makeNodeShapePath(
|
||||||
|
|
@ -366,7 +371,7 @@ export function makeNodeShapePath(
|
||||||
rect: Float32Array,
|
rect: Float32Array,
|
||||||
hasRadius: boolean
|
hasRadius: boolean
|
||||||
): Path {
|
): Path {
|
||||||
const path = new r.ck.Path()
|
const path = new r.ck.PathBuilder()
|
||||||
switch (node.type) {
|
switch (node.type) {
|
||||||
case 'ELLIPSE':
|
case 'ELLIPSE':
|
||||||
path.addOval(rect)
|
path.addOval(rect)
|
||||||
|
|
@ -396,17 +401,17 @@ export function makeNodeShapePath(
|
||||||
path.addRect(rect)
|
path.addRect(rect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return path
|
return path.detachAndDelete()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makePolygonPath(r: SkiaRenderer, node: SceneNode): Path {
|
export function makePolygonPath(r: SkiaRenderer, node: SceneNode): Path {
|
||||||
const path = new r.ck.Path()
|
const path = new r.ck.PathBuilder()
|
||||||
polygonVertices(node).forEach((point, index) => {
|
polygonVertices(node).forEach((point, index) => {
|
||||||
if (index === 0) path.moveTo(point.x, point.y)
|
if (index === 0) path.moveTo(point.x, point.y)
|
||||||
else path.lineTo(point.x, point.y)
|
else path.lineTo(point.x, point.y)
|
||||||
})
|
})
|
||||||
path.close()
|
path.close()
|
||||||
return path
|
return path.detachAndDelete()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function makeRRect(r: SkiaRenderer, node: SceneNode): Float32Array {
|
export function makeRRect(r: SkiaRenderer, node: SceneNode): Float32Array {
|
||||||
|
|
@ -500,10 +505,11 @@ export function clipNodeShape(
|
||||||
hasRadius: boolean
|
hasRadius: boolean
|
||||||
): void {
|
): void {
|
||||||
if (node.type === 'ELLIPSE') {
|
if (node.type === 'ELLIPSE') {
|
||||||
const clipPath = new r.ck.Path()
|
const clipPath = new r.ck.PathBuilder()
|
||||||
clipPath.addOval(rect)
|
clipPath.addOval(rect)
|
||||||
canvas.clipPath(clipPath, r.ck.ClipOp.Intersect, true)
|
const immutableClipPath = clipPath.detachAndDelete()
|
||||||
clipPath.delete()
|
canvas.clipPath(immutableClipPath, r.ck.ClipOp.Intersect, true)
|
||||||
|
immutableClipPath.delete()
|
||||||
} else if (nodeHasSmoothCorners(node)) {
|
} else if (nodeHasSmoothCorners(node)) {
|
||||||
const clipPath = makeSmoothRRectPath(r, node)
|
const clipPath = makeSmoothRRectPath(r, node)
|
||||||
canvas.clipPath(clipPath, r.ck.ClipOp.Intersect, true)
|
canvas.clipPath(clipPath, r.ck.ClipOp.Intersect, true)
|
||||||
|
|
|
||||||
|
|
@ -191,13 +191,19 @@ export function drawStrokeWithAlign(
|
||||||
} else if (align === 'OUTSIDE') {
|
} else if (align === 'OUTSIDE') {
|
||||||
canvas.save()
|
canvas.save()
|
||||||
const bigRect = r.ck.LTRBRect(-node.width, -node.height, node.width * 2, node.height * 2)
|
const bigRect = r.ck.LTRBRect(-node.width, -node.height, node.width * 2, node.height * 2)
|
||||||
const outerPath = new r.ck.Path()
|
const outerPath = new r.ck.PathBuilder()
|
||||||
outerPath.addRect(bigRect)
|
outerPath.addRect(bigRect)
|
||||||
const innerPath = r.makeNodeShapePath(node, rect, hasRadius)
|
const innerPath = r.makeNodeShapePath(node, rect, hasRadius)
|
||||||
outerPath.op(innerPath, r.ck.PathOp.Difference)
|
const immutableOuterPath = outerPath.detachAndDelete()
|
||||||
|
const clipPath = r.ck.Path.MakeFromOp(immutableOuterPath, innerPath, r.ck.PathOp.Difference)
|
||||||
|
immutableOuterPath.delete()
|
||||||
innerPath.delete()
|
innerPath.delete()
|
||||||
canvas.clipPath(outerPath, r.ck.ClipOp.Intersect, true)
|
if (!clipPath) {
|
||||||
outerPath.delete()
|
canvas.restore()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
canvas.clipPath(clipPath, r.ck.ClipOp.Intersect, true)
|
||||||
|
clipPath.delete()
|
||||||
const origWidth = r.strokePaint.getStrokeWidth()
|
const origWidth = r.strokePaint.getStrokeWidth()
|
||||||
r.strokePaint.setStrokeWidth(origWidth * 2)
|
r.strokePaint.setStrokeWidth(origWidth * 2)
|
||||||
r.drawNodeStroke(canvas, node, rect, hasRadius)
|
r.drawNodeStroke(canvas, node, rect, hasRadius)
|
||||||
|
|
@ -236,14 +242,25 @@ export function drawRRectStrokeWithAlign(
|
||||||
canvas.restore()
|
canvas.restore()
|
||||||
} else if (stroke.align === 'OUTSIDE') {
|
} else if (stroke.align === 'OUTSIDE') {
|
||||||
canvas.save()
|
canvas.save()
|
||||||
const outerPath = new r.ck.Path()
|
const outerPath = new r.ck.PathBuilder()
|
||||||
outerPath.addRect(r.ck.LTRBRect(-node.width, -node.height, node.width * 2, node.height * 2))
|
outerPath.addRect(r.ck.LTRBRect(-node.width, -node.height, node.width * 2, node.height * 2))
|
||||||
const innerPath = new r.ck.Path()
|
const innerPath = new r.ck.PathBuilder()
|
||||||
innerPath.addRRect(rrect)
|
innerPath.addRRect(rrect)
|
||||||
outerPath.op(innerPath, r.ck.PathOp.Difference)
|
const immutableOuterPath = outerPath.detachAndDelete()
|
||||||
innerPath.delete()
|
const immutableInnerPath = innerPath.detachAndDelete()
|
||||||
canvas.clipPath(outerPath, r.ck.ClipOp.Intersect, true)
|
const clipPath = r.ck.Path.MakeFromOp(
|
||||||
outerPath.delete()
|
immutableOuterPath,
|
||||||
|
immutableInnerPath,
|
||||||
|
r.ck.PathOp.Difference
|
||||||
|
)
|
||||||
|
immutableOuterPath.delete()
|
||||||
|
immutableInnerPath.delete()
|
||||||
|
if (!clipPath) {
|
||||||
|
canvas.restore()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
canvas.clipPath(clipPath, r.ck.ClipOp.Intersect, true)
|
||||||
|
clipPath.delete()
|
||||||
r.strokePaint.setStrokeWidth(stroke.weight * 2)
|
r.strokePaint.setStrokeWidth(stroke.weight * 2)
|
||||||
canvas.drawRRect(rrect, r.strokePaint)
|
canvas.drawRRect(rrect, r.strokePaint)
|
||||||
r.strokePaint.setStrokeWidth(stroke.weight)
|
r.strokePaint.setStrokeWidth(stroke.weight)
|
||||||
|
|
|
||||||
|
|
@ -183,14 +183,15 @@ function drawWavyDecoration(
|
||||||
): void {
|
): void {
|
||||||
const amplitude = Math.max(0.5, span.thickness * 0.5)
|
const amplitude = Math.max(0.5, span.thickness * 0.5)
|
||||||
const wavelength = Math.max(6, span.thickness * 5)
|
const wavelength = Math.max(6, span.thickness * 5)
|
||||||
const path = new r.ck.Path()
|
const path = new r.ck.PathBuilder()
|
||||||
path.moveTo(span.x1, y)
|
path.moveTo(span.x1, y)
|
||||||
for (let x = span.x1; x <= span.x2; x += 2) {
|
for (let x = span.x1; x <= span.x2; x += 2) {
|
||||||
path.lineTo(x, y + Math.sin(((x - span.x1) / wavelength) * Math.PI * 2) * amplitude)
|
path.lineTo(x, y + Math.sin(((x - span.x1) / wavelength) * Math.PI * 2) * amplitude)
|
||||||
}
|
}
|
||||||
path.lineTo(span.x2, y)
|
path.lineTo(span.x2, y)
|
||||||
canvas.drawPath(path, paint)
|
const immutablePath = path.detachAndDelete()
|
||||||
path.delete()
|
canvas.drawPath(immutablePath, paint)
|
||||||
|
immutablePath.delete()
|
||||||
}
|
}
|
||||||
|
|
||||||
function derivedDecorationY(node: SceneNode, span: DecorationSpan, baselineY: number): number {
|
function derivedDecorationY(node: SceneNode, span: DecorationSpan, baselineY: number): number {
|
||||||
|
|
@ -278,27 +279,29 @@ function getGlyphSilhouette(
|
||||||
// Round join/cap: miter spikes on glyph cusps (e.g. 'A' apex) shoot far
|
// Round join/cap: miter spikes on glyph cusps (e.g. 'A' apex) shoot far
|
||||||
// outside the letterform. Width doubles because half the band is swallowed
|
// outside the letterform. Width doubles because half the band is swallowed
|
||||||
// by the union with the glyph body (OUTSIDE-stroke look).
|
// by the union with the glyph body (OUTSIDE-stroke look).
|
||||||
const stroked = outline.stroke({
|
const stroked = outline.makeStroked({
|
||||||
width: relativeWeight * 2,
|
width: relativeWeight * 2,
|
||||||
join: r.ck.StrokeJoin.Round,
|
join: r.ck.StrokeJoin.Round,
|
||||||
cap: r.ck.StrokeCap.Round
|
cap: r.ck.StrokeCap.Round
|
||||||
})
|
})
|
||||||
// stroke()/op() mutate `outline` in place; both report failure, not a new path.
|
const merged = stroked ? r.ck.Path.MakeFromOp(stroked, base, r.ck.PathOp.Union) : null
|
||||||
const merged = stroked?.op(base, r.ck.PathOp.Union)
|
|
||||||
if (!merged) {
|
if (!merged) {
|
||||||
// Degenerate outline — draw the bare glyph, uncached so callers free it.
|
// Degenerate outline — draw the bare glyph, uncached so callers free it.
|
||||||
outline.delete()
|
outline.delete()
|
||||||
|
stroked?.delete()
|
||||||
return { path: base, cached: false }
|
return { path: base, cached: false }
|
||||||
}
|
}
|
||||||
base.delete()
|
base.delete()
|
||||||
|
stroked?.delete()
|
||||||
|
outline.delete()
|
||||||
// ponytail: crude bound — a live stroke-weight drag mints a key per tick;
|
// ponytail: crude bound — a live stroke-weight drag mints a key per tick;
|
||||||
// wholesale clear beats an LRU here since rebuild is cheap.
|
// wholesale clear beats an LRU here since rebuild is cheap.
|
||||||
if (r.glyphSilhouetteCache.size >= 512) {
|
if (r.glyphSilhouetteCache.size >= 512) {
|
||||||
for (const path of r.glyphSilhouetteCache.values()) path.delete()
|
for (const path of r.glyphSilhouetteCache.values()) path.delete()
|
||||||
r.glyphSilhouetteCache.clear()
|
r.glyphSilhouetteCache.clear()
|
||||||
}
|
}
|
||||||
r.glyphSilhouetteCache.set(key, outline)
|
r.glyphSilhouetteCache.set(key, merged)
|
||||||
return { path: outline, cached: true }
|
return { path: merged, cached: true }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import type { Path } from 'canvaskit-wasm'
|
import type { Path, PathBuilder } from 'canvaskit-wasm'
|
||||||
|
|
||||||
import type { SceneNode } from '@open-pencil/scene-graph'
|
import type { SceneNode } from '@open-pencil/scene-graph'
|
||||||
|
|
||||||
|
|
@ -7,7 +7,7 @@ import type { OutlineCommand } from '#core/text/opentype'
|
||||||
import { textNodeToOutlineLayout } from '#core/text/outlines'
|
import { textNodeToOutlineLayout } from '#core/text/outlines'
|
||||||
|
|
||||||
function appendOutlineCommand(
|
function appendOutlineCommand(
|
||||||
path: Path,
|
path: PathBuilder,
|
||||||
command: OutlineCommand,
|
command: OutlineCommand,
|
||||||
xOffset: number,
|
xOffset: number,
|
||||||
yOffset: number
|
yOffset: number
|
||||||
|
|
@ -47,9 +47,9 @@ export function textNodeToOutlinePath(r: SkiaRenderer, node: SceneNode): Path |
|
||||||
const layout = textNodeToOutlineLayout(node)
|
const layout = textNodeToOutlineLayout(node)
|
||||||
if (!layout) return null
|
if (!layout) return null
|
||||||
|
|
||||||
const path = new r.ck.Path()
|
const path = new r.ck.PathBuilder()
|
||||||
for (const glyph of layout.glyphs) {
|
for (const glyph of layout.glyphs) {
|
||||||
for (const command of glyph.commands) appendOutlineCommand(path, command, glyph.x, glyph.y)
|
for (const command of glyph.commands) appendOutlineCommand(path, command, glyph.x, glyph.y)
|
||||||
}
|
}
|
||||||
return path
|
return path.detachAndDelete()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -173,17 +173,17 @@ function buildCenterlineFromCrescent(
|
||||||
const arcParams = fitCircleArc(midpoints)
|
const arcParams = fitCircleArc(midpoints)
|
||||||
if (arcParams) {
|
if (arcParams) {
|
||||||
const { cx, cy, r, startAngleDeg, sweepDeg } = arcParams
|
const { cx, cy, r, startAngleDeg, sweepDeg } = arcParams
|
||||||
const path = new ck.Path()
|
const path = new ck.PathBuilder()
|
||||||
path.addArc(ck.LTRBRect(cx - r, cy - r, cx + r, cy + r), startAngleDeg, sweepDeg)
|
path.addArc(ck.LTRBRect(cx - r, cy - r, cx + r, cy + r), startAngleDeg, sweepDeg)
|
||||||
return path
|
return path.detachAndDelete()
|
||||||
}
|
}
|
||||||
|
|
||||||
const path = new ck.Path()
|
const path = new ck.PathBuilder()
|
||||||
path.moveTo(midpoints[0].x, midpoints[0].y)
|
path.moveTo(midpoints[0].x, midpoints[0].y)
|
||||||
for (let i = 1; i < midpoints.length; i++) {
|
for (let i = 1; i < midpoints.length; i++) {
|
||||||
path.lineTo(midpoints[i].x, midpoints[i].y)
|
path.lineTo(midpoints[i].x, midpoints[i].y)
|
||||||
}
|
}
|
||||||
return path
|
return path.detachAndDelete()
|
||||||
}
|
}
|
||||||
|
|
||||||
export function vectorNetworkToCenterlinePath(ck: CanvasKit, network: VectorNetwork): Path {
|
export function vectorNetworkToCenterlinePath(ck: CanvasKit, network: VectorNetwork): Path {
|
||||||
|
|
@ -195,7 +195,7 @@ export function vectorNetworkToCenterlinePath(ck: CanvasKit, network: VectorNetw
|
||||||
if (result) return result
|
if (result) return result
|
||||||
}
|
}
|
||||||
|
|
||||||
const path = new ck.Path()
|
const path = new ck.PathBuilder()
|
||||||
addOpenSegmentsToPath(path, segments, vertices)
|
addOpenSegmentsToPath(path, segments, vertices)
|
||||||
return path
|
return path.detachAndDelete()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ export function vectorNetworkToPath(ck: CanvasKit, network: VectorNetwork): Path
|
||||||
const paths: Path[] = []
|
const paths: Path[] = []
|
||||||
const regionSegmentIndexes = new Set<number>()
|
const regionSegmentIndexes = new Set<number>()
|
||||||
for (const region of regions) {
|
for (const region of regions) {
|
||||||
const regionPath = new ck.Path()
|
const regionPath = new ck.PathBuilder()
|
||||||
for (const loop of region.loops) {
|
for (const loop of region.loops) {
|
||||||
for (const segmentIndex of loop) regionSegmentIndexes.add(segmentIndex)
|
for (const segmentIndex of loop) regionSegmentIndexes.add(segmentIndex)
|
||||||
addLoopToPath(regionPath, loop, segments, vertices)
|
addLoopToPath(regionPath, loop, segments, vertices)
|
||||||
|
|
@ -40,21 +40,21 @@ export function vectorNetworkToPath(ck: CanvasKit, network: VectorNetwork): Path
|
||||||
regionPath.setFillType(
|
regionPath.setFillType(
|
||||||
region.windingRule === 'EVENODD' ? ck.FillType.EvenOdd : ck.FillType.Winding
|
region.windingRule === 'EVENODD' ? ck.FillType.EvenOdd : ck.FillType.Winding
|
||||||
)
|
)
|
||||||
paths.push(regionPath)
|
paths.push(regionPath.detachAndDelete())
|
||||||
}
|
}
|
||||||
|
|
||||||
const openSegments = segments.filter((_, index) => !regionSegmentIndexes.has(index))
|
const openSegments = segments.filter((_, index) => !regionSegmentIndexes.has(index))
|
||||||
if (openSegments.length > 0) {
|
if (openSegments.length > 0) {
|
||||||
const openPath = new ck.Path()
|
const openPath = new ck.PathBuilder()
|
||||||
addOpenSegmentsToPath(openPath, openSegments, vertices)
|
addOpenSegmentsToPath(openPath, openSegments, vertices)
|
||||||
paths.push(openPath)
|
paths.push(openPath.detachAndDelete())
|
||||||
}
|
}
|
||||||
return paths
|
return paths
|
||||||
}
|
}
|
||||||
|
|
||||||
const path = new ck.Path()
|
const path = new ck.PathBuilder()
|
||||||
addOpenSegmentsToPath(path, segments, vertices)
|
addOpenSegmentsToPath(path, segments, vertices)
|
||||||
return [path]
|
return [path.detachAndDelete()]
|
||||||
}
|
}
|
||||||
|
|
||||||
const CMD_CLOSE = 0
|
const CMD_CLOSE = 0
|
||||||
|
|
@ -68,8 +68,8 @@ export function geometryBlobToPath(
|
||||||
blob: Uint8Array,
|
blob: Uint8Array,
|
||||||
windingRule: WindingRule
|
windingRule: WindingRule
|
||||||
): Path {
|
): Path {
|
||||||
const path = new ck.Path()
|
const path = new ck.PathBuilder()
|
||||||
if (!(blob.buffer instanceof ArrayBuffer)) return path
|
if (!(blob.buffer instanceof ArrayBuffer)) return path.detachAndDelete()
|
||||||
const dv = new DataView(blob.buffer, blob.byteOffset, blob.byteLength)
|
const dv = new DataView(blob.buffer, blob.byteOffset, blob.byteLength)
|
||||||
let o = 0
|
let o = 0
|
||||||
|
|
||||||
|
|
@ -114,10 +114,10 @@ export function geometryBlobToPath(
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return path
|
return path.detachAndDelete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
path.setFillType(windingRule === 'EVENODD' ? ck.FillType.EvenOdd : ck.FillType.Winding)
|
path.setFillType(windingRule === 'EVENODD' ? ck.FillType.EvenOdd : ck.FillType.Winding)
|
||||||
return path
|
return path.detachAndDelete()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@open-pencil/core": "workspace:*",
|
"@open-pencil/core": "workspace:*",
|
||||||
"canvaskit-wasm": "^0.40.0",
|
"canvaskit-wasm": ">=0.41.1",
|
||||||
"vue": "^3.5.41"
|
"vue": "^3.5.41"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
|
|
|
||||||
|
|
@ -168,8 +168,9 @@ describe('boolean operation paths', () => {
|
||||||
|
|
||||||
test('uses imported fill geometry when child paths cannot produce a boolean path', async () => {
|
test('uses imported fill geometry when child paths cannot produce a boolean path', async () => {
|
||||||
const r = await createRenderer()
|
const r = await createRenderer()
|
||||||
const importedPath = new r.ck.Path()
|
const importedPathBuilder = new r.ck.PathBuilder()
|
||||||
importedPath.addRect(r.ck.LTRBRect(5, 6, 25, 36))
|
importedPathBuilder.addRect(r.ck.LTRBRect(5, 6, 25, 36))
|
||||||
|
const importedPath = importedPathBuilder.detachAndDelete()
|
||||||
r.getFillGeometry = () => [importedPath]
|
r.getFillGeometry = () => [importedPath]
|
||||||
const node = {
|
const node = {
|
||||||
id: 'boolean',
|
id: 'boolean',
|
||||||
|
|
|
||||||
|
|
@ -23,14 +23,15 @@ function createRenderer() {
|
||||||
delete: ReturnType<typeof mock>
|
delete: ReturnType<typeof mock>
|
||||||
}> = []
|
}> = []
|
||||||
|
|
||||||
class MockPath {
|
class MockPathBuilder {
|
||||||
addRect = mock(() => undefined)
|
addRect = mock(() => this)
|
||||||
moveTo = mock(() => undefined)
|
moveTo = mock(() => this)
|
||||||
lineTo = mock(() => undefined)
|
lineTo = mock(() => this)
|
||||||
cubicTo = mock(() => undefined)
|
cubicTo = mock(() => this)
|
||||||
arcToRotated = mock(() => undefined)
|
arcToRotated = mock(() => this)
|
||||||
close = mock(() => undefined)
|
close = mock(() => this)
|
||||||
delete = mock(() => undefined)
|
delete = mock(() => undefined)
|
||||||
|
detachAndDelete = mock(() => ({ delete: mock(() => undefined) }))
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
paths.push(this)
|
paths.push(this)
|
||||||
|
|
@ -39,7 +40,7 @@ function createRenderer() {
|
||||||
|
|
||||||
const renderer = {
|
const renderer = {
|
||||||
ck: {
|
ck: {
|
||||||
Path: MockPath,
|
PathBuilder: MockPathBuilder,
|
||||||
LTRBRect: mock((l, t, r, b) => new Float32Array([l, t, r, b]))
|
LTRBRect: mock((l, t, r, b) => new Float32Array([l, t, r, b]))
|
||||||
},
|
},
|
||||||
fillPaint: {}
|
fillPaint: {}
|
||||||
|
|
|
||||||
|
|
@ -8,26 +8,34 @@ export function mockCalls(fn: ReturnType<typeof mock>): unknown[][] {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createMockRenderer(overrides: Partial<SkiaRenderer> = {}): SkiaRenderer {
|
export function createMockRenderer(overrides: Partial<SkiaRenderer> = {}): SkiaRenderer {
|
||||||
|
class MockPath {
|
||||||
|
delete = mock(() => undefined)
|
||||||
|
copy = mock(() => new MockPath())
|
||||||
|
makeCombined = mock(() => new MockPath())
|
||||||
|
makeStroked = mock(() => new MockPath())
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ck: {
|
ck: {
|
||||||
Color4f: mock((r, g, b, a) => new Float32Array([r, g, b, a])),
|
Color4f: mock((r, g, b, a) => new Float32Array([r, g, b, a])),
|
||||||
LTRBRect: mock((l, t, r, b) => new Float32Array([l, t, r, b])),
|
LTRBRect: mock((l, t, r, b) => new Float32Array([l, t, r, b])),
|
||||||
RRectXY: mock(() => new Float32Array(12)),
|
RRectXY: mock(() => new Float32Array(12)),
|
||||||
ClipOp: { Intersect: 0 },
|
ClipOp: { Intersect: 0 },
|
||||||
Path: class {
|
Path: Object.assign(MockPath, {
|
||||||
addOval = mock(() => undefined)
|
MakeFromOp: mock(() => new MockPath())
|
||||||
addRect = mock(() => undefined)
|
}),
|
||||||
addRRect = mock(() => undefined)
|
PathBuilder: class {
|
||||||
addPath = mock(() => undefined)
|
addOval = mock(() => this)
|
||||||
op = mock(() => true)
|
addRect = mock(() => this)
|
||||||
transform = mock(() => undefined)
|
addRRect = mock(() => this)
|
||||||
|
addPath = mock(() => this)
|
||||||
|
transform = mock(() => this)
|
||||||
delete = mock(() => undefined)
|
delete = mock(() => undefined)
|
||||||
copy = mock(() => this)
|
moveTo = mock(() => this)
|
||||||
stroke = mock(() => this)
|
lineTo = mock(() => this)
|
||||||
moveTo = mock(() => undefined)
|
cubicTo = mock(() => this)
|
||||||
lineTo = mock(() => undefined)
|
close = mock(() => this)
|
||||||
cubicTo = mock(() => undefined)
|
detachAndDelete = mock(() => new MockPath())
|
||||||
close = mock(() => undefined)
|
|
||||||
},
|
},
|
||||||
PathOp: { Difference: 0, Union: 1 },
|
PathOp: { Difference: 0, Union: 1 },
|
||||||
StrokeCap: { Butt: 0, Round: 1, Square: 2 },
|
StrokeCap: { Butt: 0, Round: 1, Square: 2 },
|
||||||
|
|
|
||||||
|
|
@ -39,12 +39,14 @@ describe('path shape shadows', () => {
|
||||||
expect(canvas.drawRect).not.toHaveBeenCalled()
|
expect(canvas.drawRect).not.toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('drop shadow spread copies imported geometry instead of mutating cache paths', () => {
|
test('drop shadow spread combines and deletes a detached stroked ring', () => {
|
||||||
const r = createMockRenderer()
|
const r = createMockRenderer()
|
||||||
const canvas = createMockCanvas()
|
const canvas = createMockCanvas()
|
||||||
const cachedPath = new r.ck.Path()
|
const cachedPath = new r.ck.Path()
|
||||||
const spreadPath = new r.ck.Path()
|
const ringPath = new r.ck.Path()
|
||||||
cachedPath.copy = mock(() => spreadPath)
|
const combinedPath = new r.ck.Path()
|
||||||
|
cachedPath.makeStroked = mock(() => ringPath)
|
||||||
|
r.ck.Path.MakeFromOp = mock(() => combinedPath)
|
||||||
r.getFillGeometry = mock(() => [cachedPath])
|
r.getFillGeometry = mock(() => [cachedPath])
|
||||||
|
|
||||||
const node: Partial<SceneNode> = {
|
const node: Partial<SceneNode> = {
|
||||||
|
|
@ -67,10 +69,11 @@ describe('path shape shadows', () => {
|
||||||
|
|
||||||
renderEffects(r, canvas as Canvas, node as SceneNode, new Float32Array(4), false, 'behind')
|
renderEffects(r, canvas as Canvas, node as SceneNode, new Float32Array(4), false, 'behind')
|
||||||
|
|
||||||
expect(cachedPath.copy).toHaveBeenCalled()
|
const makeFromOp = r.ck.Path.MakeFromOp as ReturnType<typeof mock>
|
||||||
expect(cachedPath.op).not.toHaveBeenCalled()
|
expect(makeFromOp).toHaveBeenCalledWith(cachedPath, ringPath, r.ck.PathOp.Union)
|
||||||
expect(spreadPath.op).toHaveBeenCalledWith(expect.anything(), r.ck.PathOp.Union)
|
expect(ringPath.delete).toHaveBeenCalledTimes(1)
|
||||||
expect(spreadPath.delete).toHaveBeenCalled()
|
expect(combinedPath.delete).toHaveBeenCalledTimes(1)
|
||||||
|
expect(cachedPath.delete).not.toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('inner shadow for a polygon clips and cuts out with polygon paths', () => {
|
test('inner shadow for a polygon clips and cuts out with polygon paths', () => {
|
||||||
|
|
|
||||||
|
|
@ -57,13 +57,14 @@ function createMockRenderer(overrides: Partial<Record<string, unknown>> = {}) {
|
||||||
},
|
},
|
||||||
ck: {
|
ck: {
|
||||||
MakePicture: mock(() => createMockPicture()),
|
MakePicture: mock(() => createMockPicture()),
|
||||||
Path: class {
|
PathBuilder: class {
|
||||||
moveTo = mock(() => undefined)
|
moveTo = mock(() => this)
|
||||||
lineTo = mock(() => undefined)
|
lineTo = mock(() => this)
|
||||||
cubicTo = mock(() => undefined)
|
cubicTo = mock(() => this)
|
||||||
quadTo = mock(() => undefined)
|
quadTo = mock(() => this)
|
||||||
close = mock(() => undefined)
|
close = mock(() => this)
|
||||||
delete = mock(() => undefined)
|
delete = mock(() => undefined)
|
||||||
|
detachAndDelete = mock(() => ({ delete: mock(() => undefined) }))
|
||||||
},
|
},
|
||||||
LTRBRect: mock((...args: number[]) => args),
|
LTRBRect: mock((...args: number[]) => args),
|
||||||
Color4f: mock((...args: number[]) => new Float32Array(args)),
|
Color4f: mock((...args: number[]) => new Float32Array(args)),
|
||||||
|
|
|
||||||
|
|
@ -41,9 +41,41 @@ function createCanvasKit() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class MockPathBuilder {
|
||||||
|
operations: string[] = []
|
||||||
|
fillType: number | null = null
|
||||||
|
|
||||||
|
moveTo(x: number, y: number): void {
|
||||||
|
this.operations.push(`M${x},${y}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
lineTo(x: number, y: number): void {
|
||||||
|
this.operations.push(`L${x},${y}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
cubicTo(x1: number, y1: number, x2: number, y2: number, x3: number, y3: number): void {
|
||||||
|
this.operations.push(`C${x1},${y1},${x2},${y2},${x3},${y3}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
close(): void {
|
||||||
|
this.operations.push('Z')
|
||||||
|
}
|
||||||
|
|
||||||
|
setFillType(value: number): void {
|
||||||
|
this.fillType = value
|
||||||
|
}
|
||||||
|
|
||||||
|
detachAndDelete(): MockPath {
|
||||||
|
const path = new MockPath()
|
||||||
|
path.operations = [...this.operations]
|
||||||
|
path.fillType = this.fillType
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
ck: {
|
ck: {
|
||||||
Path: MockPath,
|
PathBuilder: MockPathBuilder,
|
||||||
FillType: { Winding: 0, EvenOdd: 1 }
|
FillType: { Winding: 0, EvenOdd: 1 }
|
||||||
} as CanvasKit,
|
} as CanvasKit,
|
||||||
paths
|
paths
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue