diff --git a/bun.lock b/bun.lock index e0b3013..cea870e 100644 --- a/bun.lock +++ b/bun.lock @@ -3,7 +3,7 @@ "configVersion": 1, "workspaces": { "": { - "name": "ui", + "name": "@avocadi/ui", "dependencies": { "@tsdown/css": "^0.21.10", "clsx": "^2.1.1", @@ -13,6 +13,7 @@ "@biomejs/biome": "^2.4.13", "@bosh-code/tsdown-plugin-inject-css": "^2.0.0", "@bosh-code/tsdown-plugin-tailwindcss": "^1.0.1", + "@rollup/plugin-url": "^8.0.2", "@types/bun": "latest", "tsdown": "^0.21.10", "tw-animate-css": "^1.4.0", @@ -27,6 +28,7 @@ "radix-ui": "^1.4.3", "react": "^19.2.5", "typescript": "^6", + "use-sound": "^5.0.0", "zod": "^4.3.6", }, }, @@ -62,7 +64,7 @@ "@babel/helper-module-imports": ["@babel/helper-module-imports@7.28.6", "", { "dependencies": { "@babel/traverse": "^7.28.6", "@babel/types": "^7.28.6" } }, "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw=="], - "@babel/helper-string-parser": ["@babel/helper-string-parser@8.0.0-rc.3", "", {}, "sha512-AmwWFx1m8G/a5cXkxLxTiWl+YEoWuoFLUCwqMlNuWO1tqAYITQAbCRPUkyBHv1VOFgfjVOqEj6L3u15J5ZCzTA=="], + "@babel/helper-string-parser": ["@babel/helper-string-parser@8.0.0-rc.4", "", {}, "sha512-dluR3v287dp6YPF57kyKKrHPKffUeuxH1zQcF1WD30TeFzWXhDiVi1U6PkqaDB0++H1PeCwRhmYl4DvoerlPIw=="], "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@8.0.0-rc.3", "", {}, "sha512-8AWCJ2VJJyDFlGBep5GpaaQ9AAaE/FjAcrqI7jyssYhtL7WGV0DOKpJsQqM037xDbpRLHXsY8TwU7zDma7coOw=="], @@ -510,6 +512,10 @@ "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.17", "", {}, "sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg=="], + "@rollup/plugin-url": ["@rollup/plugin-url@8.0.2", "", { "dependencies": { "@rollup/pluginutils": "^5.0.1", "make-dir": "^3.1.0", "mime": "^3.0.0" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5yW2LP5NBEgkvIRSSEdJkmxe5cUNZKG3eenKtfJvSkxVm/xTTu7w+ayBtNwhozl1ZnTUCU0xFaRQR+cBl2H7TQ=="], + + "@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "", { "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^2.0.2", "picomatch": "^4.0.2" }, "peerDependencies": { "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "optionalPeers": ["rollup"] }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="], + "@swc/helpers": ["@swc/helpers@0.5.15", "", { "dependencies": { "tslib": "^2.8.0" } }, "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g=="], "@tailwindcss/node": ["@tailwindcss/node@4.2.4", "", { "dependencies": { "@jridgewell/remapping": "^2.3.5", "enhanced-resolve": "^5.19.0", "jiti": "^2.6.1", "lightningcss": "1.32.0", "magic-string": "^0.30.21", "source-map-js": "^1.2.1", "tailwindcss": "4.2.4" } }, "sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA=="], @@ -588,7 +594,7 @@ "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], - "@unom/style": ["@unom/style@0.4.0", "https://git.unom.io/api/packages/unom/npm/%40unom%2Fstyle/-/0.4.0/style-0.4.0.tgz", {}, "sha512-dYLTnBs+hJyXMHrHv/20Q7SVO5FZuCHSD3ksqWACpY1Ywnitw7WXdj6b8MoBdiPLoC27tp2KELNCgOUU9NRUgA=="], + "@unom/style": ["@unom/style@0.4.4", "https://git.unom.io/api/packages/unom/npm/%40unom%2Fstyle/-/0.4.4/style-0.4.4.tgz", { "peerDependencies": { "motion": "^12" } }, "sha512-M45nihK+LGyxwy2mmHYRKggaocTt+EKNVFNaMpTvTaIUpozi7bmKIkbM2/enMYS0/UYTaZrBSZs/a0nPXqkAKw=="], "acorn": ["acorn@8.16.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw=="], @@ -608,7 +614,7 @@ "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=="], - "baseline-browser-mapping": ["baseline-browser-mapping@2.10.23", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-xwVXGqevyKPsiuQdLj+dZMVjidjJV508TBqexND5HrF89cGdCYCJFB3qhcxRHSeMctdCfbR1jrxBajhDy7o29g=="], + "baseline-browser-mapping": ["baseline-browser-mapping@2.10.24", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-I2NkZOOrj2XuguvWCK6OVh9GavsNjZjK908Rq3mIBK25+GD8vPX5w2WdxVqnQ7xx3SrZJiCiZFu+/Oz50oSYSA=="], "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], @@ -726,7 +732,7 @@ "estree-util-visit": ["estree-util-visit@2.0.0", "", { "dependencies": { "@types/estree-jsx": "^1.0.0", "@types/unist": "^3.0.0" } }, "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww=="], - "estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], + "estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], "fast-copy": ["fast-copy@3.0.2", "", {}, "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ=="], @@ -778,6 +784,8 @@ "hookable": ["hookable@6.1.1", "", {}, "sha512-U9LYDy1CwhMCnprUfeAZWZGByVbhd54hwepegYTK7Pi5NvqEj63ifz5z+xukznehT7i6NIZRu89Ay1AZmRsLEQ=="], + "howler": ["howler@2.2.4", "", {}, "sha512-iARIBPgcQrwtEr+tALF+rapJ8qSc+Set2GJQl7xT1MQzWaVkFebdJhR3alVlSiUf5U7nAANKuj3aWpwerocD5w=="], + "http-status": ["http-status@2.1.0", "", {}, "sha512-O5kPr7AW7wYd/BBiOezTwnVAnmSNFY+J7hlZD2X5IOxVBetjcHAiTXhzj0gMrnojQlwy+UT1/Y3H3vJ3UlmvLA=="], "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], @@ -874,10 +882,12 @@ "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], - "lucide-react": ["lucide-react@1.11.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-UOhjdztXCgdBReRcIhsvz2siIBogfv/lhJEIViCpLt924dO+GDms9T7DNoucI23s6kEPpe988m5N0D2ajnzb2g=="], + "lucide-react": ["lucide-react@1.14.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-+1mdWcfSJVUsaTIjN9zoezmUhfXo5l0vP7ekBMPo3jcS/aIkxHnXqAPsByszMZx/Y8oQBRJxJx5xg+RH3urzxA=="], "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + "make-dir": ["make-dir@3.1.0", "", { "dependencies": { "semver": "^6.0.0" } }, "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw=="], + "marked": ["marked@14.0.0", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ=="], "md5": ["md5@2.3.0", "", { "dependencies": { "charenc": "0.0.2", "crypt": "0.0.2", "is-buffer": "~1.1.6" } }, "sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g=="], @@ -942,6 +952,8 @@ "micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="], + "mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="], + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], "monaco-editor": ["monaco-editor@0.55.1", "", { "dependencies": { "dompurify": "3.2.7", "marked": "14.0.0" } }, "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A=="], @@ -954,7 +966,7 @@ "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - "nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + "nanoid": ["nanoid@3.3.12", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ=="], "next": ["next@16.2.4", "", { "dependencies": { "@next/env": "16.2.4", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", "postcss": "8.4.31", "styled-jsx": "5.1.6" }, "optionalDependencies": { "@next/swc-darwin-arm64": "16.2.4", "@next/swc-darwin-x64": "16.2.4", "@next/swc-linux-arm64-gnu": "16.2.4", "@next/swc-linux-arm64-musl": "16.2.4", "@next/swc-linux-x64-gnu": "16.2.4", "@next/swc-linux-x64-musl": "16.2.4", "@next/swc-win32-arm64-msvc": "16.2.4", "@next/swc-win32-x64-msvc": "16.2.4", "sharp": "^0.34.5" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", "@playwright/test": "^1.51.1", "babel-plugin-react-compiler": "*", "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", "sass": "^1.3.0" }, "optionalPeers": ["@opentelemetry/api", "@playwright/test", "babel-plugin-react-compiler", "sass"], "bin": { "next": "dist/bin/next" } }, "sha512-kPvz56wF5frc+FxlHI5qnklCzbq53HTwORaWBGdT0vNoKh1Aya9XC8aPauH4NJxqtzbWsS5mAbctm4cr+EkQ2Q=="], @@ -1114,7 +1126,7 @@ "thread-stream": ["thread-stream@3.1.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A=="], - "tinyexec": ["tinyexec@1.1.1", "", {}, "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg=="], + "tinyexec": ["tinyexec@1.1.2", "", {}, "sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA=="], "tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="], @@ -1136,7 +1148,7 @@ "tw-animate-css": ["tw-animate-css@1.4.0", "", {}, "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ=="], - "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + "typescript": ["typescript@6.0.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw=="], "uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="], @@ -1166,6 +1178,8 @@ "use-sidecar": ["use-sidecar@1.1.3", "", { "dependencies": { "detect-node-es": "^1.1.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ=="], + "use-sound": ["use-sound@5.0.0", "", { "dependencies": { "howler": "^2.2.4" }, "peerDependencies": { "react": ">=16.8" } }, "sha512-MNHT3FFC5HxNCrgZtrnpIMJI2cw/0D2xismcrtyht8BTuF5FhFhb57xO/jlQr2xJaFrc/0btzRQvGyHQwB7PVA=="], + "use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="], "utf8-byte-length": ["utf8-byte-length@1.0.5", "", {}, "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA=="], @@ -1186,7 +1200,7 @@ "yjs": ["yjs@13.6.30", "", { "dependencies": { "lib0": "^0.2.99" } }, "sha512-vv/9h42eCMC81ZHDFswuu/MKzkl/vyq1BhaNGfHyOonwlG4CJbQF4oiBBJPvfdeCt/PlVDWh7Nov9D34YY09uQ=="], - "zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="], + "zod": ["zod@4.4.1", "", {}, "sha512-a6ENMBBGZBsnlSebQ/eKCguSBeGKSf4O7BPnqVPmYGtpBYI7VSqoVqw+QcB7kPRjbqPwhYTpFbVj/RqNz/CT0Q=="], "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], @@ -1194,13 +1208,13 @@ "@babel/helper-module-imports/@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], - "@babel/template/@babel/parser": ["@babel/parser@7.29.2", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA=="], + "@babel/template/@babel/parser": ["@babel/parser@7.29.3", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA=="], "@babel/template/@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], "@babel/traverse/@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="], - "@babel/traverse/@babel/parser": ["@babel/parser@7.29.2", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA=="], + "@babel/traverse/@babel/parser": ["@babel/parser@7.29.3", "", { "dependencies": { "@babel/types": "^7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-b3ctpQwp+PROvU/cttc4OYl4MzfJUWy6FZg+PMXfzmt/+39iHVF0sDfqay8TQM3JA2EUOyKcFZt75jWriQijsA=="], "@babel/traverse/@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], @@ -1224,6 +1238,12 @@ "anymatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], + "ast-kit/estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="], + + "dom-helpers/csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], + + "make-dir/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "next/@next/env": ["@next/env@16.2.4", "", {}, "sha512-dKkkOzOSwFYe5RX6y26fZgkSpVAlIOJKQHIiydQcrWH6y/97+RceSOAdjZ14Qa3zLduVUy0TXcn+EiM6t4rPgw=="], "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], diff --git a/package.json b/package.json index 42299aa..a3a7091 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@avocadi/ui", "type": "module", - "version": "0.2.2", + "version": "0.2.4", "private": false, "files": [ "dist" @@ -13,6 +13,7 @@ "@biomejs/biome": "^2.4.13", "@bosh-code/tsdown-plugin-inject-css": "^2.0.0", "@bosh-code/tsdown-plugin-tailwindcss": "^1.0.1", + "@rollup/plugin-url": "^8.0.2", "@types/bun": "latest", "tsdown": "^0.21.10", "tw-animate-css": "^1.4.0" @@ -27,6 +28,7 @@ "radix-ui": "^1.4.3", "react": "^19.2.5", "typescript": "^6", + "use-sound": "^5.0.0", "zod": "^4.3.6" }, "exports": { diff --git a/src/assets/sounds/762132__ienba__ui-buttons.wav b/src/assets/sounds/762132__ienba__ui-buttons.wav new file mode 100644 index 0000000..36e13f7 Binary files /dev/null and b/src/assets/sounds/762132__ienba__ui-buttons.wav differ diff --git a/src/assets/sounds/842498__newlocknew__uimvmt_game-user-interface-sound-set.mp3 b/src/assets/sounds/842498__newlocknew__uimvmt_game-user-interface-sound-set.mp3 new file mode 100644 index 0000000..0c4efd4 Binary files /dev/null and b/src/assets/sounds/842498__newlocknew__uimvmt_game-user-interface-sound-set.mp3 differ diff --git a/src/button.tsx b/src/button.tsx index 77d29c5..1c41663 100644 --- a/src/button.tsx +++ b/src/button.tsx @@ -1,7 +1,8 @@ import { Slot } from "@radix-ui/react-slot"; import { cva, type VariantProps } from "class-variance-authority"; -import { motion } from "motion/react"; +import { type MotionProps, motion } from "motion/react"; import type * as React from "react"; +import type { ComponentProps, FC } from "react"; import { cn } from "@/lib/utils"; const buttonVariants = cva( @@ -59,6 +60,32 @@ function Button({ ); } -const AnimatedButton = motion.create(Button); +const MButton = motion.create(Button); -export { Button, buttonVariants, AnimatedButton }; +const AnimatedButton: FC & MotionProps> = ({ + ...props +}) => { + return ( + + ); +}; + +export { AnimatedButton, Button, buttonVariants }; diff --git a/src/form/checkbox.tsx b/src/form/checkbox.tsx new file mode 100644 index 0000000..11f23f9 --- /dev/null +++ b/src/form/checkbox.tsx @@ -0,0 +1,38 @@ +"use client"; + +import { CheckIcon } from "lucide-react"; +import { Checkbox as CheckboxPrimitive } from "radix-ui"; +import type * as React from "react"; +import useInterfaceSound from "@/hooks/useInterfaceSound"; +import { cn } from "@/lib/utils"; + +function Checkbox({ + className, + onCheckedChange, + ...props +}: React.ComponentProps) { + const { play } = useInterfaceSound(); + return ( + { + if (onCheckedChange) onCheckedChange(checked); + play({ id: "click2" }); + }} + data-slot="checkbox" + className={cn( + "peer relative flex size-4 shrink-0 items-center justify-center rounded-sm border border-input transition-colors outline-none group-has-disabled/field:opacity-50 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 aria-invalid:aria-checked:border-primary dark:bg-input/30 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 data-checked:border-primary data-checked:bg-primary data-checked:text-primary-foreground dark:data-checked:bg-primary", + className, + )} + {...props} + > + + + + + ); +} + +export { Checkbox }; diff --git a/src/form/field-container.tsx b/src/form/field-container.tsx new file mode 100644 index 0000000..692fbb4 --- /dev/null +++ b/src/form/field-container.tsx @@ -0,0 +1,27 @@ +import { ease } from "@unom/style"; +import { motion } from "motion/react"; +import type { ReactNode } from "react"; + +const animation = { + container: { + variants: { + enter: { + opacity: 1, + y: 0, + }, + from: { + opacity: 0, + y: -20, + }, + }, + transition: ease.quint(0.9).out, + }, +}; + +export const FieldContainer = ({ children }: { children: ReactNode }) => { + return ( + + {children} + + ); +}; diff --git a/src/form/form.tsx b/src/form/form.tsx new file mode 100644 index 0000000..bfb8d14 --- /dev/null +++ b/src/form/form.tsx @@ -0,0 +1,31 @@ +import { cva } from "class-variance-authority"; +import { motion } from "motion/react"; +import type { ReactNode } from "react"; +import { cn } from "@/lib/utils.ts"; +import { defaultAnimationStagger } from "@/styles/animations"; + +export const formVariants = cva(cn("py-2 gap-2 max-w-max-form flex flex-col")); + +export const Form = ({ + children, + id, + onSubmit, +}: { + children: ReactNode; + id?: string; + onSubmit?: () => void; +}) => { + return ( + { + e.preventDefault(); + onSubmit?.(); + }} + {...defaultAnimationStagger} + className={formVariants()} + > + {children} + + ); +}; diff --git a/src/form/input-number.tsx b/src/form/input-number.tsx new file mode 100644 index 0000000..3ac1ca8 --- /dev/null +++ b/src/form/input-number.tsx @@ -0,0 +1,77 @@ +import * as React from "react"; +import useInterfaceSound from "@/hooks/useInterfaceSound"; +import { InputText } from "./input-text"; + +type Props = Omit< + React.ComponentProps<"input">, + "value" | "onChange" | "type" +> & { + value: number; + onChange: (value: number) => void; + min?: number; + max?: number; + step?: number | string; +}; + +const InputNumber = React.forwardRef( + ({ value, onChange, min, max, onBlur, onFocus, ...rest }, ref) => { + const [draft, setDraft] = React.useState(String(value)); + const [focused, setFocused] = React.useState(false); + + React.useEffect(() => { + if (!focused && String(value) !== draft) { + setDraft(String(value)); + } + }, [value, focused, draft]); + + const commit = (raw: string) => { + if (raw === "" || raw === "-") return; + const parsed = Number(raw); + if (!Number.isFinite(parsed)) return; + if (min !== undefined && parsed < min) return; + if (max !== undefined && parsed > max) return; + if (parsed !== value) onChange(parsed); + }; + + const { play } = useInterfaceSound(); + + return ( + { + setFocused(true); + play({ id: "click2" }); + onFocus?.(e); + }} + onChange={(e) => { + const next = e.target.value; + setDraft(next); + commit(next); + }} + onBlur={(e) => { + setFocused(false); + const parsed = Number(draft); + if (draft === "" || !Number.isFinite(parsed)) { + setDraft(String(value)); + } else { + let clamped = parsed; + if (min !== undefined && clamped < min) clamped = min; + if (max !== undefined && clamped > max) clamped = max; + setDraft(String(clamped)); + if (clamped !== value) onChange(clamped); + } + onBlur?.(e); + }} + {...rest} + /> + ); + }, +); +InputNumber.displayName = "InputNumber"; + +export { InputNumber }; diff --git a/src/form/input-text.tsx b/src/form/input-text.tsx new file mode 100644 index 0000000..8fab3fe --- /dev/null +++ b/src/form/input-text.tsx @@ -0,0 +1,28 @@ +import * as React from "react"; +import useInterfaceSound from "@/hooks/useInterfaceSound"; +import { cn } from "@/lib/utils"; + +const InputText = React.forwardRef< + HTMLInputElement, + React.ComponentProps<"input"> +>(({ className, type, ...props }, ref) => { + const { play } = useInterfaceSound(); + + return ( + { + play({ id: "click2" }); + }} + type={type} + className={cn( + "flex h-input-height w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm", + className, + )} + ref={ref} + {...props} + /> + ); +}); +InputText.displayName = "InputText"; + +export { InputText }; diff --git a/src/form/label.tsx b/src/form/label.tsx new file mode 100644 index 0000000..b6ebd26 --- /dev/null +++ b/src/form/label.tsx @@ -0,0 +1,26 @@ +"use client"; + +import { cva, type VariantProps } from "class-variance-authority"; +import { Label as LabelPrimitive } from "radix-ui"; +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +const labelVariants = cva( + "text-sm font-medium text-main leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70", +); + +const Label = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, ...props }, ref) => ( + +)); +Label.displayName = LabelPrimitive.Root.displayName; + +export { Label }; diff --git a/src/form/select.tsx b/src/form/select.tsx new file mode 100644 index 0000000..d8cd8ea --- /dev/null +++ b/src/form/select.tsx @@ -0,0 +1,221 @@ +"use client"; + +import { CheckIcon, ChevronDownIcon, ChevronUpIcon } from "lucide-react"; +import { Select as SelectPrimitive } from "radix-ui"; +import type * as React from "react"; +import useInterfaceSound from "@/hooks/useInterfaceSound"; +import { cn } from "@/lib/utils"; + +function Select({ + ...props +}: React.ComponentProps) { + const { play } = useInterfaceSound(); + + return ( + { + if (open) { + play({ id: "click3" }); + } else { + play({ id: "click4" }); + } + }} + data-slot="select" + {...props} + /> + ); +} + +function SelectGroup({ + ...props +}: React.ComponentProps) { + return ; +} + +function SelectValue({ + ...props +}: React.ComponentProps) { + return ; +} + +function SelectTrigger({ + className, + size = "default", + children, + ...props +}: React.ComponentProps & { + size?: "sm" | "default"; +}) { + return ( + + {children} + + + + + ); +} + +function SelectContent({ + className, + children, + position = "item-aligned", + align = "center", + ...props +}: React.ComponentProps) { + return ( + + + + + {children} + + + + + ); +} + +function SelectLabel({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function SelectItem({ + className, + children, + ...props +}: React.ComponentProps) { + const { play } = useInterfaceSound(); + + return ( + play({ id: "click2" })} + data-slot="select-item" + className={cn( + "focus:bg-main/25 text-main/75 focus:text-main [&_svg:not([class*='text-'])]:text-main transition-colors", + "relative flex w-full cursor-default items-center gap-2 rounded-sm py-1.5 pr-8 pl-3", + "text-sm outline-hidden select-none data-disabled:pointer-events-none data-disabled:opacity-50", + "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 *:[span]:last:flex", + "*:[span]:last:items-center *:[span]:last:gap-2", + className, + )} + {...props} + > + + + + + + {children} + + ); +} + +function SelectSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function SelectScrollUpButton({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + ); +} + +function SelectScrollDownButton({ + className, + ...props +}: React.ComponentProps) { + return ( + + + + ); +} + +export { + Select, + SelectContent, + SelectGroup, + SelectItem, + SelectLabel, + SelectScrollDownButton, + SelectScrollUpButton, + SelectSeparator, + SelectTrigger, + SelectValue, +}; diff --git a/src/global.d.ts b/src/global.d.ts new file mode 100644 index 0000000..1b94865 --- /dev/null +++ b/src/global.d.ts @@ -0,0 +1,2 @@ +declare module "*.mp3"; +declare module "*.wav"; diff --git a/src/hooks/useInterfaceSound.ts b/src/hooks/useInterfaceSound.ts new file mode 100644 index 0000000..7deb796 --- /dev/null +++ b/src/hooks/useInterfaceSound.ts @@ -0,0 +1,43 @@ +import { useSound } from "use-sound"; +import z from "zod"; +import soundSpriteButtons from "@/assets/sounds/762132__ienba__ui-buttons.wav"; +import soundSprite from "@/assets/sounds/842498__newlocknew__uimvmt_game-user-interface-sound-set.mp3"; + +const UiSoundSetSprites = z.enum([ + "smooth1", + "smooth2", + "lobbyCreated", + "gameStart", +]); + +const UiButtonSprites = z.enum(["click1", "click2", "click3", "click4"]); + +export default function useInterfaceSound() { + const [playSprite1] = useSound(soundSprite, { + sprite: { + smooth1: [0, 1200], + smooth2: [7800, 1400], + lobbyCreated: [53800, 3500], + gameStart: [62000, 4000], + }, + }); + + const [playSprite2] = useSound(soundSpriteButtons, { + sprite: { + click1: [0, 1000], + click2: [2750, 1000], + click3: [5200, 1000], + click4: [7700, 1000], + }, + }); + + const play = ({ id }: { id: string }) => { + if (UiSoundSetSprites.safeParse(id).success) { + playSprite1({ id }); + } else if (UiButtonSprites.safeParse(id).success) { + playSprite2({ id }); + } + }; + + return { play }; +} diff --git a/src/styles/animations.ts b/src/styles/animations.ts new file mode 100644 index 0000000..72aefb4 --- /dev/null +++ b/src/styles/animations.ts @@ -0,0 +1,23 @@ +import type { Transition, Variants } from "motion"; + +export const defaultTransitionCard: Transition = { + type: "spring", + stiffness: 200, + damping: 10, + mass: 1, +}; + +export const defaultAnimationStagger = { + variants: { + enter: {}, + from: {}, + }, + transition: { + staggerChildren: 0.1, + }, +}; + +export const defaultVariantsCard: Variants = { + enter: { y: 0, opacity: 1 }, + from: { opacity: 0, y: 30 }, +}; diff --git a/tsconfig.json b/tsconfig.json index 07acd97..b8caf87 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,33 +1,33 @@ { - "compilerOptions": { - // Environment setup & latest features - "lib": ["ESNext"], - "target": "ESNext", - "module": "Preserve", - "moduleDetection": "force", - "jsx": "react-jsx", - "allowJs": true, - "types": ["bun"], + "compilerOptions": { + // Environment setup & latest features + "lib": ["ESNext", "DOM"], + "target": "ESNext", + "module": "Preserve", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + "types": ["bun"], - // Bundler mode - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "noEmit": true, + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, - // Best practices - "strict": true, - "skipLibCheck": true, - "noFallthroughCasesInSwitch": true, - "noUncheckedIndexedAccess": true, - "noImplicitOverride": true, + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, - // Some stricter flags (disabled by default) - "noUnusedLocals": false, - "noUnusedParameters": false, - "noPropertyAccessFromIndexSignature": false, - "paths": { - "@/*": ["./src/*"] - } - } + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false, + "paths": { + "@/*": ["./src/*"] + } + } } diff --git a/tsdown.config.ts b/tsdown.config.ts index e95e57a..ce7ca74 100644 --- a/tsdown.config.ts +++ b/tsdown.config.ts @@ -1,3 +1,4 @@ +import url from "@rollup/plugin-url"; import { defineConfig } from "tsdown"; export default defineConfig({ @@ -12,5 +13,10 @@ export default defineConfig({ ], platform: "browser", dts: true, - plugins: [], + plugins: [ + url({ + include: ["**/*.mp3", "**/*.wav"], + limit: 8192, + }), + ], });