diff --git a/biome.json b/biome.json index ed24ee3..5f4fd9c 100644 --- a/biome.json +++ b/biome.json @@ -6,7 +6,14 @@ "indentStyle": "space" }, "files": { - "includes": ["**", "!**/cosmos-export", "!**/dist", "!**/package.json"] + "includes": [ + "**", + "!**/cosmos-export", + "!**/dist", + "!**/package.json", + "!src/styles.css", + "!fixtures-support/assets/sparkfun-qwiic-micropressure/**" + ] }, "javascript": { "formatter": { diff --git a/bun.lock b/bun.lock index 076a401..286983b 100644 --- a/bun.lock +++ b/bun.lock @@ -5,11 +5,13 @@ "": { "name": "monaco-code-editor", "dependencies": { + "@fontsource-variable/geist": "^5.2.9", "@monaco-editor/react": "^4.7.0", "@shikijs/monaco": "^4.3.0", "@shikijs/vscode-textmate": "^10.0.2", "@typescript/ata": "^0.9.8", "monaco-editor": "^0.55.1", + "radix-ui": "^1.6.0", "shiki": "^4.3.0", "typescript": "^6.0.3", }, @@ -24,7 +26,6 @@ "@radix-ui/react-slot": "^1.3.0", "@radix-ui/react-tabs": "^1.1.15", "@radix-ui/react-tooltip": "^1.2.10", - "@tailwindcss/vite": "^4.3.1", "@tscircuit/3d-viewer": "^0.0.571", "@tscircuit/assembly-viewer": "^0.0.6", "@tscircuit/core": "^0.0.1362", @@ -32,12 +33,14 @@ "@tscircuit/internal-dynamic-import": "^0.0.7", "@tscircuit/pcb-viewer": "^1.11.374", "@tscircuit/props": "^0.0.557", + "@tscircuit/runframe": "^0.0.2128", "@tscircuit/schematic-viewer": "^2.0.67", "@tscircuit/solver-utils": "^0.0.19", "@types/bun": "latest", "@types/react": "^19.2.17", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.3", + "autoprefixer": "^10.4.20", "circuit-json-to-bom-csv": "^0.0.9", "circuit-json-to-pnp-csv": "^0.0.8", "class-variance-authority": "^0.7.1", @@ -51,6 +54,7 @@ "lucide-react": "^1.21.0", "marked": "^18.0.5", "minimatch": "^10.2.5", + "postcss": "^8.4.47", "posthog-js": "^1.395.0", "react": "^19.2.7", "react-cosmos": "^7.3.0", @@ -60,8 +64,9 @@ "react-hot-toast": "^2.6.0", "react-query": "^3.39.3", "tailwind-merge": "^3.6.0", - "tailwindcss": "^4.3.1", - "three": "^0.185.0", + "tailwindcss": "^3.4.13", + "tailwindcss-animate": "^1.0.7", + "three": "0.165.0", "tsup": "^8.5.1", "vite": "^8.1.0", "zustand": "^5.0.14", @@ -73,6 +78,8 @@ }, }, "packages": { + "@alloc/quick-lru": ["@alloc/quick-lru@5.2.0", "", {}, "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw=="], + "@babel/code-frame": ["@babel/code-frame@7.29.7", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw=="], "@babel/compat-data": ["@babel/compat-data@7.29.7", "", {}, "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg=="], @@ -221,6 +228,8 @@ "@floating-ui/utils": ["@floating-ui/utils@0.2.11", "", {}, "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg=="], + "@fontsource-variable/geist": ["@fontsource-variable/geist@5.2.9", "", {}, "sha512-TP+QSBG3wxKGPE33CbMy/L0Nu3qvJ6Fy81Yc4LnQ95xH+i+cfEp8fyU8/kfV14YwszxIFPhnoMTbjL71waVpyQ=="], + "@gltf-transform/core": ["@gltf-transform/core@4.4.0", "", { "dependencies": { "property-graph": "^4.1.0" } }, "sha512-cOPxOhHFFz5hwmix+li1+Nnq5qMV/QD3fTCsVlApxxFACtFdjkt2R/juseD4gvZ7D2c/yl6OilKH0pvI735YyQ=="], "@gltf-transform/extensions": ["@gltf-transform/extensions@4.4.0", "", { "dependencies": { "@gltf-transform/core": "^4.4.0", "ktx-parse": "^1.1.0" } }, "sha512-ZwEgFkkqnUR7d4m6roK9BycxxdoqJNtVyo7w5ShJ9syKBoQiXw2QrTSLwXaUAImSrEIl9Jh/wZTtvSVyviQuXg=="], @@ -311,6 +320,12 @@ "@nodable/entities": ["@nodable/entities@2.2.0", "", {}, "sha512-9uGyhaQavEUMC8AIddIjau4NsnsXhou+j5sBAGojCM1oxmQpVKTWR/9JxABD6UAv12vpIms55fPZKFQEhG6uBg=="], + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], + + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], + + "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + "@oxc-project/types": ["@oxc-project/types@0.137.0", "", {}, "sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA=="], "@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="], @@ -319,20 +334,34 @@ "@posthog/types": ["@posthog/types@1.391.1", "", {}, "sha512-ASwd7Nf4pViqdYRYaNRyPYRVKWa1CcHUAUWR0XeQJLGdNnsWACBwe0sSieb/cHnKsRXjRwO/23KIY83lm/Ccpw=="], + "@radix-ui/number": ["@radix-ui/number@1.1.2", "", {}, "sha512-ceTwaxc4I5IOi97DgCotl3pqiyRGvffcc0oOsE2dQYaJOFIDsDt4VWG6xEbg1QePv9QWausCEIppud/tJ1wNig=="], + "@radix-ui/primitive": ["@radix-ui/primitive@1.1.4", "", {}, "sha512-7AdCK9PQyiljKoBDbN8OuctCbd/esdwZPQ8RtOE3SsyQtUpiPb+ND75q0jEhC1m1ecBI0MFNeLJvwIh9iKHRcQ=="], + "@radix-ui/react-accessible-icon": ["@radix-ui/react-accessible-icon@1.1.10", "", { "dependencies": { "@radix-ui/react-visually-hidden": "1.2.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TraSwZUqTcVbiDV2/RXzAXC7aeVVXchq0daPFZE7zAxYFaMzjOUggLOfQH9KFLgRizuwVKZO/crveV1eeO3/ZQ=="], + + "@radix-ui/react-accordion": ["@radix-ui/react-accordion@1.2.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-collapsible": "1.1.14", "@radix-ui/react-collection": "1.1.10", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-iE8YB9nmTBH8zd73ofBISZ8JCzgMoMkATJr7qDwa6u5F1+7mTM81V6fa71jgZ65rpjVpecDf1vSnwIFP9Ly1zw=="], + "@radix-ui/react-alert-dialog": ["@radix-ui/react-alert-dialog@1.1.17", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-dialog": "1.1.17", "@radix-ui/react-primitive": "2.1.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-563ygGeyWPrxyVCNp7OV4rE2aIXhFPknpFyo4wbDlcyMMPZ6ySh+zC5WTvY0ZFLgPTg/QB6tA8PyDQyJ2b4cPg=="], "@radix-ui/react-arrow": ["@radix-ui/react-arrow@1.1.10", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-j2VTDz1vgCsmuG0k5lBfOcM8n5JPFqZBcMryasFjHYMhwxYL5SRUV5lMSUpRdNtw3D/Sv8pzJtrlAgkssYSsQQ=="], + "@radix-ui/react-aspect-ratio": ["@radix-ui/react-aspect-ratio@1.1.10", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-kbI7NrqhDeuytYrq7JjAsoXczvL8wgj2tc1MyaYWm+50bMKHCHQtVWCryslx4cCpmCTTkBcwQckE4CmmGV2haQ=="], + + "@radix-ui/react-avatar": ["@radix-ui/react-avatar@1.2.0", "", { "dependencies": { "@radix-ui/react-context": "1.1.4", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-is-hydrated": "0.1.1", "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-am/CwltXtmtdtP+5FbYblYDnMa/zuKcMJP1i3/SJMDXXfj2mG+BTqLH2wucqeyyiQMursUtg/5cK+Nh2pCaSOA=="], + "@radix-ui/react-checkbox": ["@radix-ui/react-checkbox@1.3.5", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-previous": "1.1.2", "@radix-ui/react-use-size": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-pREzrmNnVwGvYaBoM64huTRK7B3lrTRuwj8A9nwhPiEtMb+yudiWh6zWAqEtP0Dzd5+iBa1Ki7V1pCxV8ExMdA=="], + "@radix-ui/react-collapsible": ["@radix-ui/react-collapsible@1.1.14", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9bT+FvifX1FK2Mj6UEsTdyu0cN3JaA3KdfhaBao+ONrYFy/pyOy3TU1TNw7iOk1o+0hOEq67RojlUUmoFGwxyA=="], + "@radix-ui/react-collection": ["@radix-ui/react-collection@1.1.10", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-IVVz4EvBcKjrzKgof714qDnz/SzQAkLA2Emh5edlHbgcE6fNd3Un6CJLlaYcnm8N4JmAtzQgse4dOKxcD2yc9g=="], "@radix-ui/react-compose-refs": ["@radix-ui/react-compose-refs@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA=="], "@radix-ui/react-context": ["@radix-ui/react-context@1.1.4", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-QwH4PO5urrbO+FaGd5Aglg+YJgWTyyuZ3g/6mKvsqraLkglDdckw9JafgL5McL5VEJ6EPNduPaT3ZE9BttDAqg=="], + "@radix-ui/react-context-menu": ["@radix-ui/react-context-menu@2.3.1", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-menu": "2.1.18", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-XbrxS68W5dyiE4fAb96yvJwSVU5x66B20A99sD5Mk3xSWK/LqeOnx6TZnim1KieMjXS/CTFq8reOAjWxas2G8Q=="], + "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.17", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-dismissable-layer": "1.1.13", "@radix-ui/react-focus-guards": "1.1.4", "@radix-ui/react-focus-scope": "1.1.10", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-portal": "1.1.12", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-slot": "1.3.0", "@radix-ui/react-use-controllable-state": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-TDTYmpdq8dI2+Xgvgj9AJ8Ghqq+Eph/TRVEdaFQPDItIY+6QSkU7MJMeevw1568Yw/2Ijz8BTphPSP2XejKphw=="], "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-C3vFhbyi4SW3PmbAi6Awpu4OzJtd0MxGurvSsYtr7p7nM8RNB3VAF3CUmnp2j50knpkrRcB7+ycVXzgLgF6yNA=="], @@ -345,12 +374,26 @@ "@radix-ui/react-focus-scope": ["@radix-ui/react-focus-scope@1.1.10", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-callback-ref": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Fas/lXQqhVvqwAb64s5RFeHiHYElZ6SUQbZaNd6EkfhP/Al7wTIQ9WIR4QVX475tlu5yFCEdDcJH6/UwsZjMWw=="], + "@radix-ui/react-form": ["@radix-ui/react-form@0.1.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-label": "2.1.10", "@radix-ui/react-primitive": "2.1.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-1NfuvctVtX4sU3Mmq/IdrR8UunxiCMiVg3A5UENKhFzxUBeOyaQQ+lmaQaV7Tc8cqvBKsJL3/KGBsixK0D8WFg=="], + + "@radix-ui/react-hover-card": ["@radix-ui/react-hover-card@1.1.17", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-dismissable-layer": "1.1.13", "@radix-ui/react-popper": "1.3.1", "@radix-ui/react-portal": "1.1.12", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-GjZQIEANVkuuWeztlKz6QEHe31ZX2iDfHzcTMCQVZXC0JyQrgfKWSC+LOOEw6aVV64zyjzobIzSA4AU4eKWrHA=="], + "@radix-ui/react-icons": ["@radix-ui/react-icons@1.3.2", "", { "peerDependencies": { "react": "^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc" } }, "sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g=="], "@radix-ui/react-id": ["@radix-ui/react-id@1.1.2", "", { "dependencies": { "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA=="], + "@radix-ui/react-label": ["@radix-ui/react-label@2.1.10", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-ib0zvq2ZsAqKm5tRnqGJn3vOxSgIts5ToxsXT0q1S/GfLD1Zj7UOEnkw8u2w6sRmn47djpQWuSU1DCL1R29/yw=="], + "@radix-ui/react-menu": ["@radix-ui/react-menu@2.1.18", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-collection": "1.1.10", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.13", "@radix-ui/react-focus-guards": "1.1.4", "@radix-ui/react-focus-scope": "1.1.10", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-popper": "1.3.1", "@radix-ui/react-portal": "1.1.12", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-roving-focus": "1.1.13", "@radix-ui/react-slot": "1.3.0", "@radix-ui/react-use-callback-ref": "1.1.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-lj8Rxjtn6zJq1oSbE/uDtAwCbB9BnxgHD+8MwJMuTh6u1dPamYhW9iuELr/Z8d0D/UysFblYYHeBPwi7T4k0YQ=="], + "@radix-ui/react-menubar": ["@radix-ui/react-menubar@1.1.18", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-collection": "1.1.10", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-menu": "2.1.18", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-roving-focus": "1.1.13", "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-hX7EGx/oFq6DPY27GQuP/2wP48GHf5LG6r06VgNJlG+znmDS8OfopZcRcGly3L4lsB9FqpmLx6JQSE9P3BUpyw=="], + + "@radix-ui/react-navigation-menu": ["@radix-ui/react-navigation-menu@1.2.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-collection": "1.1.10", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.13", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-layout-effect": "1.1.2", "@radix-ui/react-use-previous": "1.1.2", "@radix-ui/react-visually-hidden": "1.2.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-nJ0SkrSQgudyYhMiYeHA1ayLVuduEJCFLan1RZZN7c9kqzzCFLaU9kuy81uNtqzweM9YaQPgWzxi9MwQ9jZ04g=="], + + "@radix-ui/react-one-time-password-field": ["@radix-ui/react-one-time-password-field@0.1.10", "", { "dependencies": { "@radix-ui/number": "1.1.2", "@radix-ui/primitive": "1.1.4", "@radix-ui/react-collection": "1.1.10", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-roving-focus": "1.1.13", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-effect-event": "0.0.3", "@radix-ui/react-use-is-hydrated": "0.1.1", "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-GHkcJ+WVj91At+OvUVTD4R3W0/wxw9t/sG5xFUBYXaCbtWiooZX5Md376QjJqgH4VsVyXrbVNHO2O4NYcmjfVg=="], + + "@radix-ui/react-password-toggle-field": ["@radix-ui/react-password-toggle-field@0.1.5", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-effect-event": "0.0.3", "@radix-ui/react-use-is-hydrated": "0.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-fVuA82u0b/fClpbEJv8yp1nU9eSvoSEOERsU/hhf3FXGPIvkmE7oEaHEu8poowoXO39/Va7zq2E0TUcYr1dBRg=="], + "@radix-ui/react-popover": ["@radix-ui/react-popover@1.1.17", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-dismissable-layer": "1.1.13", "@radix-ui/react-focus-guards": "1.1.4", "@radix-ui/react-focus-scope": "1.1.10", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-popper": "1.3.1", "@radix-ui/react-portal": "1.1.12", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-slot": "1.3.0", "@radix-ui/react-use-controllable-state": "1.2.3", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/YSAOdJ7YJvdn7bn5sdSx2egW+SKY+u7O5RyAVs94Ymrg2fg5QTSFPMRkzvhGyFuE4/qsmPBdrwYoZMZh/4f+g=="], "@radix-ui/react-popper": ["@radix-ui/react-popper@1.3.1", "", { "dependencies": { "@floating-ui/react-dom": "^2.0.0", "@radix-ui/react-arrow": "1.1.10", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.2", "@radix-ui/react-use-rect": "1.1.2", "@radix-ui/react-use-size": "1.1.2", "@radix-ui/rect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-bhnq/0DEPTi2lsOD3J5rTL65qUKHbKbhqHsmN9TMiclSXpipi651ooUKPPp6G5lF/WiHBdn1s0Wuqsn+myVAvw=="], @@ -361,12 +404,34 @@ "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.6", "", { "dependencies": { "@radix-ui/react-slot": "1.3.0" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-wetd0QI77DbvrPpTAvH1SqOxsYF2wZe5TNxqwOd5Ty4XDpV3dpV0s8K/1MGMJBeY5o7lg8ub5VIt1Ub+yVen6g=="], + "@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.10", "", { "dependencies": { "@radix-ui/react-context": "1.1.4", "@radix-ui/react-primitive": "2.1.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-JYzEg60lk79PwKM27WZyKd7PW8O4OM5jOaFfRPfOyeXmMw7tLJh5kSj+CEjVTehszuwml/AdCzPGMXBTGf4BBw=="], + + "@radix-ui/react-radio-group": ["@radix-ui/react-radio-group@1.4.1", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-roving-focus": "1.1.13", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-previous": "1.1.2", "@radix-ui/react-use-size": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-/SSxZdKEo2Eo29FFRKd06EfFDYp8HryKg0WYg7QLXaydPzl52YfSvCH2a3QDBRdtcuwACroJT8UVjQVgOJ7P9A=="], + "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-collection": "1.1.10", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9gkwneI0guf8JDmrFxPjJF6Ozzgioyw+/lonYNCwefS9ZHA05er0BVHiXr+LbWGHxUfczvMY6G1oiZZi1VzjRw=="], + "@radix-ui/react-scroll-area": ["@radix-ui/react-scroll-area@1.2.12", "", { "dependencies": { "@radix-ui/number": "1.1.2", "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-layout-effect": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-xuafVzQiTCLsyEjakowTdG3OgTXsmO7IdCiO77otIa+z44xoLNs9Do5eg7POFumIOCjtG6djfm6RKUKpUa/csA=="], + + "@radix-ui/react-select": ["@radix-ui/react-select@2.3.1", "", { "dependencies": { "@radix-ui/number": "1.1.2", "@radix-ui/primitive": "1.1.4", "@radix-ui/react-collection": "1.1.10", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.13", "@radix-ui/react-focus-guards": "1.1.4", "@radix-ui/react-focus-scope": "1.1.10", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-popper": "1.3.1", "@radix-ui/react-portal": "1.1.12", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-slot": "1.3.0", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-layout-effect": "1.1.2", "@radix-ui/react-use-previous": "1.1.2", "@radix-ui/react-visually-hidden": "1.2.6", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.7.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-w6eDvY78LE9ZUiNnXCA1QVK8RYN7k9galFv09kjVydJqBAgHd7Y9A6h0UJ/6DCZNGZMZrB2ohcSW1Bo9d8+wWA=="], + + "@radix-ui/react-separator": ["@radix-ui/react-separator@1.1.10", "", { "dependencies": { "@radix-ui/react-primitive": "2.1.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Y6K6jLQCVfCnTL2MEtGxDLffkhNfEfHsEg3Wa8JU+IWdn3EWbLXd3OuOfQRN7p/W/cUce1WyTk3QeuAoDBzN9g=="], + + "@radix-ui/react-slider": ["@radix-ui/react-slider@1.4.1", "", { "dependencies": { "@radix-ui/number": "1.1.2", "@radix-ui/primitive": "1.1.4", "@radix-ui/react-collection": "1.1.10", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-layout-effect": "1.1.2", "@radix-ui/react-use-previous": "1.1.2", "@radix-ui/react-use-size": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-r91WSpQucNGFKAIxT8FT0H0zyjd5tJlqObLp7LOMV4z49KoDCwjy01w3vDOU4e1wxhF9IgjYco7SB6byOW7Buw=="], + "@radix-ui/react-slot": ["@radix-ui/react-slot@1.3.0", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.3" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA=="], + "@radix-ui/react-switch": ["@radix-ui/react-switch@1.3.1", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-previous": "1.1.2", "@radix-ui/react-use-size": "1.1.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-55bQtCnOB0BohomSHi6qvQXpJEEqUGDm6hRrM0Bph5OXwhSegqkd8IqgBAQkM1IlgUlWZIxpxRcpOEfRIgimyw=="], + "@radix-ui/react-tabs": ["@radix-ui/react-tabs@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-roving-focus": "1.1.13", "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-kxc9gI6/HfcU4nfMMVS3AmQK414kbU1IE6UCJmMmxjhO3cRPXOyYnmvyKD+ODt7q56nRq9l7Wovi6uaGwKgMlg=="], + "@radix-ui/react-toast": ["@radix-ui/react-toast@1.2.17", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-collection": "1.1.10", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-dismissable-layer": "1.1.13", "@radix-ui/react-portal": "1.1.12", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-layout-effect": "1.1.2", "@radix-ui/react-visually-hidden": "1.2.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-uL4kyyWy000pPL43fGGCV5qT6ZchCWEQZOSlkYiPwPt8Hy1iW38RjeptIvz1/SZesrW6Vn58Ct3sV7tfEfiAbw=="], + + "@radix-ui/react-toggle": ["@radix-ui/react-toggle@1.1.12", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-AsAVsYNZIlRBsci7BhE+QyQeKd1h6TffJYt+lF0QQkd5OpQ3klfIByPsCb4G0h/Fq6PJwh1FYNluzBFYzhk4+w=="], + + "@radix-ui/react-toggle-group": ["@radix-ui/react-toggle-group@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-roving-focus": "1.1.13", "@radix-ui/react-toggle": "1.1.12", "@radix-ui/react-use-controllable-state": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Xb9PLtlvU66F36LiKba6dFswu6V2mDkgidO4fNSbQHQwmZ9ObxMIO17MN/LJ4aWJecVuSVLAHPZjyeMzJrgeiA=="], + + "@radix-ui/react-toolbar": ["@radix-ui/react-toolbar@1.1.13", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-roving-focus": "1.1.13", "@radix-ui/react-separator": "1.1.10", "@radix-ui/react-toggle-group": "1.1.13" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-Za1l4f6fzTkGgz/iynAMN8iaqiKff2wm2/QwiLmHPtDQreWEBrvSimgQFIekxMUdRPhILM7xdIXxuS/o/DGZag=="], + "@radix-ui/react-tooltip": ["@radix-ui/react-tooltip@1.2.10", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-dismissable-layer": "1.1.13", "@radix-ui/react-id": "1.1.2", "@radix-ui/react-popper": "1.3.1", "@radix-ui/react-portal": "1.1.12", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-slot": "1.3.0", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-visually-hidden": "1.2.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-NlNe8D0dWEpVfXFli90IO6X07Josx/b1iu98tDnx9Xv0HT4wLIL+m2VOheMHhK7qbp2HoTBqALEFzGyZs/levw=="], "@radix-ui/react-use-callback-ref": ["@radix-ui/react-use-callback-ref@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw=="], @@ -377,6 +442,8 @@ "@radix-ui/react-use-escape-keydown": ["@radix-ui/react-use-escape-keydown@1.1.2", "", { "dependencies": { "@radix-ui/react-use-callback-ref": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-2uVLvLjgO7NZCWw01/FdqRwmA42J0BcjPMUCA+koFEOAb+zjqIP7SiFz/7zWPrKnVmSqr76Omq2ALyCuX4dhLw=="], + "@radix-ui/react-use-is-hydrated": ["@radix-ui/react-use-is-hydrated@0.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-qwOiz4Tjo8CNnrOLAYUMXeZwDzXgXpvK4TKQPmWLECM9XoWvA6+0Z2/7Ag3A4ivjS4ovbLJPbskkxioFyBhr8A=="], + "@radix-ui/react-use-layout-effect": ["@radix-ui/react-use-layout-effect@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA=="], "@radix-ui/react-use-previous": ["@radix-ui/react-use-previous@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-IGBQPtRFdhN6MQ8dbegVmBq1LVZluya3F1jWY+puIcQC3MHctRwTDSBWCkL/3ZcnMJLTMJ++Z+ktmvg0F89iCw=="], @@ -535,36 +602,6 @@ "@skidding/launch-editor": ["@skidding/launch-editor@2.13.2", "", { "dependencies": { "shell-quote": "^1.8.3" } }, "sha512-BphfE/1Prmsjj5K7mZzKU5wHf360pu7CdylfR6UqRHrzw/qMgqnQA/0yTDHDe1VsPuGpQt2QeSbbu48WY4bj0g=="], - "@tailwindcss/node": ["@tailwindcss/node@4.3.1", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "5.21.6", "jiti": "^2.7.0", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.3.1" } }, "sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A=="], - - "@tailwindcss/oxide": ["@tailwindcss/oxide@4.3.1", "", { "optionalDependencies": { "@tailwindcss/oxide-android-arm64": "4.3.1", "@tailwindcss/oxide-darwin-arm64": "4.3.1", "@tailwindcss/oxide-darwin-x64": "4.3.1", "@tailwindcss/oxide-freebsd-x64": "4.3.1", "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.1", "@tailwindcss/oxide-linux-arm64-gnu": "4.3.1", "@tailwindcss/oxide-linux-arm64-musl": "4.3.1", "@tailwindcss/oxide-linux-x64-gnu": "4.3.1", "@tailwindcss/oxide-linux-x64-musl": "4.3.1", "@tailwindcss/oxide-wasm32-wasi": "4.3.1", "@tailwindcss/oxide-win32-arm64-msvc": "4.3.1", "@tailwindcss/oxide-win32-x64-msvc": "4.3.1" } }, "sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA=="], - - "@tailwindcss/oxide-android-arm64": ["@tailwindcss/oxide-android-arm64@4.3.1", "", { "os": "android", "cpu": "arm64" }, "sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ=="], - - "@tailwindcss/oxide-darwin-arm64": ["@tailwindcss/oxide-darwin-arm64@4.3.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA=="], - - "@tailwindcss/oxide-darwin-x64": ["@tailwindcss/oxide-darwin-x64@4.3.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg=="], - - "@tailwindcss/oxide-freebsd-x64": ["@tailwindcss/oxide-freebsd-x64@4.3.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g=="], - - "@tailwindcss/oxide-linux-arm-gnueabihf": ["@tailwindcss/oxide-linux-arm-gnueabihf@4.3.1", "", { "os": "linux", "cpu": "arm" }, "sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg=="], - - "@tailwindcss/oxide-linux-arm64-gnu": ["@tailwindcss/oxide-linux-arm64-gnu@4.3.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ=="], - - "@tailwindcss/oxide-linux-arm64-musl": ["@tailwindcss/oxide-linux-arm64-musl@4.3.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA=="], - - "@tailwindcss/oxide-linux-x64-gnu": ["@tailwindcss/oxide-linux-x64-gnu@4.3.1", "", { "os": "linux", "cpu": "x64" }, "sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg=="], - - "@tailwindcss/oxide-linux-x64-musl": ["@tailwindcss/oxide-linux-x64-musl@4.3.1", "", { "os": "linux", "cpu": "x64" }, "sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ=="], - - "@tailwindcss/oxide-wasm32-wasi": ["@tailwindcss/oxide-wasm32-wasi@4.3.1", "", { "dependencies": { "@emnapi/core": "^1.10.0", "@emnapi/runtime": "^1.10.0", "@emnapi/wasi-threads": "^1.2.1", "@napi-rs/wasm-runtime": "^1.1.4", "@tybys/wasm-util": "^0.10.2", "tslib": "^2.8.1" }, "cpu": "none" }, "sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA=="], - - "@tailwindcss/oxide-win32-arm64-msvc": ["@tailwindcss/oxide-win32-arm64-msvc@4.3.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg=="], - - "@tailwindcss/oxide-win32-x64-msvc": ["@tailwindcss/oxide-win32-x64-msvc@4.3.1", "", { "os": "win32", "cpu": "x64" }, "sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA=="], - - "@tailwindcss/vite": ["@tailwindcss/vite@4.3.1", "", { "dependencies": { "@tailwindcss/node": "4.3.1", "@tailwindcss/oxide": "4.3.1", "tailwindcss": "4.3.1" }, "peerDependencies": { "vite": "^5.2.0 || ^6 || ^7 || ^8" } }, "sha512-hItDHuIIlEV61R+faXu66s1K36aTurO/Qw0e45Vskz57gXl9pWOT6eg3zmcEui6CZXddbN7zd41bwmvag4JGwQ=="], - "@thednp/dommatrix": ["@thednp/dommatrix@3.0.4", "", {}, "sha512-xpKtQZqFOuAPfQDbePIh9f48YKfmULV7z9C+anPBSHiOG4P+T3ct7Cx2AZOoUeXbxiDkz7SONANy1bB7p2uysg=="], "@tscircuit/3d-viewer": ["@tscircuit/3d-viewer@0.0.571", "", { "dependencies": { "@jscad/regl-renderer": "^2.6.12", "@jscad/stl-serializer": "^2.1.20", "circuit-json": "^0.0.421", "circuit-to-canvas": "^0.0.110", "react-hot-toast": "^2.6.0", "three": "^0.165.0", "three-stdlib": "^2.36.0", "troika-three-text": "^0.52.4" }, "peerDependencies": { "@tscircuit/circuit-json-util": "*", "@tscircuit/core": "*", "react": "19.1.0", "react-dom": "19.1.0", "zod": "3" } }, "sha512-U8R+RdXSX0rq0atMDSmrta91ultUWixkf8xqFkYHz63vecEFojipjIXD+9bbFyWyIo3TDUvCeYQozVXiKgTfdw=="], @@ -701,10 +738,14 @@ "anynum": ["anynum@1.0.1", "", {}, "sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A=="], + "arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="], + "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="], "array-flatten": ["array-flatten@1.1.1", "", {}, "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="], + "autoprefixer": ["autoprefixer@10.5.2", "", { "dependencies": { "browserslist": "^4.28.4", "caniuse-lite": "^1.0.30001799", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" }, "peerDependencies": { "postcss": "^8.1.0" }, "bin": { "autoprefixer": "bin/autoprefixer" } }, "sha512-rD5t5DwOjJdmSORcTq64j8MawTC+tbQ+HHqjR4NDumamy/ambn1UJrlKL+KdwujWxMkFjPM3pPHOEA9tl4767Q=="], + "b4a": ["b4a@1.8.1", "", { "peerDependencies": { "react-native-b4a": "*" }, "optionalPeers": ["react-native-b4a"] }, "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw=="], "babel-plugin-macros": ["babel-plugin-macros@3.1.0", "", { "dependencies": { "@babel/runtime": "^7.12.5", "cosmiconfig": "^7.0.0", "resolve": "^1.19.0" } }, "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg=="], @@ -775,6 +816,8 @@ "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], + "camelcase-css": ["camelcase-css@2.0.1", "", {}, "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="], + "camera-unproject": ["camera-unproject@1.0.1", "", {}, "sha512-IAta9EeGGa9rLJsw9Fk0lrZycDg2fF6nl6AvJ+QrkROxc4IaawosU9PQjoqgFYrOe1+kqJlod/W2TAZkTpxZQg=="], "caniuse-lite": ["caniuse-lite@1.0.30001799", "", {}, "sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw=="], @@ -871,6 +914,8 @@ "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], + "cssesc": ["cssesc@3.0.0", "", { "bin": { "cssesc": "bin/cssesc" } }, "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="], + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], "cwise-compiler": ["cwise-compiler@1.1.3", "", { "dependencies": { "uniq": "^1.0.0" } }, "sha512-WXlK/m+Di8DMMcCjcWr4i+XzcQra9eCdXIJrgh4TUgh0pIS/yJduLxS9JgefsHJ/YVLdgPtXm9r62W92MvanEQ=="], @@ -905,6 +950,10 @@ "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], + "didyoumean": ["didyoumean@1.2.2", "", {}, "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="], + + "dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="], + "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "^2.3.0", "domhandler": "^5.0.2", "entities": "^4.2.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], @@ -933,8 +982,6 @@ "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], - "enhanced-resolve": ["enhanced-resolve@5.21.6", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ=="], - "entities": ["entities@6.0.1", "", {}, "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g=="], "error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "^0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="], @@ -975,6 +1022,8 @@ "fast-fifo": ["fast-fifo@1.3.2", "", {}, "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ=="], + "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], "fast-png": ["fast-png@8.0.0", "", { "dependencies": { "fflate": "^0.8.2", "iobuffer": "^6.0.1" } }, "sha512-gCysNasJ8KEMgfdYIKd/wTDo6ENK1PWT0RJO7O+0pgmuHPw2O6tA1WvdxFRJoLf9V8yFYpG0FA1YgI8X97OhJA=="], @@ -983,6 +1032,8 @@ "fast-xml-parser": ["fast-xml-parser@5.9.3", "", { "dependencies": { "@nodable/entities": "^2.2.0", "fast-xml-builder": "^1.2.0", "is-unsafe": "^1.0.1", "path-expression-matcher": "^1.5.0", "strnum": "^2.4.1", "xml-naming": "^0.1.0" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-brCNCeScma/kqa54J4PIDriSSSLssRkuYaUCpvHJulGc3HGI/xxKUCTDcYkAdqJsyb//ydpbxecjC3hB9+tb/g=="], + "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], + "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], "fflate": ["fflate@0.8.3", "", {}, "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA=="], @@ -1009,6 +1060,8 @@ "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], + "fraction.js": ["fraction.js@5.3.4", "", {}, "sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ=="], + "fresh": ["fresh@0.5.2", "", {}, "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q=="], "fs-constants": ["fs-constants@1.0.0", "", {}, "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="], @@ -1043,7 +1096,7 @@ "glob": ["glob@10.5.0", "", { "dependencies": { "foreground-child": "^3.1.0", "jackspeak": "^3.1.2", "minimatch": "^9.0.4", "minipass": "^7.1.2", "package-json-from-dist": "^1.0.0", "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" } }, "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg=="], - "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], "goober": ["goober@2.1.19", "", { "peerDependencies": { "csstype": "^3.0.10" } }, "sha512-U7veizMqxyKlM58+Z5j2ngJBH/r9siDmxpvNxSw0PylF6WQvrASJEZrxh1hidRBJc2jqoBVSyOban5u8m+6Rxg=="], @@ -1125,7 +1178,7 @@ "jackspeak": ["jackspeak@3.4.3", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" }, "optionalDependencies": { "@pkgjs/parseargs": "^0.11.0" } }, "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw=="], - "jiti": ["jiti@2.7.0", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ=="], + "jiti": ["jiti@1.21.7", "", { "bin": { "jiti": "bin/jiti.js" } }, "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A=="], "joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="], @@ -1227,6 +1280,8 @@ "merge-descriptors": ["merge-descriptors@1.0.3", "", {}, "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ=="], + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], + "methods": ["methods@1.1.2", "", {}, "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w=="], "micromark-util-character": ["micromark-util-character@2.1.1", "", { "dependencies": { "micromark-util-symbol": "^2.0.0", "micromark-util-types": "^2.0.0" } }, "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q=="], @@ -1365,6 +1420,8 @@ "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], + "pify": ["pify@2.3.0", "", {}, "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="], + "pirates": ["pirates@4.0.7", "", {}, "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA=="], "pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], @@ -1377,8 +1434,18 @@ "postcss": ["postcss@8.5.15", "", { "dependencies": { "nanoid": "^3.3.12", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A=="], + "postcss-import": ["postcss-import@15.1.0", "", { "dependencies": { "postcss-value-parser": "^4.0.0", "read-cache": "^1.0.0", "resolve": "^1.1.7" }, "peerDependencies": { "postcss": "^8.0.0" } }, "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew=="], + + "postcss-js": ["postcss-js@4.1.0", "", { "dependencies": { "camelcase-css": "^2.0.1" }, "peerDependencies": { "postcss": "^8.4.21" } }, "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw=="], + "postcss-load-config": ["postcss-load-config@6.0.1", "", { "dependencies": { "lilconfig": "^3.1.1" }, "peerDependencies": { "jiti": ">=1.21.0", "postcss": ">=8.0.9", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["jiti", "postcss", "tsx", "yaml"] }, "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g=="], + "postcss-nested": ["postcss-nested@6.2.0", "", { "dependencies": { "postcss-selector-parser": "^6.1.1" }, "peerDependencies": { "postcss": "^8.2.14" } }, "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ=="], + + "postcss-selector-parser": ["postcss-selector-parser@6.1.4", "", { "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" } }, "sha512-bIoJLOmjCO1S9XdY/DcnR5hJxvrDir1PbGChrzXG3vw0/FOliy/fA3dmdhQ441kah4gKv+TwckGzex6wNS5cnQ=="], + + "postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="], + "posthog-js": ["posthog-js@1.395.0", "", { "dependencies": { "@posthog/core": "^1.38.0", "@posthog/types": "^1.391.1", "core-js": "^3.38.1", "dompurify": "^3.3.2", "fflate": "^0.4.8", "preact": "^10.29.2", "query-selector-shadow-dom": "^1.0.1", "web-vitals": "^5.3.0" } }, "sha512-5iTb00CGt2eQUUiBQysQiX89RAbCN6wK2sDNzvs9zv0alaY8mJ0ZySrUD3LQ+XyLhgM5pCpacBuUwChqiYDLDw=="], "potpack": ["potpack@1.0.2", "", {}, "sha512-choctRBIV9EMT9WGAZHn3V7t0Z2pMQyl0EZE6pFc/6ml3ssw7Dlf/oAOvFwjm1HVsqfQN8GfeFyJ+d8tRzqueQ=="], @@ -1405,6 +1472,10 @@ "query-selector-shadow-dom": ["query-selector-shadow-dom@1.0.1", "", {}, "sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw=="], + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + + "radix-ui": ["radix-ui@1.6.0", "", { "dependencies": { "@radix-ui/primitive": "1.1.4", "@radix-ui/react-accessible-icon": "1.1.10", "@radix-ui/react-accordion": "1.2.14", "@radix-ui/react-alert-dialog": "1.1.17", "@radix-ui/react-arrow": "1.1.10", "@radix-ui/react-aspect-ratio": "1.1.10", "@radix-ui/react-avatar": "1.2.0", "@radix-ui/react-checkbox": "1.3.5", "@radix-ui/react-collapsible": "1.1.14", "@radix-ui/react-collection": "1.1.10", "@radix-ui/react-compose-refs": "1.1.3", "@radix-ui/react-context": "1.1.4", "@radix-ui/react-context-menu": "2.3.1", "@radix-ui/react-dialog": "1.1.17", "@radix-ui/react-direction": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.13", "@radix-ui/react-dropdown-menu": "2.1.18", "@radix-ui/react-focus-guards": "1.1.4", "@radix-ui/react-focus-scope": "1.1.10", "@radix-ui/react-form": "0.1.10", "@radix-ui/react-hover-card": "1.1.17", "@radix-ui/react-label": "2.1.10", "@radix-ui/react-menu": "2.1.18", "@radix-ui/react-menubar": "1.1.18", "@radix-ui/react-navigation-menu": "1.2.16", "@radix-ui/react-one-time-password-field": "0.1.10", "@radix-ui/react-password-toggle-field": "0.1.5", "@radix-ui/react-popover": "1.1.17", "@radix-ui/react-popper": "1.3.1", "@radix-ui/react-portal": "1.1.12", "@radix-ui/react-presence": "1.1.6", "@radix-ui/react-primitive": "2.1.6", "@radix-ui/react-progress": "1.1.10", "@radix-ui/react-radio-group": "1.4.1", "@radix-ui/react-roving-focus": "1.1.13", "@radix-ui/react-scroll-area": "1.2.12", "@radix-ui/react-select": "2.3.1", "@radix-ui/react-separator": "1.1.10", "@radix-ui/react-slider": "1.4.1", "@radix-ui/react-slot": "1.3.0", "@radix-ui/react-switch": "1.3.1", "@radix-ui/react-tabs": "1.1.15", "@radix-ui/react-toast": "1.2.17", "@radix-ui/react-toggle": "1.1.12", "@radix-ui/react-toggle-group": "1.1.13", "@radix-ui/react-toolbar": "1.1.13", "@radix-ui/react-tooltip": "1.2.10", "@radix-ui/react-use-callback-ref": "1.1.2", "@radix-ui/react-use-controllable-state": "1.2.3", "@radix-ui/react-use-effect-event": "0.0.3", "@radix-ui/react-use-escape-keydown": "1.1.2", "@radix-ui/react-use-is-hydrated": "0.1.1", "@radix-ui/react-use-layout-effect": "1.1.2", "@radix-ui/react-use-size": "1.1.2", "@radix-ui/react-visually-hidden": "1.2.6" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-EUEC70O03EgxWMP5aoqfBZ6iLC5bczFagGy7zhSYRt8o5DP7IWNiP3ywetse3L9b8843ExB0OGWZvgbYVJuNeg=="], + "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], "raw-body": ["raw-body@2.5.3", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "unpipe": "~1.0.0" } }, "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA=="], @@ -1453,6 +1524,8 @@ "react-toastify": ["react-toastify@10.0.6", "", { "dependencies": { "clsx": "^2.1.0" }, "peerDependencies": { "react": ">=18", "react-dom": ">=18" } }, "sha512-yYjp+omCDf9lhZcrZHKbSq7YMuK0zcYkDFTzfRFgTXkTFHZ1ToxwAonzA4JI5CxA91JpjFLmwEsZEgfYfOqI1A=="], + "read-cache": ["read-cache@1.0.0", "", { "dependencies": { "pify": "^2.3.0" } }, "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA=="], + "readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], @@ -1479,6 +1552,8 @@ "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], + "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], + "rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], "rolldown": ["rolldown@1.1.3", "", { "dependencies": { "@oxc-project/types": "=0.137.0", "@rolldown/pluginutils": "^1.0.0" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.1.3", "@rolldown/binding-darwin-arm64": "1.1.3", "@rolldown/binding-darwin-x64": "1.1.3", "@rolldown/binding-freebsd-x64": "1.1.3", "@rolldown/binding-linux-arm-gnueabihf": "1.1.3", "@rolldown/binding-linux-arm64-gnu": "1.1.3", "@rolldown/binding-linux-arm64-musl": "1.1.3", "@rolldown/binding-linux-ppc64-gnu": "1.1.3", "@rolldown/binding-linux-s390x-gnu": "1.1.3", "@rolldown/binding-linux-x64-gnu": "1.1.3", "@rolldown/binding-linux-x64-musl": "1.1.3", "@rolldown/binding-openharmony-arm64": "1.1.3", "@rolldown/binding-wasm32-wasi": "1.1.3", "@rolldown/binding-win32-arm64-msvc": "1.1.3", "@rolldown/binding-win32-x64-msvc": "1.1.3" }, "bin": { "rolldown": "./bin/cli.mjs" } }, "sha512-1F1eEtUBtFvcGm1HQ9TiUIUHPQG7mSAODrhIzjxoUEFuo8OcbrGLiVLkevNgj84TE4lnHvnumwFjhJO5Eu135g=="], @@ -1489,6 +1564,8 @@ "run-applescript": ["run-applescript@7.1.0", "", {}, "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q=="], + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + "s-expression": ["s-expression@3.1.1", "", {}, "sha512-VMsW7sIvixXfIDmDll7XCePMYYY52UlUtA7OlFQUovqj3XtQ2UkZkjjAvnSFW8o+SbswzUEeCBMmpAx9LS3qrg=="], "safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], @@ -1579,9 +1656,9 @@ "tailwind-merge": ["tailwind-merge@3.6.0", "", {}, "sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w=="], - "tailwindcss": ["tailwindcss@4.3.1", "", {}, "sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q=="], + "tailwindcss": ["tailwindcss@3.4.19", "", { "dependencies": { "@alloc/quick-lru": "^5.2.0", "arg": "^5.0.2", "chokidar": "^3.6.0", "didyoumean": "^1.2.2", "dlv": "^1.1.3", "fast-glob": "^3.3.2", "glob-parent": "^6.0.2", "is-glob": "^4.0.3", "jiti": "^1.21.7", "lilconfig": "^3.1.3", "micromatch": "^4.0.8", "normalize-path": "^3.0.0", "object-hash": "^3.0.0", "picocolors": "^1.1.1", "postcss": "^8.4.47", "postcss-import": "^15.1.0", "postcss-js": "^4.0.1", "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", "postcss-nested": "^6.2.0", "postcss-selector-parser": "^6.1.2", "resolve": "^1.22.8", "sucrase": "^3.35.0" }, "bin": { "tailwind": "lib/cli.js", "tailwindcss": "lib/cli.js" } }, "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ=="], - "tapable": ["tapable@2.3.3", "", {}, "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A=="], + "tailwindcss-animate": ["tailwindcss-animate@1.0.7", "", { "peerDependencies": { "tailwindcss": ">=3.0.0 || insiders" } }, "sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA=="], "tar-fs": ["tar-fs@3.1.3", "", { "dependencies": { "pump": "^3.0.0", "tar-stream": "^3.1.5" }, "optionalDependencies": { "bare-fs": "^4.0.1", "bare-path": "^3.0.0" } }, "sha512-/hU4AXnIdZu+Gvl1pk0oI5f5HxWsCJRtY2aFaJdk9VvyL48DWU6iU5WAIPG+wIi1YvWA6eTJvIviP/tMAZZNwQ=="], @@ -1595,7 +1672,7 @@ "thenify-all": ["thenify-all@1.6.0", "", { "dependencies": { "thenify": ">= 3.1.0 < 4" } }, "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA=="], - "three": ["three@0.185.0", "", {}, "sha512-+yRrcRO2iZa8uzvNNl0d7cL4huhgKgBvVJ0njcTe8xFqZ6DMAFZdCKDP91SEAuj25bNAj7k1QQdf+srZywVK6w=="], + "three": ["three@0.165.0", "", {}, "sha512-cc96IlVYGydeceu0e5xq70H8/yoVT/tXBxV/W8A/U6uOq7DXc4/s1Mkmnu6SqoYGhSRWWYFOhVwvq6V0VtbplA=="], "three-stdlib": ["three-stdlib@2.36.1", "", { "dependencies": { "@types/draco3d": "^1.4.0", "@types/offscreencanvas": "^2019.6.4", "@types/webxr": "^0.5.2", "draco3d": "^1.4.1", "fflate": "^0.6.9", "potpack": "^1.0.1" }, "peerDependencies": { "three": ">=0.128.0" } }, "sha512-XyGQrFmNQ5O/IoKm556ftwKsBg11TIb301MB5dWNicziQBEs2g3gtOYIf7pFiLa0zI2gUwhtCjv9fmjnxKZ1Cg=="], @@ -1727,20 +1804,6 @@ "@isaacs/cliui/wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", "strip-ansi": "^7.0.1" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], - "@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/runtime": ["@emnapi/runtime@1.11.1", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw=="], - - "@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/@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.6", "", { "dependencies": { "@tybys/wasm-util": "^0.10.3" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" }, "bundled": true }, "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg=="], - - "@tailwindcss/oxide-wasm32-wasi/@tybys/wasm-util": ["@tybys/wasm-util@0.10.3", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg=="], - - "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], - - "@tscircuit/3d-viewer/three": ["three@0.165.0", "", {}, "sha512-cc96IlVYGydeceu0e5xq70H8/yoVT/tXBxV/W8A/U6uOq7DXc4/s1Mkmnu6SqoYGhSRWWYFOhVwvq6V0VtbplA=="], - "@tscircuit/pcb-viewer/@vitejs/plugin-react": ["@vitejs/plugin-react@5.2.0", "", { "dependencies": { "@babel/core": "^7.29.0", "@babel/plugin-transform-react-jsx-self": "^7.27.1", "@babel/plugin-transform-react-jsx-source": "^7.27.1", "@rolldown/pluginutils": "1.0.0-rc.3", "@types/babel__core": "^7.20.5", "react-refresh": "^0.18.0" }, "peerDependencies": { "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw=="], "@tscircuit/pcb-viewer/zustand": ["zustand@4.5.7", "", { "dependencies": { "use-sync-external-store": "^1.2.2" }, "peerDependencies": { "@types/react": ">=16.8", "immer": ">=9.0.6", "react": ">=16.8" }, "optionalPeers": ["@types/react", "immer", "react"] }, "sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw=="], @@ -1761,6 +1824,8 @@ "calculate-cell-boundaries/react-dom": ["react-dom@18.3.1", "", { "dependencies": { "loose-envify": "^1.1.0", "scheduler": "^0.23.2" }, "peerDependencies": { "react": "^18.3.1" } }, "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw=="], + "chokidar/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + "circuit-json-to-connectivity-map/@tscircuit/math-utils": ["@tscircuit/math-utils@0.0.9", "", { "peerDependencies": { "typescript": "^5.0.0" } }, "sha512-sPzfXndijet8z29X6f5vnSZddiso2tRg7m6rB+268bVj60mxnxUMD14rKuMlLn6n84fMOpD/X7pRTZUfi6M+Tg=="], "circuit-json-to-spice/circuit-json-to-connectivity-map": ["circuit-json-to-connectivity-map@0.0.22", "", { "dependencies": { "@tscircuit/math-utils": "^0.0.9" }, "peerDependencies": { "typescript": "^5.0.0" } }, "sha512-HN8DiISjZZLTglGEkYNRpKeQ/DMG4dDo5j4Hck0UGSJbpux9aFwtJOGszMf06Inh/gu5oKBrpZJIeWxaNacKUg=="], @@ -1779,6 +1844,8 @@ "express/safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + "finalhandler/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], "glob/minimatch": ["minimatch@9.0.9", "", { "dependencies": { "brace-expansion": "^2.0.2" } }, "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg=="], diff --git a/components.json b/components.json new file mode 100644 index 0000000..28c7d0a --- /dev/null +++ b/components.json @@ -0,0 +1,25 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/styles.css", + "baseColor": "slate", + "cssVariables": false, + "prefix": "" + }, + "iconLibrary": "lucide", + "rtl": false, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "menuColor": "default", + "menuAccent": "subtle", + "registries": {} +} diff --git a/examples/TscircuitWorkspace.fixture.tsx b/examples/TscircuitWorkspace.fixture.tsx index 3ed75eb..899f18b 100644 --- a/examples/TscircuitWorkspace.fixture.tsx +++ b/examples/TscircuitWorkspace.fixture.tsx @@ -1,4 +1,5 @@ import "../src/styles.css" +import { Toaster } from "react-hot-toast" import { WorkspaceCodeEditor, type EditorFile, @@ -97,6 +98,24 @@ export const MPL3115A2R1 = (props: ChipProps) => { "schematic_placements": [], "edit_events": [] } +`, + }, + { + path: "lib/constants.ts", + content: `export const BOARD_WIDTH_MM = 15.24 +export const BOARD_HEIGHT_MM = 17.78 +`, + }, + { + path: "lib/footprints/cap0402.ts", + content: `export const cap0402 = "cap0402" +`, + }, + { + path: "README.md", + content: `# MPL3115A2 breakout + +A tiny tscircuit example board. Edit \`index.tsx\` to get started. `, }, ] @@ -110,6 +129,7 @@ export default function TscircuitWorkspaceFixture() { return (
+
) } diff --git a/examples/TscircuitWorkspaceWithRunframe.fixture.tsx b/examples/TscircuitWorkspaceWithRunframe.fixture.tsx index 5401ace..74f8319 100644 --- a/examples/TscircuitWorkspaceWithRunframe.fixture.tsx +++ b/examples/TscircuitWorkspaceWithRunframe.fixture.tsx @@ -6,106 +6,31 @@ import { resolveTscircuitEntrypoint } from "../fixtures-support/resolveTscircuit import { WorkspaceCodeEditor } from "../src/components/WorkspaceCodeEditor" import { useWorkspaceFiles } from "../src/hooks/useWorkspaceFiles" -const initialFiles: EditorFile[] = [ - { - path: "index.tsx", - content: `import manualEdits from "./manual-edits.json" -import { MPL3115A2R1 } from "./MPL3115A2R1" -import { sel } from "tscircuit" - -export default () => ( - - - - - - - - -) -`, - }, - { - path: "MPL3115A2R1.tsx", - content: `import type { ChipProps } from "@tscircuit/props" +// Real SparkFun Qwiic MicroPressure Sensor board (copied verbatim from +// ../sparkfun-boards) loaded as raw source so the tree sidebar shows a genuine +// multi-folder package: an `imports/` folder of chip definitions alongside the +// board entrypoint. We skip the board's `index.tsx` (it only re-exports the +// circuit) and run the `.circuit.tsx` directly. +import circuitSource from "../fixtures-support/assets/sparkfun-qwiic-micropressure/SparkFun-Qwiic-MicroPressure-Sensor.circuit.tsx?raw" +import readmeSource from "../fixtures-support/assets/sparkfun-qwiic-micropressure/README.md?raw" +import mprlsSource from "../fixtures-support/assets/sparkfun-qwiic-micropressure/imports/MPRLS0025PA00001A.tsx?raw" +import sm04bSource from "../fixtures-support/assets/sparkfun-qwiic-micropressure/imports/SM04B_SRSS_TB_LF__SN.tsx?raw" +import sm04b2Source from "../fixtures-support/assets/sparkfun-qwiic-micropressure/imports/SM04B_SRSS_TB_LF__SN2.tsx?raw" -const pinLabels = { - pin1: ["VDD"], - pin2: ["CAP"], - pin3: ["GND"], - pin4: ["VDDIO"], - pin5: ["INT2"], - pin6: ["INT1"], - pin7: ["SDA"], - pin8: ["SCL"], -} as const +const BOARD_ENTRYPOINT = "SparkFun-Qwiic-MicroPressure-Sensor.circuit.tsx" -export const MPL3115A2R1 = (props: ChipProps) => { - return ( - - - - - - - - - - - } - /> - ) -} -`, - }, - { - path: "manual-edits.json", - content: `{ - "pcb_placements": [], - "schematic_placements": [], - "edit_events": [] -} -`, - }, +const initialFiles: EditorFile[] = [ + { path: BOARD_ENTRYPOINT, content: circuitSource }, + { path: "imports/MPRLS0025PA00001A.tsx", content: mprlsSource }, + { path: "imports/SM04B_SRSS_TB_LF__SN.tsx", content: sm04bSource }, + { path: "imports/SM04B_SRSS_TB_LF__SN2.tsx", content: sm04b2Source }, + { path: "README.md", content: readmeSource }, ] export default function TscircuitWorkspaceWithRunframeFixture() { const workspace = useWorkspaceFiles({ initialFiles, - initialCurrentFile: "index.tsx", + initialCurrentFile: BOARD_ENTRYPOINT, }) const [lastRenderState, setLastRenderState] = useState< "idle" | "running" | "finished" @@ -124,7 +49,7 @@ export default function TscircuitWorkspaceWithRunframeFixture() { const mainComponentPath = useMemo( () => resolveTscircuitEntrypoint(workspace.files, workspace.currentFile) ?? - "index.tsx", + BOARD_ENTRYPOINT, [workspace.files, workspace.currentFile], ) diff --git a/fixtures-support/assets/sparkfun-qwiic-micropressure/README.md b/fixtures-support/assets/sparkfun-qwiic-micropressure/README.md new file mode 100644 index 0000000..a985ff7 --- /dev/null +++ b/fixtures-support/assets/sparkfun-qwiic-micropressure/README.md @@ -0,0 +1,5 @@ +# SparkFun Qwiic MicroPressure Sensor + +For more information about this board, visit the official SparkFun product page: + +[https://www.sparkfun.com/sparkfun-qwiic-micropressure-sensor.html](https://www.sparkfun.com/sparkfun-qwiic-micropressure-sensor.html) diff --git a/fixtures-support/assets/sparkfun-qwiic-micropressure/SparkFun-Qwiic-MicroPressure-Sensor.circuit.tsx b/fixtures-support/assets/sparkfun-qwiic-micropressure/SparkFun-Qwiic-MicroPressure-Sensor.circuit.tsx new file mode 100644 index 0000000..6536a61 --- /dev/null +++ b/fixtures-support/assets/sparkfun-qwiic-micropressure/SparkFun-Qwiic-MicroPressure-Sensor.circuit.tsx @@ -0,0 +1,338 @@ +import { sel } from "tscircuit" +import { MPRLS0025PA00001A } from "./imports/MPRLS0025PA00001A" +import { SM04B_SRSS_TB_LF__SN } from "./imports/SM04B_SRSS_TB_LF__SN" +import { SM04B_SRSS_TB_LF__SN2 } from "./imports/SM04B_SRSS_TB_LF__SN2" + +const qwiicHeaderLabels = { + pin1: ["GND"], + pin2: ["3V3"], + pin3: ["SDA"], + pin4: ["SCL"], +} + +const eocResetHeaderLabels = { + pin1: ["RESET"], + pin2: ["EOC"], +} + +export default () => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ) +} diff --git a/fixtures-support/assets/sparkfun-qwiic-micropressure/imports/MPRLS0025PA00001A.tsx b/fixtures-support/assets/sparkfun-qwiic-micropressure/imports/MPRLS0025PA00001A.tsx new file mode 100644 index 0000000..0ebc619 --- /dev/null +++ b/fixtures-support/assets/sparkfun-qwiic-micropressure/imports/MPRLS0025PA00001A.tsx @@ -0,0 +1,81 @@ +import type { ChipProps } from "@tscircuit/props" + +const pinLabels = { + pin1: ["SS"], + pin2: ["MOSI", "SDA"], + pin3: ["SCLK", "SCL"], + pin4: ["VO_POS"], + pin5: ["NC1"], + pin6: ["VO_NEG"], + pin7: ["MISO"], + pin8: ["EOC"], + pin9: ["RESET"], + pin10: ["GND"], + pin11: ["NC2"], + pin12: ["VDD"], +} as const + +export const MPRLS0025PA00001A = (props: ChipProps) => { + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + } + cadModel={{ + objUrl: + "https://modelcdn.tscircuit.com/easyeda_models/assets/C3257154.obj?uuid=7364e275613048ceb87ae8926d81a54e", + stepUrl: + "https://modelcdn.tscircuit.com/easyeda_models/assets/C3257154.step?uuid=7364e275613048ceb87ae8926d81a54e", + pcbRotationOffset: 0, + modelOriginPosition: { x: 0, y: 0.2912914000001403, z: -0.311591 }, + }} + {...props} + /> + ) +} diff --git a/fixtures-support/assets/sparkfun-qwiic-micropressure/imports/SM04B_SRSS_TB_LF__SN.tsx b/fixtures-support/assets/sparkfun-qwiic-micropressure/imports/SM04B_SRSS_TB_LF__SN.tsx new file mode 100644 index 0000000..a91dc9d --- /dev/null +++ b/fixtures-support/assets/sparkfun-qwiic-micropressure/imports/SM04B_SRSS_TB_LF__SN.tsx @@ -0,0 +1,48 @@ +import type { ChipProps } from "@tscircuit/props" + +const pinLabels = { + pin1: ["GND"], + pin2: ["VDD"], + pin3: ["SDA"], + pin4: ["SCL"], +} as const + +export const SM04B_SRSS_TB_LF__SN = (props: ChipProps) => { + return ( + + + + + + + + + + + + + } + cadModel={{ + objUrl: + "https://modelcdn.tscircuit.com/easyeda_models/download?uuid=96ff162c26934a308e7bbf01d083d593&pn=C160404", + rotationOffset: { x: 0, y: 0, z: 0 }, + positionOffset: { x: 0, y: -1.5, z: 0 }, + }} + {...props} + /> + ) +} diff --git a/fixtures-support/assets/sparkfun-qwiic-micropressure/imports/SM04B_SRSS_TB_LF__SN2.tsx b/fixtures-support/assets/sparkfun-qwiic-micropressure/imports/SM04B_SRSS_TB_LF__SN2.tsx new file mode 100644 index 0000000..194c971 --- /dev/null +++ b/fixtures-support/assets/sparkfun-qwiic-micropressure/imports/SM04B_SRSS_TB_LF__SN2.tsx @@ -0,0 +1,48 @@ +import type { ChipProps } from "@tscircuit/props" + +const pinLabels = { + pin1: ["GND"], + pin2: ["VDD"], + pin3: ["SDA"], + pin4: ["SCL"], +} as const + +export const SM04B_SRSS_TB_LF__SN2 = (props: ChipProps) => { + return ( + + + + + + + + + + + + + } + cadModel={{ + objUrl: + "https://modelcdn.tscircuit.com/easyeda_models/download?uuid=96ff162c26934a308e7bbf01d083d593&pn=C160404", + rotationOffset: { x: 0, y: 0, z: 0 }, + positionOffset: { x: 0, y: 1.5, z: 0 }, + }} + {...props} + /> + ) +} diff --git a/package.json b/package.json index ebfa29c..4d1dc50 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "@radix-ui/react-slot": "^1.3.0", "@radix-ui/react-tabs": "^1.1.15", "@radix-ui/react-tooltip": "^1.2.10", - "@tailwindcss/vite": "^4.3.1", "@tscircuit/3d-viewer": "^0.0.571", "@tscircuit/assembly-viewer": "^0.0.6", "@tscircuit/core": "^0.0.1362", @@ -45,6 +44,7 @@ "@types/react": "^19.2.17", "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.3", + "autoprefixer": "^10.4.20", "circuit-json-to-bom-csv": "^0.0.9", "circuit-json-to-pnp-csv": "^0.0.8", "class-variance-authority": "^0.7.1", @@ -59,6 +59,7 @@ "marked": "^18.0.5", "minimatch": "^10.2.5", "posthog-js": "^1.395.0", + "postcss": "^8.4.47", "react": "^19.2.7", "react-cosmos": "^7.3.0", "react-cosmos-plugin-vite": "^7.3.0", @@ -67,8 +68,9 @@ "react-hot-toast": "^2.6.0", "react-query": "^3.39.3", "tailwind-merge": "^3.6.0", - "tailwindcss": "^4.3.1", - "three": "^0.185.0", + "tailwindcss": "^3.4.13", + "tailwindcss-animate": "^1.0.7", + "three": "0.165.0", "tsup": "^8.5.1", "vite": "^8.1.0", "zustand": "^5.0.14" @@ -78,11 +80,13 @@ "react-dom": ">=18" }, "dependencies": { + "@fontsource-variable/geist": "^5.2.9", "@monaco-editor/react": "^4.7.0", "@shikijs/monaco": "^4.3.0", "@shikijs/vscode-textmate": "^10.0.2", "@typescript/ata": "^0.9.8", "monaco-editor": "^0.55.1", + "radix-ui": "^1.6.0", "shiki": "^4.3.0", "typescript": "^6.0.3" } diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..2e7af2b --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/src/components/FileSidebar.tsx b/src/components/FileSidebar.tsx new file mode 100644 index 0000000..74f278c --- /dev/null +++ b/src/components/FileSidebar.tsx @@ -0,0 +1,264 @@ +import { Loader2, PanelRightClose, PanelRightOpen, Plus } from "lucide-react" +import { useMemo, useState } from "react" +import { Input } from "@/components/ui/input" +import { TreeView } from "@/components/ui/tree-view" +import type { + CreateFileProps, + CreateFileResult, + DeleteFileProps, + DeleteFileResult, + EditorFile, + RenameFileProps, + RenameFileResult, +} from "@/components/WorkspaceCodeEditor" +import { cn } from "@/lib/utils" +import { + constructFilePath, + getCurrentFolderPath, + getFolderPlaceholder, +} from "@/utils/fileSidebarPaths" +import { transformFilesToTreeData } from "@/utils/transformFilesToTreeData" + +export type FileSidebarProps = { + files: EditorFile[] + currentFile: string | null + onFileSelect: (filename: string) => void + handleCreateFile?: (props: CreateFileProps) => CreateFileResult + handleDeleteFile?: (props: DeleteFileProps) => DeleteFileResult + handleRenameFile?: (props: RenameFileProps) => RenameFileResult + isLoadingFiles?: boolean + loadingProgress?: string | null + /** Controlled open state. When omitted the sidebar manages its own. */ + open?: boolean + onOpenChange?: (open: boolean) => void + className?: string +} + +const noopRename = (): RenameFileResult => ({ fileRenamed: false }) +const noopDelete = (): DeleteFileResult => ({ fileDeleted: false }) + +export function FileSidebar({ + files, + currentFile, + onFileSelect, + handleCreateFile, + handleDeleteFile, + handleRenameFile, + isLoadingFiles = false, + loadingProgress = null, + open, + onOpenChange, + className, +}: FileSidebarProps) { + const [internalOpen, setInternalOpen] = useState(true) + const sidebarOpen = open ?? internalOpen + const setSidebarOpen = (next: boolean) => { + onOpenChange?.(next) + if (open !== undefined) return + setInternalOpen(next) + } + const [isCreatingFile, setIsCreatingFile] = useState(false) + const [newFileName, setNewFileName] = useState("") + const [errorMessage, setErrorMessage] = useState("") + const [renamingFile, setRenamingFile] = useState(null) + const [selectedFolderForCreation, setSelectedFolderForCreation] = useState< + string | null + >(null) + const [openDropdownId, setOpenDropdownId] = useState(null) + + const selectedItemId = currentFile ?? "" + const canModifyFiles = + Boolean(handleRenameFile && handleDeleteFile) && !isLoadingFiles + const currentFolderPath = getCurrentFolderPath( + selectedFolderForCreation, + selectedItemId, + ) + + const filesRecord = useMemo( + () => Object.fromEntries(files.map((file) => [file.path, file.content])), + [files], + ) + + const treeData = transformFilesToTreeData({ + files: filesRecord, + currentFile, + renamingFile, + handleRenameFile: handleRenameFile ?? noopRename, + handleDeleteFile: handleDeleteFile ?? noopDelete, + setRenamingFile, + onFileSelect, + onFolderSelect: setSelectedFolderForCreation, + canModifyFiles, + setErrorMessage, + setSelectedFolderForCreation, + openDropdownId, + setOpenDropdownId, + }) + + const resetCreateFileState = () => { + setIsCreatingFile(false) + setNewFileName("") + setErrorMessage("") + setSelectedFolderForCreation(null) + } + + const handleCreateFileInline = () => { + if (!handleCreateFile) return + const finalFileName = constructFilePath(newFileName, currentFolderPath) + if (!finalFileName) { + setErrorMessage("File name cannot be empty") + return + } + + const { newFileCreated } = handleCreateFile({ + newFileName: finalFileName, + openFile: true, + onError: (error) => { + setErrorMessage(error.message) + }, + }) + + if (newFileCreated) { + resetCreateFileState() + onFileSelect(finalFileName) + } + } + + const handleCreateFileBlur = () => { + if (newFileName.trim() === "") { + resetCreateFileState() + return + } + handleCreateFileInline() + } + + const isControlled = open !== undefined + + if (!sidebarOpen && !isControlled) { + return ( +
+ +
+ ) + } + + return ( +
+
+ +
+ {isLoadingFiles && ( +
+ + {loadingProgress && ( + + {loadingProgress} + + )} +
+ )} + {handleCreateFile && ( + + )} +
+
+ + {isCreatingFile && ( +
+ { + setNewFileName(e.target.value) + if (errorMessage) { + setErrorMessage("") + } + }} + onBlur={handleCreateFileBlur} + onKeyDown={(e) => { + if (e.key === "Enter") { + e.preventDefault() + handleCreateFileInline() + } else if (e.key === "Escape") { + e.preventDefault() + resetCreateFileState() + } else if (e.key === "Tab") { + e.preventDefault() + if (currentFolderPath && !newFileName.includes("/")) { + const displayPath = currentFolderPath.startsWith("/") + ? currentFolderPath.slice(1) + : currentFolderPath + setNewFileName(`${displayPath}/`) + } + } + }} + placeholder={getFolderPlaceholder(currentFolderPath)} + className={ + errorMessage ? "border-red-500 focus-visible:ring-red-500" : "" + } + /> + {errorMessage && ( +
{errorMessage}
+ )} +
+ Tip: Use / for subfolders, Tab to auto-complete current folder +
+
+ )} + +
+ { + if (value && filesRecord[value] !== undefined) { + onFileSelect(value) + } + }} + selectedItemId={selectedItemId} + onSelectChange={(item) => { + if (item?.onClick) { + item.onClick() + } + }} + /> +
+
+ ) +} diff --git a/src/components/WorkspaceCodeEditor.tsx b/src/components/WorkspaceCodeEditor.tsx index c9be3e8..3740624 100644 --- a/src/components/WorkspaceCodeEditor.tsx +++ b/src/components/WorkspaceCodeEditor.tsx @@ -1,4 +1,5 @@ import Editor, { type OnChange, type OnMount } from "@monaco-editor/react" +import { PanelRightClose } from "lucide-react" import { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react" import * as monaco from "monaco-editor" import { @@ -11,6 +12,15 @@ import { createMonacoWorkspaceModelManager, type MonacoWorkspaceModelManager, } from "../monaco/monacoWorkspace" +import { isHiddenFile } from "../utils/isHiddenFile" +import { FileSidebar } from "./FileSidebar" +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "./ui/select" export type EditorFile = { path: string @@ -70,9 +80,6 @@ export type WorkspaceCodeEditorProps = { options?: monaco.editor.IStandaloneEditorConstructionOptions } -const sidebarIconButtonClassName = - "rounded px-1 py-0.5 text-xs leading-none transition hover:bg-slate-200/80 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-1" - const isCodeFile = (path: string | null): path is string => !!path && /\.(ts|tsx|js|jsx)$/.test(path) @@ -110,6 +117,7 @@ export function WorkspaceCodeEditor({ const isReady = useMonacoReady() const [editorReady, setEditorReady] = useState(false) const [workspaceModelsReady, setWorkspaceModelsReady] = useState(false) + const [sidebarOpen, setSidebarOpen] = useState(true) const editorRef = useRef(null) const managerRef = useRef(null) @@ -146,6 +154,16 @@ export function WorkspaceCodeEditor({ [files], ) + // Files offered in the top-bar dropdown: hide noise (lockfiles, dist, …) but + // always keep the active file selectable even when it is itself hidden. + const dropdownFiles = useMemo( + () => + files.filter( + (file) => !isHiddenFile(file.path) || file.path === currentFile, + ), + [files, currentFile], + ) + const editorOptions = useMemo( () => ({ @@ -266,124 +284,124 @@ export function WorkspaceCodeEditor({ onFileContentChanged?.(currentFile, nextValue) } - const promptCreateFile = () => { - if (!handleCreateFile) return - const newFileName = window.prompt("New file name")?.trim() - if (!newFileName) return - handleCreateFile({ - newFileName, - openFile: true, - onError: (error) => window.alert(error.message), - }) - } - - const promptRenameFile = (path: string) => { - if (!handleRenameFile) return - const newFilename = window.prompt("Rename file", path)?.trim() - if (!newFilename || newFilename === path) return - handleRenameFile({ - oldFilename: path, - newFilename, - onError: (error) => window.alert(error.message), - }) - } + let editorBody: React.ReactNode - const confirmDeleteFile = (path: string) => { - if (!handleDeleteFile) return - if (!window.confirm(`Delete ${path}?`)) return - handleDeleteFile({ - filename: path, - onError: (error) => window.alert(error.message), - }) + if (isStreaming) { + editorBody = ( +
+        {currentContent}
+      
+ ) + } else if (currentFileIsBinary) { + editorBody = + } else if (!isReady || !workspaceModelsReady || isPriorityFilePending) { + editorBody = Loading editor… + } else if (currentFile) { + editorBody = ( + + ) + } else { + editorBody = ( + Select a file to start editing + ) } return (
{showSidebar && ( -
-
- Files - {handleCreateFile && ( - - )} -
- {files.map((file) => { - const isActive = file.path === currentFile - return ( -
onFileSelect(file.path)} - > - - {file.path} - - {handleRenameFile && ( - - )} - {handleDeleteFile && ( - - )} -
- ) - })} -
+ )} -
- {isStreaming ? ( -
-            {currentContent}
-          
- ) : currentFileIsBinary ? ( - - ) : !isReady || !workspaceModelsReady || isPriorityFilePending ? ( - Loading editor… - ) : currentFile ? ( - + {showSidebar && ( + setSidebarOpen(true)} + files={dropdownFiles} + currentFile={currentFile} + onFileSelect={onFileSelect} /> - ) : ( - Select a file to start editing )} + +
{editorBody}
+
+
+ ) +} + +function EditorTopBar({ + sidebarOpen, + onShowSidebar, + files, + currentFile, + onFileSelect, +}: { + sidebarOpen: boolean + onShowSidebar: () => void + files: EditorFile[] + currentFile: string | null + onFileSelect: (path: string) => void +}) { + const fileLabelWidthClass = sidebarOpen + ? "max-w-[8rem] sm:max-w-[12rem]" + : "max-w-[12rem] sm:max-w-[16rem]" + + return ( +
+ +
+
) diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx new file mode 100644 index 0000000..0b41ed8 --- /dev/null +++ b/src/components/ui/button.tsx @@ -0,0 +1,65 @@ +import * as React from "react" +import { cva, type VariantProps } from "class-variance-authority" +import { Slot } from "radix-ui" + +import { cn } from "@/lib/utils" + +const buttonVariants = cva( + "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-slate-950 disabled:pointer-events-none disabled:opacity-50 dark:focus-visible:ring-slate-300 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", + { + variants: { + variant: { + default: + "bg-slate-900 text-slate-50 shadow hover:bg-slate-900/90 dark:bg-slate-50 dark:text-slate-900 dark:hover:bg-slate-50/90", + destructive: + "bg-red-500 text-slate-50 shadow-sm hover:bg-red-500/90 dark:bg-red-900 dark:text-slate-50 dark:hover:bg-red-900/90", + outline: + "border border-slate-200 bg-white shadow-sm hover:bg-slate-100 hover:text-slate-900 dark:border-slate-800 dark:bg-slate-950 dark:hover:bg-slate-800 dark:hover:text-slate-50", + secondary: + "bg-slate-100 text-slate-900 shadow-sm hover:bg-slate-100/80 dark:bg-slate-800 dark:text-slate-50 dark:hover:bg-slate-800/80", + ghost: + "hover:bg-slate-100 hover:text-slate-900 dark:hover:bg-slate-800 dark:hover:text-slate-50", + link: "text-slate-900 underline-offset-4 hover:underline dark:text-slate-50", + }, + size: { + default: "h-9 px-4 py-2", + xs: "h-6 rounded-md px-2 text-xs", + sm: "h-8 rounded-md px-3 text-xs", + lg: "h-10 rounded-md px-8", + icon: "h-9 w-9", + "icon-xs": "h-6 w-6", + "icon-sm": "h-7 w-7", + "icon-lg": "h-10 w-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + }, +) + +function Button({ + className, + variant = "default", + size = "default", + asChild = false, + ...props +}: React.ComponentProps<"button"> & + VariantProps & { + asChild?: boolean + }) { + const Comp = asChild ? Slot.Root : "button" + + return ( + + ) +} + +export { Button, buttonVariants } diff --git a/src/components/ui/dropdown-menu.tsx b/src/components/ui/dropdown-menu.tsx new file mode 100644 index 0000000..9aba68d --- /dev/null +++ b/src/components/ui/dropdown-menu.tsx @@ -0,0 +1,274 @@ +import * as React from "react" +import { DropdownMenu as DropdownMenuPrimitive } from "radix-ui" + +import { cn } from "@/lib/utils" +import { CheckIcon, ChevronRightIcon } from "lucide-react" + +function DropdownMenu({ + ...props +}: React.ComponentProps) { + return +} + +function DropdownMenuPortal({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuContent({ + className, + align = "start", + sideOffset = 4, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +function DropdownMenuGroup({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuItem({ + className, + inset, + variant = "default", + ...props +}: React.ComponentProps & { + inset?: boolean + variant?: "default" | "destructive" +}) { + return ( + + ) +} + +function DropdownMenuCheckboxItem({ + className, + children, + checked, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean +}) { + return ( + + + + + + + {children} + + ) +} + +function DropdownMenuRadioGroup({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuRadioItem({ + className, + children, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean +}) { + return ( + + + + + + + {children} + + ) +} + +function DropdownMenuLabel({ + className, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean +}) { + return ( + + ) +} + +function DropdownMenuSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function DropdownMenuShortcut({ + className, + ...props +}: React.ComponentProps<"span">) { + return ( + + ) +} + +function DropdownMenuSub({ + ...props +}: React.ComponentProps) { + return +} + +function DropdownMenuSubTrigger({ + className, + inset, + children, + ...props +}: React.ComponentProps & { + inset?: boolean +}) { + return ( + + {children} + + + ) +} + +function DropdownMenuSubContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +export { + DropdownMenu, + DropdownMenuPortal, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuLabel, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubTrigger, + DropdownMenuSubContent, +} diff --git a/src/components/ui/input.tsx b/src/components/ui/input.tsx new file mode 100644 index 0000000..b55cf78 --- /dev/null +++ b/src/components/ui/input.tsx @@ -0,0 +1,19 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +function Input({ className, type, ...props }: React.ComponentProps<"input">) { + return ( + + ) +} + +export { Input } diff --git a/src/components/ui/select.tsx b/src/components/ui/select.tsx new file mode 100644 index 0000000..7c1573d --- /dev/null +++ b/src/components/ui/select.tsx @@ -0,0 +1,210 @@ +import * as React from "react" +import { Select as SelectPrimitive } from "radix-ui" + +import { cn } from "@/lib/utils" +import { + ChevronDownIcon, + CheckIcon, + ChevronUpIcon, + ChevronsUpDown, +} from "lucide-react" + +function Select({ + ...props +}: React.ComponentProps) { + return +} + +function SelectGroup({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SelectValue({ + ...props +}: React.ComponentProps) { + return +} + +function SelectTrigger({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + span]:line-clamp-1 dark:border-slate-800 dark:ring-offset-slate-950 dark:placeholder:text-slate-400 dark:focus:ring-slate-300", + className, + )} + {...props} + > + {children} + + + + + ) +} + +function SelectContent({ + className, + children, + position = "popper", + ...props +}: React.ComponentProps) { + return ( + + + + + {children} + + + + + ) +} + +function SelectLabel({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SelectItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ) +} + +function SelectSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function SelectScrollUpButton({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +function SelectScrollDownButton({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + ) +} + +function SelectScrollButton({ + component: Component, + className, + ...props +}: React.ComponentProps & { + component: + | typeof SelectPrimitive.ScrollUpButton + | typeof SelectPrimitive.ScrollDownButton +}) { + return ( + + ) +} + +export { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectScrollDownButton, + SelectScrollUpButton, + SelectSeparator, + SelectTrigger, + SelectValue, +} diff --git a/src/components/ui/tree-view.tsx b/src/components/ui/tree-view.tsx new file mode 100644 index 0000000..39e0d21 --- /dev/null +++ b/src/components/ui/tree-view.tsx @@ -0,0 +1,615 @@ +import * as React from "react" +import { cva } from "class-variance-authority" +import { ChevronRight } from "lucide-react" +import { Accordion as AccordionPrimitive } from "radix-ui" +import { cn } from "@/lib/utils" +import { Input } from "@/components/ui/input" + +const treeVariants = cva( + "group hover:before:opacity-100 before:absolute before:rounded-lg before:left-0 before:w-full before:opacity-0 before:bg-slate-100/70 before:h-[2rem] before:-z-10 dark:before:bg-slate-800/70", +) + +const selectedTreeVariants = cva( + "before:opacity-100 before:bg-slate-100/70 text-slate-900 dark:before:bg-slate-800/70 dark:text-slate-50", +) + +const dragOverVariants = cva( + "before:opacity-100 before:bg-slate-900/20 text-slate-50 dark:before:bg-slate-50/20 dark:text-slate-900", +) + +interface TreeDataItem { + id: string + name: React.ReactNode + icon?: any + selectedIcon?: any + openIcon?: any + children?: TreeDataItem[] + actions?: React.ReactNode + onClick?: () => void + draggable?: boolean + droppable?: boolean + isRenaming?: boolean + onRename?: (newName: string) => void + onCancelRename?: () => void + onContextMenu?: (e: React.MouseEvent) => void +} + +type TreeProps = React.HTMLAttributes & { + data: TreeDataItem[] | TreeDataItem + initialSelectedItemId?: string + onSelectChange?: (item: TreeDataItem | undefined) => void + expandAll?: boolean + defaultNodeIcon?: any + defaultLeafIcon?: any + selectedItemId: string + setSelectedItemId: (id: string | undefined) => void + onDocumentDrag?: (sourceItem: TreeDataItem, targetItem: TreeDataItem) => void +} + +const TreeView = React.forwardRef( + ( + { + data, + initialSelectedItemId, + onSelectChange, + expandAll, + defaultLeafIcon, + defaultNodeIcon, + className, + onDocumentDrag, + selectedItemId, + setSelectedItemId, + ...props + }, + ref, + ) => { + React.useEffect(() => { + setSelectedItemId(initialSelectedItemId) + }, [initialSelectedItemId]) + + const [draggedItem, setDraggedItem] = React.useState( + null, + ) + + const handleSelectChange = React.useCallback( + (item: TreeDataItem | undefined) => { + setSelectedItemId(item?.id) + if (onSelectChange) { + onSelectChange(item) + } + }, + [onSelectChange], + ) + + const handleDragStart = React.useCallback((item: TreeDataItem) => { + setDraggedItem(item) + }, []) + + const handleDrop = React.useCallback( + (targetItem: TreeDataItem) => { + if (draggedItem && onDocumentDrag && draggedItem.id !== targetItem.id) { + onDocumentDrag(draggedItem, targetItem) + } + setDraggedItem(null) + }, + [draggedItem, onDocumentDrag], + ) + + const expandedItemIds = React.useMemo(() => { + if (!initialSelectedItemId) { + return [] as string[] + } + + const ids: string[] = [] + + function walkTreeItems( + items: TreeDataItem[] | TreeDataItem, + targetId: string, + ) { + if (items instanceof Array) { + for (let i = 0; i < items.length; i++) { + ids.push(items[i]!.id) + if (walkTreeItems(items[i]!, targetId) && !expandAll) { + return true + } + if (!expandAll) ids.pop() + } + } else if (!expandAll && items.id === targetId) { + return true + } else if (items.children) { + return walkTreeItems(items.children, targetId) + } + } + + walkTreeItems(data, initialSelectedItemId) + return ids + }, [data, expandAll, initialSelectedItemId]) + + return ( +
+ +
{ + handleDrop({ id: "", name: "parent_div" }) + }} + >
+
+ ) + }, +) +TreeView.displayName = "TreeView" + +type TreeItemProps = TreeProps & { + selectedItemId?: string + handleSelectChange: (item: TreeDataItem | undefined) => void + expandedItemIds: string[] + defaultNodeIcon?: any + defaultLeafIcon?: any + handleDragStart?: (item: TreeDataItem) => void + handleDrop?: (item: TreeDataItem) => void + setSelectedItemId: (id: string | undefined) => void + draggedItem: TreeDataItem | null +} + +const TreeItem = React.forwardRef( + ( + { + className, + data, + selectedItemId, + handleSelectChange, + setSelectedItemId, + expandedItemIds, + defaultNodeIcon, + defaultLeafIcon, + handleDragStart, + handleDrop, + draggedItem, + ...props + }, + ref, + ) => { + if (!(data instanceof Array)) { + data = [data] + } + + const sortedData = [...data].sort((a, b) => { + const aIsFolder = !!a.children + const bIsFolder = !!b.children + + if (aIsFolder && !bIsFolder) return -1 + if (!aIsFolder && bIsFolder) return 1 + return 0 + }) + + return ( +
+
    + {sortedData.map((item) => ( +
  • + {item.children ? ( + + ) : ( + + )} +
  • + ))} +
+
+ ) + }, +) +TreeItem.displayName = "TreeItem" + +const TreeNode = ({ + item, + handleSelectChange, + expandedItemIds, + selectedItemId, + defaultNodeIcon, + defaultLeafIcon, + handleDragStart, + setSelectedItemId, + handleDrop, + draggedItem, +}: { + item: TreeDataItem + handleSelectChange: (item: TreeDataItem | undefined) => void + expandedItemIds: string[] + selectedItemId: string + setSelectedItemId: (id: string | undefined) => void + defaultNodeIcon?: any + defaultLeafIcon?: any + handleDragStart?: (item: TreeDataItem) => void + handleDrop?: (item: TreeDataItem) => void + draggedItem: TreeDataItem | null +}) => { + const [value, setValue] = React.useState( + expandedItemIds.includes(item.id) ? [item.id] : [], + ) + const [isDragOver, setIsDragOver] = React.useState(false) + + const onDragStart = (e: React.DragEvent) => { + if (!item.draggable) { + e.preventDefault() + return + } + e.dataTransfer.setData("text/plain", item.id) + handleDragStart?.(item) + } + + const onDragOver = (e: React.DragEvent) => { + if (item.droppable !== false && draggedItem && draggedItem.id !== item.id) { + e.preventDefault() + setIsDragOver(true) + } + } + + const onDragLeave = () => { + setIsDragOver(false) + } + + const onDrop = (e: React.DragEvent) => { + e.preventDefault() + setIsDragOver(false) + handleDrop?.(item) + } + + return ( + setValue(s)} + > + + { + handleSelectChange(item) + item.onClick?.() + }} + onContextMenu={item.onContextMenu} + draggable={!!item.draggable} + onDragStart={onDragStart} + onDragOver={onDragOver} + onDragLeave={onDragLeave} + onDrop={onDrop} + > + +
+ {item.isRenaming ? ( + { + if (e.key === "Enter") { + e.preventDefault() + const value = e.currentTarget.value.trim() + if (value && value !== item.name) { + item.onRename?.(value) + } else { + item.onCancelRename?.() + } + } else if (e.key === "Escape") { + e.preventDefault() + item.onCancelRename?.() + } + }} + spellCheck={false} + autoComplete="off" + onBlur={(e) => { + const value = e.currentTarget.value.trim() + if (value && value !== item.name) { + item.onRename?.(value) + } else { + item.onCancelRename?.() + } + }} + autoFocus + onClick={(e) => e.stopPropagation()} + className="h-6 w-full rounded-sm border border-blue-500 bg-white px-2 py-0 text-sm shadow-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500" + onFocus={(e) => { + e.currentTarget.select() + // Select filename without extension + const filename = e.currentTarget.value + const lastDotIndex = filename.lastIndexOf(".") + if (lastDotIndex > 0) { + e.currentTarget.setSelectionRange(0, lastDotIndex) + } + }} + /> + ) : ( + {item.name} + )} +
+
e.stopPropagation()} + > + {item.actions} +
+
+ + + +
+
+ ) +} + +const TreeLeaf = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes & { + item: TreeDataItem + selectedItemId?: string + handleSelectChange: (item: TreeDataItem | undefined) => void + defaultLeafIcon?: any + handleDragStart?: (item: TreeDataItem) => void + handleDrop?: (item: TreeDataItem) => void + draggedItem: TreeDataItem | null + } +>( + ( + { + className, + item, + selectedItemId, + handleSelectChange, + defaultLeafIcon, + handleDragStart, + handleDrop, + draggedItem, + ...props + }, + ref, + ) => { + const [isDragOver, setIsDragOver] = React.useState(false) + + const onDragStart = (e: React.DragEvent) => { + if (!item.draggable) { + e.preventDefault() + return + } + e.dataTransfer.setData("text/plain", item.id) + handleDragStart?.(item) + } + + const onDragOver = (e: React.DragEvent) => { + if ( + item.droppable !== false && + draggedItem && + draggedItem.id !== item.id + ) { + e.preventDefault() + setIsDragOver(true) + } + } + + const onDragLeave = () => { + setIsDragOver(false) + } + + const onDrop = (e: React.DragEvent) => { + e.preventDefault() + setIsDragOver(false) + handleDrop?.(item) + } + + return ( +
{ + handleSelectChange(item) + item.onClick?.() + }} + onContextMenu={item.onContextMenu} + draggable={!!item.draggable} + onDragStart={onDragStart} + onDragOver={onDragOver} + onDragLeave={onDragLeave} + onDrop={onDrop} + {...props} + > + +
+ {item.isRenaming ? ( + { + if (e.key === "Enter") { + e.preventDefault() + const value = e.currentTarget.value.trim() + if (value && value !== item.name) { + item.onRename?.(value) + } else { + item.onCancelRename?.() + } + } else if (e.key === "Escape") { + e.preventDefault() + item.onCancelRename?.() + } + }} + spellCheck={false} + autoComplete="off" + onBlur={(e) => { + const value = e.currentTarget.value.trim() + if (value && value !== item.name) { + item.onRename?.(value) + } else { + item.onCancelRename?.() + } + }} + autoFocus + onClick={(e) => e.stopPropagation()} + className="h-6 w-full rounded-sm border border-blue-500 bg-white px-2 py-0 text-sm shadow-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500" + onFocus={(e) => { + e.currentTarget.select() + // Select filename without extension + const filename = e.currentTarget.value + const lastDotIndex = filename.lastIndexOf(".") + if (lastDotIndex > 0) { + e.currentTarget.setSelectionRange(0, lastDotIndex) + } + }} + /> + ) : ( + {item.name} + )} +
+
e.stopPropagation()}> + {item.actions} +
+
+ ) + }, +) +TreeLeaf.displayName = "TreeLeaf" + +const AccordionTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + svg]:rotate-90", + className, + )} + {...props} + > + + {children} + + +)) +AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName + +const AccordionContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + +
{children}
+
+)) +AccordionContent.displayName = AccordionPrimitive.Content.displayName + +const TreeIcon = ({ + item, + isOpen, + isSelected, + default: defaultIcon, +}: { + item: TreeDataItem + isOpen?: boolean + isSelected?: boolean + default?: any +}) => { + let Icon = defaultIcon + if (isSelected && item.selectedIcon) { + Icon = item.selectedIcon + } else if (isOpen && item.openIcon) { + Icon = item.openIcon + } else if (item.icon) { + Icon = item.icon + } + return Icon ? : <> +} + +const TreeActions = ({ + children, + isSelected, +}: { + children: React.ReactNode + isSelected: boolean +}) => { + return ( +
+ {children} +
+ ) +} + +export { TreeView, type TreeDataItem } diff --git a/src/global.d.ts b/src/global.d.ts index d7e961e..6c64bf7 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -1 +1,6 @@ declare module "*.css" + +declare module "*?raw" { + const content: string + export default content +} diff --git a/src/index.ts b/src/index.ts index f7a0e00..568d9b8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,10 @@ export { CodeEditor, defaultCodeEditorOptions } from "./components/CodeEditor" +export { FileSidebar } from "./components/FileSidebar" export { WorkspaceCodeEditor } from "./components/WorkspaceCodeEditor" +export { TreeView, type TreeDataItem } from "./components/ui/tree-view" export type { CodeEditorProps } from "./components/CodeEditor" +export type { FileSidebarProps } from "./components/FileSidebar" export type { CreateFileProps, CreateFileResult, diff --git a/src/lib/utils.ts b/src/lib/utils.ts new file mode 100644 index 0000000..bd0c391 --- /dev/null +++ b/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/src/styles.css b/src/styles.css index f1d8c73..2f6dd0a 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1 +1,31 @@ -@import "tailwindcss"; +@import "@fontsource-variable/geist"; + +@tailwind base; +@tailwind components; +@tailwind utilities; + +:root { + --radius: 0.625rem; + --background: #ffffff; + --foreground: #0f172a; +} + +.dark { + --background: #0f172a; + --foreground: #f8fafc; +} + +@layer base { + * { + @apply border-slate-200; + } + + html { + font-family: "Geist Variable", sans-serif; + } + + body { + @apply bg-white text-slate-900; + font-family: "Geist Variable", sans-serif; + } +} diff --git a/src/utils/fileSidebarPaths.ts b/src/utils/fileSidebarPaths.ts new file mode 100644 index 0000000..242e80f --- /dev/null +++ b/src/utils/fileSidebarPaths.ts @@ -0,0 +1,48 @@ +export function getCurrentFolderPath( + selectedFolderForCreation: string | null, + selectedItemId: string, +): string { + if (selectedFolderForCreation) return selectedFolderForCreation + if (!selectedItemId) return "" + + const hasLeadingSlash = selectedItemId.startsWith("/") + const pathParts = selectedItemId.split("/") + + if (pathParts.length > 1) { + const folderPath = pathParts.slice(0, -1).join("/") + return hasLeadingSlash ? `/${folderPath}` : folderPath + } + + return hasLeadingSlash ? "/" : "" +} + +export function constructFilePath( + fileName: string, + currentFolder: string, +): string { + const trimmedFileName = fileName.trim() + + if (!trimmedFileName) return "" + + if (trimmedFileName.startsWith("/") || trimmedFileName.includes("/")) { + return trimmedFileName + } + + if (!currentFolder || currentFolder === "/") { + return currentFolder === "/" ? `/${trimmedFileName}` : trimmedFileName + } + + return `${currentFolder}/${trimmedFileName}` +} + +export function getFolderPlaceholder(currentFolder: string): string { + if (!currentFolder || currentFolder === "/") { + return "Enter file name (root folder)" + } + + const displayPath = currentFolder.startsWith("/") + ? currentFolder.slice(1) + : currentFolder + + return `Enter file name (${displayPath}/)` +} diff --git a/src/utils/isHiddenFile.ts b/src/utils/isHiddenFile.ts new file mode 100644 index 0000000..4e8301b --- /dev/null +++ b/src/utils/isHiddenFile.ts @@ -0,0 +1,59 @@ +/** + * Heuristic for files/directories that shouldn't clutter the file tree + * (lockfiles, build output, editor/config dotfiles, logs, etc.). Ported from + * tscircuit.com's ViewPackagePage so the sidebar hides the same noise. + */ +export const isHiddenFile = (filePath: string): boolean => { + if (filePath.startsWith("/")) { + filePath = filePath.slice(1) + } + + // Normalize the path to handle both Unix and Windows paths + const normalizedPath = filePath.replace(/\\/g, "/") + + // Common patterns for files to hide + const hiddenPatterns = [ + // Lock files + /package-lock\.json$/, + /yarn\.lock$/, + /pnpm-lock\.yaml$/, + /\.pnpm-store/, + /bun\.lockb/, + /bun\.lock/, + + // Generated directories + /^dist\//, + /^build\//, + /^out\//, + /^\.next\//, + /^\.nuxt\//, + /^\.output\//, + + // Config files + /\.env(\.[^/]*)?$/, + /\.eslintrc(\.[^/]*)?$/, + /\.prettierrc(\.[^/]*)?$/, + /\.babelrc$/, + /jest\.config\.[^/]*$/, + /vite\.config\.[^/]*$/, + /next\.config\.[^/]*$/, + /webpack\.config\.[^/]*$/, + /rollup\.config\.[^/]*$/, + + // Cache and temp directories + /^\.cache\//, + /^node_modules\//, + /^\.git\//, + /^\.github\//, + /^\.husky\//, + /^\.vscode\//, + /^\.idea\//, + + // Misc + /\.DS_Store$/, + /Thumbs\.db$/, + /\.log$/, + ] + + return hiddenPatterns.some((pattern) => pattern.test(normalizedPath)) +} diff --git a/src/utils/transformFilesToTreeData.tsx b/src/utils/transformFilesToTreeData.tsx new file mode 100644 index 0000000..89f8899 --- /dev/null +++ b/src/utils/transformFilesToTreeData.tsx @@ -0,0 +1,208 @@ +import { File, Folder, MoreVertical, Pencil, Trash2 } from "lucide-react" +import toast from "react-hot-toast" +import type * as React from "react" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import type { TreeDataItem } from "@/components/ui/tree-view" +import type { + DeleteFileProps, + DeleteFileResult, + RenameFileProps, + RenameFileResult, +} from "@/components/WorkspaceCodeEditor" +import { isHiddenFile } from "@/utils/isHiddenFile" + +type FileName = string +type TreeNode = Omit & { + children?: Record +} + +interface TransformFilesToTreeDataProps { + files: Record + currentFile: FileName | null + renamingFile: string | null + handleRenameFile: (props: RenameFileProps) => RenameFileResult + handleDeleteFile: (props: DeleteFileProps) => DeleteFileResult + setRenamingFile: (filename: string | null) => void + onFileSelect: (filename: FileName) => void + onFolderSelect: (folderPath: string) => void + canModifyFiles: boolean + setErrorMessage: (message: string) => void + setSelectedFolderForCreation: (folder: string | null) => void + openDropdownId: string | null + setOpenDropdownId: (id: string | null) => void +} + +export const transformFilesToTreeData = ({ + files, + currentFile, + renamingFile, + handleRenameFile, + handleDeleteFile, + setRenamingFile, + onFileSelect, + onFolderSelect, + canModifyFiles, + setErrorMessage, + setSelectedFolderForCreation, + openDropdownId, + setOpenDropdownId, +}: TransformFilesToTreeDataProps): TreeDataItem[] => { + const root: Record = {} + + Object.keys(files).forEach((filePath) => { + const hasLeadingSlash = filePath.startsWith("/") + const pathSegments = (hasLeadingSlash ? filePath.slice(1) : filePath) + .trim() + .split("/") + let currentNode: Record = root + + pathSegments.forEach((segment, segmentIndex) => { + const isLeafNode = segmentIndex === pathSegments.length - 1 + const ancestorPath = pathSegments.slice(0, segmentIndex).join("/") + const relativePath = ancestorPath ? `${ancestorPath}/${segment}` : segment + const absolutePath = hasLeadingSlash ? `/${relativePath}` : relativePath + const itemId = absolutePath + + if ( + !currentNode[segment] && + (!isHiddenFile(relativePath) || + isHiddenFile( + currentFile?.startsWith("/") + ? currentFile.slice(1) + : currentFile || "", + )) + ) { + currentNode[segment] = { + id: itemId, + name: segment, + isRenaming: renamingFile === itemId, + onRename: (newFilename: string) => { + const oldPath = itemId + const pathParts = oldPath.split("/").filter((part) => part !== "") + let newPath: string + + if (pathParts.length > 1) { + const folderPath = pathParts.slice(0, -1).join("/") + newPath = folderPath + "/" + newFilename + } else { + newPath = newFilename + } + + if (oldPath.startsWith("/") && !newPath.startsWith("/")) { + newPath = "/" + newPath + } + + const { fileRenamed } = handleRenameFile({ + oldFilename: itemId, + newFilename: newPath, + onError: (error) => { + toast.error(`Error renaming file: ${error.message}`) + }, + }) + if (fileRenamed) { + setRenamingFile(null) + } + }, + onCancelRename: () => { + setRenamingFile(null) + }, + icon: isLeafNode ? File : Folder, + onClick: isLeafNode + ? () => { + onFileSelect(absolutePath) + setSelectedFolderForCreation(null) + } + : () => onFolderSelect(absolutePath), + draggable: false, + droppable: !isLeafNode, + children: isLeafNode ? undefined : {}, + actions: canModifyFiles ? ( + { + setOpenDropdownId(open ? itemId : null) + }} + > + + + + + + { + setRenamingFile(itemId) + setOpenDropdownId(null) + }} + className="flex items-center px-3 py-1 text-xs text-black hover:bg-gray-100 cursor-pointer" + > + + Rename + + { + const { fileDeleted } = handleDeleteFile({ + filename: itemId, + onError: (error) => { + toast.error( + `Error deleting file ${itemId}: ${error.message}`, + ) + }, + }) + if (fileDeleted) { + setErrorMessage("") + } + setOpenDropdownId(null) + }} + className="flex items-center px-3 py-1 text-xs text-red-600 hover:bg-gray-100 cursor-pointer" + > + + Delete + + + + + ) : undefined, + onContextMenu: canModifyFiles + ? (e: React.MouseEvent) => { + e.preventDefault() + e.stopPropagation() + setOpenDropdownId(itemId) + } + : undefined, + } + } + + if (!isLeafNode && currentNode[segment]?.children) { + currentNode = currentNode[segment].children + } + }) + }) + + const convertToArray = (items: Record): TreeDataItem[] => { + return Object.values(items).map((item) => ({ + ...item, + children: item.children ? convertToArray(item.children) : undefined, + })) + } + return convertToArray(root).filter((x) => { + if (x.children?.length === 0) return false + return true + }) +} diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..f54ce01 --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,45 @@ +/** @type {import("tailwindcss").Config} */ +export default { + darkMode: ["class"], + content: [ + "./index.html", + "./src/**/*.{js,ts,jsx,tsx}", + "./examples/**/*.{js,ts,jsx,tsx}", + ], + theme: { + extend: { + borderRadius: { + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)", + }, + fontFamily: { + sans: ['"Geist Variable"', "sans-serif"], + heading: ['"Geist Variable"', "sans-serif"], + }, + keyframes: { + "accordion-down": { + from: { + height: "0", + }, + to: { + height: "var(--radix-accordion-content-height)", + }, + }, + "accordion-up": { + from: { + height: "var(--radix-accordion-content-height)", + }, + to: { + height: "0", + }, + }, + }, + animation: { + "accordion-down": "accordion-down 0.2s ease-out", + "accordion-up": "accordion-up 0.2s ease-out", + }, + }, + }, + plugins: [require("tailwindcss-animate")], +} diff --git a/tsconfig.json b/tsconfig.json index 5df833f..ff807b7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,6 +10,12 @@ "ignoreDeprecations": "6.0", "types": ["bun-types"], + // Path aliases + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + }, + // Bundler mode "moduleResolution": "bundler", "allowImportingTsExtensions": true, diff --git a/vite.config.ts b/vite.config.ts index f448cec..110eeed 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,9 +1,14 @@ -import tailwindcss from "@tailwindcss/vite" +import { fileURLToPath } from "node:url" import react from "@vitejs/plugin-react" import { defineConfig } from "vite" export default defineConfig({ - plugins: [react(), tailwindcss()], + plugins: [react()], + resolve: { + alias: { + "@": fileURLToPath(new URL("./src", import.meta.url)), + }, + }, optimizeDeps: { include: ["@tscircuit/runframe/runner"], },