diff --git a/bun.lock b/bun.lock index 7dff8dfe..dc2f7923 100644 --- a/bun.lock +++ b/bun.lock @@ -6,25 +6,25 @@ "name": "openchamber-monorepo", "dependencies": { "@base-ui/react": "^1.4.0", - "@codemirror/autocomplete": "^6.20.0", - "@codemirror/commands": "^6.10.1", + "@codemirror/autocomplete": "^6.20.3", + "@codemirror/commands": "^6.11.0", "@codemirror/lang-cpp": "^6.0.3", "@codemirror/lang-css": "^6.3.1", "@codemirror/lang-go": "^6.0.1", - "@codemirror/lang-html": "^6.4.11", - "@codemirror/lang-javascript": "^6.2.4", + "@codemirror/lang-html": "^6.4.12", + "@codemirror/lang-javascript": "^6.2.5", "@codemirror/lang-json": "^6.0.2", - "@codemirror/lang-markdown": "^6.5.0", + "@codemirror/lang-markdown": "^6.5.2", "@codemirror/lang-python": "^6.2.1", "@codemirror/lang-rust": "^6.0.2", "@codemirror/lang-sql": "^6.10.0", "@codemirror/lang-xml": "^6.1.0", - "@codemirror/lang-yaml": "^6.1.2", - "@codemirror/language": "6.12.2", - "@codemirror/lint": "^6.9.2", - "@codemirror/search": "^6.6.0", - "@codemirror/state": "^6.5.4", - "@codemirror/view": "6.39.13", + "@codemirror/lang-yaml": "^6.1.3", + "@codemirror/language": "6.12.4", + "@codemirror/lint": "^6.9.7", + "@codemirror/search": "^6.7.1", + "@codemirror/state": "^6.7.1", + "@codemirror/view": "6.43.9", "@heroui/scroll-shadow": "^2.3.18", "@heroui/system": "^2.4.23", "@heroui/theme": "^2.4.23", @@ -143,34 +143,34 @@ "@capacitor/keyboard": "^8.0.0", "@capacitor/push-notifications": "^8.1.1", "@capacitor/status-bar": "^8.0.0", - "@codemirror/autocomplete": "^6.20.0", - "@codemirror/commands": "^6.10.1", + "@codemirror/autocomplete": "^6.20.3", + "@codemirror/commands": "^6.11.0", "@codemirror/lang-cpp": "^6.0.3", "@codemirror/lang-css": "^6.3.1", "@codemirror/lang-go": "^6.0.1", - "@codemirror/lang-html": "^6.4.11", - "@codemirror/lang-javascript": "^6.2.4", + "@codemirror/lang-html": "^6.4.12", + "@codemirror/lang-javascript": "^6.2.5", "@codemirror/lang-json": "^6.0.2", - "@codemirror/lang-markdown": "^6.5.0", + "@codemirror/lang-markdown": "^6.5.2", "@codemirror/lang-python": "^6.2.1", "@codemirror/lang-rust": "^6.0.2", "@codemirror/lang-sql": "^6.10.0", "@codemirror/lang-xml": "^6.1.0", - "@codemirror/lang-yaml": "^6.1.2", - "@codemirror/language": "6.12.2", + "@codemirror/lang-yaml": "^6.1.3", + "@codemirror/language": "6.12.4", "@codemirror/language-data": "^6.5.2", - "@codemirror/legacy-modes": "^6.5.2", - "@codemirror/lint": "^6.9.2", - "@codemirror/search": "^6.6.0", - "@codemirror/state": "^6.5.4", - "@codemirror/view": "6.39.13", + "@codemirror/legacy-modes": "^6.5.3", + "@codemirror/lint": "^6.9.7", + "@codemirror/search": "^6.7.1", + "@codemirror/state": "^6.7.1", + "@codemirror/view": "6.43.9", "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", "@lezer/highlight": "^1.2.3", "@opencode-ai/sdk": "1.18.18", "@pierre/diffs": "1.3.0-beta.6", - "@replit/codemirror-vim": "^6.3.0", + "@replit/codemirror-vim": "^6.4.0", "@simplewebauthn/browser": "13.3.0", "@tanstack/react-virtual": "3.14.5", "@xenova/transformers": "^2.17.2", @@ -355,8 +355,18 @@ "bun-pty@0.4.8": "bun-patches/bun-pty@0.4.8.patch", }, "overrides": { - "@codemirror/language": "6.12.2", - "@codemirror/view": "6.39.13", + "@codemirror/autocomplete": "6.20.3", + "@codemirror/commands": "6.11.0", + "@codemirror/lang-html": "6.4.12", + "@codemirror/lang-javascript": "6.2.5", + "@codemirror/lang-markdown": "6.5.2", + "@codemirror/lang-yaml": "6.1.3", + "@codemirror/language": "6.12.4", + "@codemirror/legacy-modes": "6.5.3", + "@codemirror/lint": "6.9.7", + "@codemirror/search": "6.7.1", + "@codemirror/state": "6.7.1", + "@codemirror/view": "6.43.9", }, "packages": { "7zip-bin": ["7zip-bin@5.2.0", "", {}, "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A=="], @@ -603,9 +613,9 @@ "@clack/prompts": ["@clack/prompts@1.1.0", "", { "dependencies": { "@clack/core": "1.1.0", "sisteransi": "^1.0.5" } }, "sha512-pkqbPGtohJAvm4Dphs2M8xE29ggupihHdy1x84HNojZuMtFsHiUlRvqD24tM2+XmI+61LlfNceM3Wr7U5QES5g=="], - "@codemirror/autocomplete": ["@codemirror/autocomplete@6.20.0", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0" } }, "sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg=="], + "@codemirror/autocomplete": ["@codemirror/autocomplete@6.20.3", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0" } }, "sha512-tlosUqb+3BbxCxZdu4tKeRghPFC+QM7q4X5YhKV2eCmPG+1r2F3f4AaSz5sCrFqUtX4Jh20VFTKecl16MgiV9g=="], - "@codemirror/commands": ["@codemirror/commands@6.10.2", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.4.0", "@codemirror/view": "^6.27.0", "@lezer/common": "^1.1.0" } }, "sha512-vvX1fsih9HledO1c9zdotZYUZnE4xV0m6i3m25s5DIfXofuprk6cRcLUZvSk3CASUbwjQX21tOGbkY2BH8TpnQ=="], + "@codemirror/commands": ["@codemirror/commands@6.11.0", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.7.0", "@codemirror/view": "^6.27.0", "@lezer/common": "^1.1.0" } }, "sha512-/K4Rl5BN0OtTiPWmJCdqODu38XnDMsDxKY5rgrPnCkutPTJf2wVbkoixLfealF5Kwse/s8P8M5jAiURiwSwnFA=="], "@codemirror/lang-angular": ["@codemirror/lang-angular@0.1.4", "", { "dependencies": { "@codemirror/lang-html": "^6.0.0", "@codemirror/lang-javascript": "^6.1.2", "@codemirror/language": "^6.0.0", "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.3.3" } }, "sha512-oap+gsltb/fzdlTQWD6BFF4bSLKcDnlxDsLdePiJpCVNKWXSTAbiiQeYI3UmES+BLAdkmIC1WjyztC1pi/bX4g=="], @@ -615,11 +625,11 @@ "@codemirror/lang-go": ["@codemirror/lang-go@6.0.1", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/language": "^6.6.0", "@codemirror/state": "^6.0.0", "@lezer/common": "^1.0.0", "@lezer/go": "^1.0.0" } }, "sha512-7fNvbyNylvqCphW9HD6WFnRpcDjr+KXX/FgqXy5H5ZS0eC5edDljukm/yNgYkwTsgp2busdod50AOTIy6Jikfg=="], - "@codemirror/lang-html": ["@codemirror/lang-html@6.4.11", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/lang-css": "^6.0.0", "@codemirror/lang-javascript": "^6.0.0", "@codemirror/language": "^6.4.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0", "@lezer/css": "^1.1.0", "@lezer/html": "^1.3.12" } }, "sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw=="], + "@codemirror/lang-html": ["@codemirror/lang-html@6.4.12", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/lang-css": "^6.0.0", "@codemirror/lang-javascript": "^6.0.0", "@codemirror/language": "^6.4.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0", "@lezer/css": "^1.1.0", "@lezer/html": "^1.3.12" } }, "sha512-pw2ReWKUqSkbvh76RAT4NYxiogRu+PWkR2ukAwO9uOgrm8uipkzjtKKtNpyeAQwHOqxEeSvAXZ6vr3AfyB9y/w=="], "@codemirror/lang-java": ["@codemirror/lang-java@6.0.2", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@lezer/java": "^1.0.0" } }, "sha512-m5Nt1mQ/cznJY7tMfQTJchmrjdjQ71IDs+55d1GAa8DGaB8JXWsVCkVT284C3RTASaY43YknrK2X3hPO/J3MOQ=="], - "@codemirror/lang-javascript": ["@codemirror/lang-javascript@6.2.4", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/language": "^6.6.0", "@codemirror/lint": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0", "@lezer/javascript": "^1.0.0" } }, "sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA=="], + "@codemirror/lang-javascript": ["@codemirror/lang-javascript@6.2.5", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/language": "^6.6.0", "@codemirror/lint": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0", "@lezer/javascript": "^1.0.0" } }, "sha512-zD4e5mS+50htS7F+TYjBPsiIFGanfVqg4HyUz6WNFikgOPf2BgKlx+TQedI1w6n/IqRBVBbBWmGFdLB/7uxO4A=="], "@codemirror/lang-jinja": ["@codemirror/lang-jinja@6.0.0", "", { "dependencies": { "@codemirror/lang-html": "^6.0.0", "@codemirror/language": "^6.0.0", "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.2.0", "@lezer/lr": "^1.4.0" } }, "sha512-47MFmRcR8UAxd8DReVgj7WJN1WSAMT7OJnewwugZM4XiHWkOjgJQqvEM1NpMj9ALMPyxmlziEI1opH9IaEvmaw=="], @@ -629,7 +639,7 @@ "@codemirror/lang-liquid": ["@codemirror/lang-liquid@6.3.2", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/lang-html": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", "@lezer/common": "^1.0.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.3.1" } }, "sha512-6PDVU3ZnfeYyz1at1E/ttorErZvZFXXt1OPhtfe1EZJ2V2iDFa0CwPqPgG5F7NXN0yONGoBogKmFAafKTqlwIw=="], - "@codemirror/lang-markdown": ["@codemirror/lang-markdown@6.5.0", "", { "dependencies": { "@codemirror/autocomplete": "^6.7.1", "@codemirror/lang-html": "^6.0.0", "@codemirror/language": "^6.3.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", "@lezer/common": "^1.2.1", "@lezer/markdown": "^1.0.0" } }, "sha512-0K40bZ35jpHya6FriukbgaleaqzBLZfOh7HuzqbMxBXkbYMJDxfF39c23xOgxFezR+3G+tR2/Mup+Xk865OMvw=="], + "@codemirror/lang-markdown": ["@codemirror/lang-markdown@6.5.2", "", { "dependencies": { "@codemirror/autocomplete": "^6.7.1", "@codemirror/lang-html": "^6.0.0", "@codemirror/language": "^6.3.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", "@lezer/common": "^1.2.1", "@lezer/markdown": "^1.0.0" } }, "sha512-AwBOdkWYuA//WcM0xO5PfHPUcmz/O2i5o0Nsg1U69SII/loCJlFI1Romd9xp2HYb1kYJRGZotyqRghuHH5n8Kw=="], "@codemirror/lang-php": ["@codemirror/lang-php@6.0.2", "", { "dependencies": { "@codemirror/lang-html": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@lezer/common": "^1.0.0", "@lezer/php": "^1.0.0" } }, "sha512-ZKy2v1n8Fc8oEXj0Th0PUMXzQJ0AIR6TaZU+PbDHExFwdu+guzOA4jmCHS1Nz4vbFezwD7LyBdDnddSJeScMCA=="], @@ -647,21 +657,21 @@ "@codemirror/lang-xml": ["@codemirror/lang-xml@6.1.0", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/language": "^6.4.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0", "@lezer/common": "^1.0.0", "@lezer/xml": "^1.0.0" } }, "sha512-3z0blhicHLfwi2UgkZYRPioSgVTo9PV5GP5ducFH6FaHy0IAJRg+ixj5gTR1gnT/glAIC8xv4w2VL1LoZfs+Jg=="], - "@codemirror/lang-yaml": ["@codemirror/lang-yaml@6.1.2", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.2.0", "@lezer/lr": "^1.0.0", "@lezer/yaml": "^1.0.0" } }, "sha512-dxrfG8w5Ce/QbT7YID7mWZFKhdhsaTNOYjOkSIMt1qmC4VQnXSDSYVHHHn8k6kJUfIhtLo8t1JJgltlxWdsITw=="], + "@codemirror/lang-yaml": ["@codemirror/lang-yaml@6.1.3", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@lezer/common": "^1.2.0", "@lezer/highlight": "^1.2.0", "@lezer/lr": "^1.0.0", "@lezer/yaml": "^1.0.0" } }, "sha512-AZ8DJBuXGVHybpBQhmZtgew5//4hv3tdkXnr3vDmOUMJRuB6vn/uuwtmTOTlqEaQFg3hQSVeA90NmvIQyUV6FQ=="], - "@codemirror/language": ["@codemirror/language@6.12.2", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.23.0", "@lezer/common": "^1.5.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0", "style-mod": "^4.0.0" } }, "sha512-jEPmz2nGGDxhRTg3lTpzmIyGKxz3Gp3SJES4b0nAuE5SWQoKdT5GoQ69cwMmFd+wvFUhYirtDTr0/DRHpQAyWg=="], + "@codemirror/language": ["@codemirror/language@6.12.4", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.23.0", "@lezer/common": "^1.5.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0", "style-mod": "^4.0.0" } }, "sha512-1q4PaT+o6PbgpkJt4Q8Fv5XJxTy4FUZ4MWETtyiDw3J0Pyr9E2vqcKL+k9wcvjNTIsauxvE7OfmWj3FRPHQ76A=="], "@codemirror/language-data": ["@codemirror/language-data@6.5.2", "", { "dependencies": { "@codemirror/lang-angular": "^0.1.0", "@codemirror/lang-cpp": "^6.0.0", "@codemirror/lang-css": "^6.0.0", "@codemirror/lang-go": "^6.0.0", "@codemirror/lang-html": "^6.0.0", "@codemirror/lang-java": "^6.0.0", "@codemirror/lang-javascript": "^6.0.0", "@codemirror/lang-jinja": "^6.0.0", "@codemirror/lang-json": "^6.0.0", "@codemirror/lang-less": "^6.0.0", "@codemirror/lang-liquid": "^6.0.0", "@codemirror/lang-markdown": "^6.0.0", "@codemirror/lang-php": "^6.0.0", "@codemirror/lang-python": "^6.0.0", "@codemirror/lang-rust": "^6.0.0", "@codemirror/lang-sass": "^6.0.0", "@codemirror/lang-sql": "^6.0.0", "@codemirror/lang-vue": "^0.1.1", "@codemirror/lang-wast": "^6.0.0", "@codemirror/lang-xml": "^6.0.0", "@codemirror/lang-yaml": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/legacy-modes": "^6.4.0" } }, "sha512-CPkWBKrNS8stYbEU5kwBwTf3JB1kghlbh4FSAwzGW2TEscdeHHH4FGysREW86Mqnj3Qn09s0/6Ea/TutmoTobg=="], - "@codemirror/legacy-modes": ["@codemirror/legacy-modes@6.5.2", "", { "dependencies": { "@codemirror/language": "^6.0.0" } }, "sha512-/jJbwSTazlQEDOQw2FJ8LEEKVS72pU0lx6oM54kGpL8t/NJ2Jda3CZ4pcltiKTdqYSRk3ug1B3pil1gsjA6+8Q=="], + "@codemirror/legacy-modes": ["@codemirror/legacy-modes@6.5.3", "", { "dependencies": { "@codemirror/language": "^6.0.0" } }, "sha512-xCsmIzH78MyWkib9jlPaaun57XNkfbMIhagfaZVd0iLTqlpw3jXaIcbZm72MTmmn64eTZpBVNjbyYh+QXnxRsg=="], - "@codemirror/lint": ["@codemirror/lint@6.9.4", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.35.0", "crelt": "^1.0.5" } }, "sha512-ABc9vJ8DEmvOWuH26P3i8FpMWPQkduD9Rvba5iwb6O3hxASgclm3T3krGo8NASXkHCidz6b++LWlzWIUfEPSWw=="], + "@codemirror/lint": ["@codemirror/lint@6.9.7", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.42.0", "crelt": "^1.0.5" } }, "sha512-28/+iWLYxKxsvGYhSYL7zaCZqLz5+FFFDq9tVsvGv9kv8RY4fFAchJ5WX9M3YrrRlTIsECjsXPqeNgnSmNP2dg=="], - "@codemirror/search": ["@codemirror/search@6.6.0", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.37.0", "crelt": "^1.0.5" } }, "sha512-koFuNXcDvyyotWcgOnZGmY7LZqEOXZaaxD/j6n18TCLx2/9HieZJ5H6hs1g8FiRxBD0DNfs0nXn17g872RmYdw=="], + "@codemirror/search": ["@codemirror/search@6.7.1", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.37.0", "crelt": "^1.0.5" } }, "sha512-uMe5UO6PamJtSHrXhhHOzSX3ReWtiJrva6GnPMwSOrZtiExb5X5eExhr2OUZQVvdxPsKpY3Ro2mFbQadpPWmHA=="], - "@codemirror/state": ["@codemirror/state@6.5.4", "", { "dependencies": { "@marijn/find-cluster-break": "^1.0.0" } }, "sha512-8y7xqG/hpB53l25CIoit9/ngxdfoG+fx+V3SHBrinnhOtLvKHRyAJJuHzkWrR4YXXLX8eXBsejgAAxHUOdW1yw=="], + "@codemirror/state": ["@codemirror/state@6.7.1", "", { "dependencies": { "@marijn/find-cluster-break": "^1.0.0" } }, "sha512-9QzNDgE4EYDnAHfrTlR2lwiPciiOymLtwKK+8yHQzCc7GXhAP9xdEbEJFy2IWB1j9UGUl9BsgMmTo/ImA02T7A=="], - "@codemirror/view": ["@codemirror/view@6.39.13", "", { "dependencies": { "@codemirror/state": "^6.5.0", "crelt": "^1.0.6", "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } }, "sha512-QBO8ZsgJLCbI28KdY0/oDy5NQLqOQVZCozBknxc2/7L98V+TVYFHnfaCsnGh1U+alpd2LOkStVwYY7nW2R1xbw=="], + "@codemirror/view": ["@codemirror/view@6.43.9", "", { "dependencies": { "@codemirror/state": "^6.7.0", "crelt": "^1.0.6", "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } }, "sha512-sTuUzTpPMFebRhg6dawChoKKgndIwfjmJgKVxBefPElcU2NwQ6AFroupk0SFqEerQyZOGRfDNnSN8Dw/lMAsXw=="], "@date-fns/tz": ["@date-fns/tz@1.4.1", "", {}, "sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA=="], @@ -1191,7 +1201,9 @@ "@remixicon/react": ["@remixicon/react@4.9.0", "", { "peerDependencies": { "react": ">=18.2.0" } }, "sha512-5/jLDD4DtKxH2B4QVXTobvV1C2uL8ab9D5yAYNtFt+w80O0Ys1xFOrspqROL3fjrZi+7ElFUWE37hBfaAl6U+Q=="], - "@replit/codemirror-vim": ["@replit/codemirror-vim@6.3.0", "", { "peerDependencies": { "@codemirror/commands": "6.x.x", "@codemirror/language": "6.x.x", "@codemirror/search": "6.x.x", "@codemirror/state": "6.x.x", "@codemirror/view": "6.x.x" } }, "sha512-aTx931ULAMuJx6xLf7KQDOL7CxD+Sa05FktTDrtLaSy53uj01ll3Zf17JdKsriER248oS55GBzg0CfCTjEneAQ=="], + "@replit/codemirror-vim": ["@replit/codemirror-vim@6.4.0", "", { "dependencies": { "@replit/codemirror-vim-core": "^0.1.0" }, "peerDependencies": { "@codemirror/commands": "6.x.x", "@codemirror/language": "6.x.x", "@codemirror/search": "6.x.x", "@codemirror/state": "6.x.x", "@codemirror/view": "6.x.x" } }, "sha512-t9UMDNhkmeAkl0uRbiJVotv97bGD6mf4GyJJoEbrjUqa/Pov0s9eL+4AaI0Xto3OGri17i9qwIpT0JbVlVXt8A=="], + + "@replit/codemirror-vim-core": ["@replit/codemirror-vim-core@0.1.0", "", {}, "sha512-1i6EBKpcNfDKvTmTh6N6g9lL6udD5t+uFNh4JCqozRnVlvUGOps7h/QzS2ne4zcvPUjvApKpmcP7Grc3fNbZiQ=="], "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.3", "", {}, "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q=="], diff --git a/package.json b/package.json index f9c145f5..7af6af03 100644 --- a/package.json +++ b/package.json @@ -91,25 +91,25 @@ }, "dependencies": { "@base-ui/react": "^1.4.0", - "@codemirror/autocomplete": "^6.20.0", - "@codemirror/commands": "^6.10.1", + "@codemirror/autocomplete": "^6.20.3", + "@codemirror/commands": "^6.11.0", "@codemirror/lang-cpp": "^6.0.3", "@codemirror/lang-css": "^6.3.1", "@codemirror/lang-go": "^6.0.1", - "@codemirror/lang-html": "^6.4.11", - "@codemirror/lang-javascript": "^6.2.4", + "@codemirror/lang-html": "^6.4.12", + "@codemirror/lang-javascript": "^6.2.5", "@codemirror/lang-json": "^6.0.2", - "@codemirror/lang-markdown": "^6.5.0", + "@codemirror/lang-markdown": "^6.5.2", "@codemirror/lang-python": "^6.2.1", "@codemirror/lang-rust": "^6.0.2", "@codemirror/lang-sql": "^6.10.0", "@codemirror/lang-xml": "^6.1.0", - "@codemirror/lang-yaml": "^6.1.2", - "@codemirror/language": "6.12.2", - "@codemirror/lint": "^6.9.2", - "@codemirror/search": "^6.6.0", - "@codemirror/state": "^6.5.4", - "@codemirror/view": "6.39.13", + "@codemirror/lang-yaml": "^6.1.3", + "@codemirror/language": "6.12.4", + "@codemirror/lint": "^6.9.7", + "@codemirror/search": "^6.7.1", + "@codemirror/state": "^6.7.1", + "@codemirror/view": "6.43.9", "@heroui/scroll-shadow": "^2.3.18", "@heroui/system": "^2.4.23", "@heroui/theme": "^2.4.23", @@ -148,8 +148,18 @@ "zustand": "^5.0.8" }, "overrides": { - "@codemirror/language": "6.12.2", - "@codemirror/view": "6.39.13" + "@codemirror/autocomplete": "6.20.3", + "@codemirror/commands": "6.11.0", + "@codemirror/lang-html": "6.4.12", + "@codemirror/lang-javascript": "6.2.5", + "@codemirror/lang-markdown": "6.5.2", + "@codemirror/lang-yaml": "6.1.3", + "@codemirror/language": "6.12.4", + "@codemirror/legacy-modes": "6.5.3", + "@codemirror/lint": "6.9.7", + "@codemirror/search": "6.7.1", + "@codemirror/state": "6.7.1", + "@codemirror/view": "6.43.9" }, "devDependencies": { "@clack/prompts": "^1.1.0", diff --git a/packages/ui/package.json b/packages/ui/package.json index 9dc25467..751a2956 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -19,34 +19,34 @@ "@capacitor/keyboard": "^8.0.0", "@capacitor/push-notifications": "^8.1.1", "@capacitor/status-bar": "^8.0.0", - "@codemirror/autocomplete": "^6.20.0", - "@codemirror/commands": "^6.10.1", + "@codemirror/autocomplete": "^6.20.3", + "@codemirror/commands": "^6.11.0", "@codemirror/lang-cpp": "^6.0.3", "@codemirror/lang-css": "^6.3.1", "@codemirror/lang-go": "^6.0.1", - "@codemirror/lang-html": "^6.4.11", - "@codemirror/lang-javascript": "^6.2.4", + "@codemirror/lang-html": "^6.4.12", + "@codemirror/lang-javascript": "^6.2.5", "@codemirror/lang-json": "^6.0.2", - "@codemirror/lang-markdown": "^6.5.0", + "@codemirror/lang-markdown": "^6.5.2", "@codemirror/lang-python": "^6.2.1", "@codemirror/lang-rust": "^6.0.2", "@codemirror/lang-sql": "^6.10.0", "@codemirror/lang-xml": "^6.1.0", - "@codemirror/lang-yaml": "^6.1.2", - "@codemirror/language": "6.12.2", + "@codemirror/lang-yaml": "^6.1.3", + "@codemirror/language": "6.12.4", "@codemirror/language-data": "^6.5.2", - "@codemirror/legacy-modes": "^6.5.2", - "@codemirror/lint": "^6.9.2", - "@codemirror/search": "^6.6.0", - "@codemirror/state": "^6.5.4", - "@codemirror/view": "6.39.13", + "@codemirror/legacy-modes": "^6.5.3", + "@codemirror/lint": "^6.9.7", + "@codemirror/search": "^6.7.1", + "@codemirror/state": "^6.7.1", + "@codemirror/view": "6.43.9", "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", "@lezer/highlight": "^1.2.3", "@opencode-ai/sdk": "1.18.18", "@pierre/diffs": "1.3.0-beta.6", - "@replit/codemirror-vim": "^6.3.0", + "@replit/codemirror-vim": "^6.4.0", "@simplewebauthn/browser": "13.3.0", "@tanstack/react-virtual": "3.14.5", "@xenova/transformers": "^2.17.2", diff --git a/packages/ui/src/components/chat/composer/DOCUMENTATION.md b/packages/ui/src/components/chat/composer/DOCUMENTATION.md index 3544932a..667c2db7 100644 --- a/packages/ui/src/components/chat/composer/DOCUMENTATION.md +++ b/packages/ui/src/components/chat/composer/DOCUMENTATION.md @@ -61,20 +61,46 @@ question of design, not of feasibility. Selection rendering: every device runs CodeMirror's `drawSelection()` — it keeps typing on the drawn-selection code path, and removing it makes CodeMirror enforce cursor association on the native selection, which iOS -answers with severe input lag. Every device also layers -`composerNativeSelectionExtension` (`editor/theme.ts`) on top: it re-shows +answers with severe input lag. **That much is not platform-specific and must +not be undone.** What differs is who paints the selection, and +`composerSelectionExtension` (`editor/theme.ts`) picks that per platform. + +When CodeMirror 6.43.9's iOS predicate does not match, +`composerNativeSelectionExtension` layers over `drawSelection()`: it re-shows the native selection, and — only while a range is selected — the native caret, hiding the painted layers those replace. The native selection is the one that shows for two reasons: the painted layer sits behind the content, so tokens -with their own background (inline code, fences) cover it completely; and -iOS's selection drag handles attach to the visible native selection and take -their colour from the caret, so a transparent caret means invisible handles. -The range-only caret scoping is load-bearing — a native caret visible while -typing makes WebKit re-render its caret UI after every keystroke, felt as -severe input lag. The selection tint comes from `--primary`, not the selection -token: -themes define `--interactive-selection` with its own alpha, so a translucent -mix of it is nearly invisible. +with their own background (inline code, fences) cover it completely; and the +platform's selection drag handles attach to the visible native selection and +take their colour from the caret, so a transparent caret means invisible +handles. The range-only caret scoping is load-bearing — a native caret visible +while typing makes the browser re-render its caret UI after every keystroke, +felt as severe input lag. + +When CodeMirror 6.43.9's exact iOS predicate matches, +`composerIOSSelectionExtension` leaves selection-handle geometry and appearance +to CodeMirror. CodeMirror puts the handles in `.cm-selectionLayer`, normally at +`z-index: -1`; the extension raises that layer above the content so opaque +token backgrounds cannot cover them, and leaves it transparent to touch. +The handle dots extend 8px past their range; matching scroller padding and +negative margin expand the clip area without moving the text or changing the +composer height. iOS still paints its taller system selection overlay even +when CSS makes `::selection` transparent. The extension therefore suppresses +CodeMirror's synthetic selection rectangles on iOS while leaving its handles, +cursor path and `nativeSelectionHidden` facet active. Otherwise the grey system +highlight and themed rectangle overlap with visibly different heights. +Do not add a second custom layer or custom handles here: overlapping translucent +rectangles make selection darker at their seams and imitated handles drift from +the geometry WebKit actually manipulates. What iOS avoids is installing the +native-selection workaround above: explicitly restoring native paint and caret +makes WebKit re-measure them after every decoration redraw, and the composer +rebuilds every decoration on every keystroke. That cost is felt worst during +IME composition. + +The non-iOS native selection tint comes from `--primary`, not the selection +token: themes define `--interactive-selection` with its own alpha, so mixing it +with transparent again is nearly invisible. The iOS system overlay owns its +visible selection fill. `composerLanguage.ts` retokenizes the whole document on every change. The composer holds a prompt, not a source file: it is short enough that a full pass diff --git a/packages/ui/src/components/chat/composer/editor/ComposerEditor.tsx b/packages/ui/src/components/chat/composer/editor/ComposerEditor.tsx index c248a53f..990f62ee 100644 --- a/packages/ui/src/components/chat/composer/editor/ComposerEditor.tsx +++ b/packages/ui/src/components/chat/composer/editor/ComposerEditor.tsx @@ -36,7 +36,7 @@ import { cn } from '@/lib/utils'; import type { ComposerLanguageContext } from '../language/tokenize'; import { composerLanguage, setLanguageContext } from './composerLanguage'; import type { ComposerEditorViewStore } from './viewStore'; -import { composerEditorTheme, composerNativeSelectionExtension } from './theme'; +import { composerEditorTheme, composerSelectionExtension } from './theme'; import { handleComposerHostMouseDown } from './hostMouseDown'; export interface ComposerSelection { @@ -234,14 +234,13 @@ export const ComposerEditor = React.forwardRef { /** * EditorView.theme compiles its selectors when this module is imported and @@ -20,13 +33,7 @@ describe('composerEditorTheme', () => { * surfaces only in the running app, where it takes the composer down. */ test('its selectors compile and the theme can be installed', () => { - let failure: unknown = null; - try { - EditorState.create({ extensions: [composerEditorTheme] }); - } catch (error) { - failure = error; - } - expect(failure).toBeNull(); + expect(installationError(composerEditorTheme)).toBeNull(); }); /** @@ -101,6 +108,10 @@ describe('composerEditorTheme', () => { expect(rule.background.includes('transparent')).toBe(true); } }); + + test('the common theme does not re-show the native selection', () => { + expect(selectors.some((selector) => selector.includes('::selection'))).toBe(false); + }); }); describe('composerNativeSelectionTheme', () => { @@ -108,21 +119,16 @@ describe('composerNativeSelectionTheme', () => { const nativeDeclarations = JSON.stringify(NATIVE_SELECTION_THEME_SPEC); /** - * Every device layers this over `drawSelection()`: the native selection - * paints over token backgrounds (the painted layer is hidden behind them) - * and iOS attaches its selection handles to it. `drawSelection()` must - * NOT be removed for that: without it CodeMirror starts enforcing cursor - * association on the native selection while typing in wrapped text, and - * iOS answers those programmatic selection moves with severe input lag. + * Every device except iOS layers this over `drawSelection()`: the native + * selection paints over token backgrounds (the painted layer is hidden + * behind them) and the platform attaches its selection handles to it. + * `drawSelection()` must NOT be removed for that: without it CodeMirror + * starts enforcing cursor association on the native selection while typing + * in wrapped text, and iOS answers those programmatic selection moves with + * severe input lag. */ test('it compiles and can be installed', () => { - let failure: unknown = null; - try { - EditorState.create({ extensions: [composerNativeSelectionExtension] }); - } catch (error) { - failure = error; - } - expect(failure).toBeNull(); + expect(installationError(composerNativeSelectionExtension)).toBeNull(); }); /** @@ -150,9 +156,9 @@ describe('composerNativeSelectionTheme', () => { }); /** - * iOS colours its selection drag handles from the caret colour. With - * `drawSelection()`'s `caret-color: transparent !important` in effect the - * handles are drawn — invisibly. The native caret must come back with + * A platform showing native handles colours them from the caret colour. + * With `drawSelection()`'s `caret-color: transparent !important` in effect + * the handles are drawn — invisibly. The native caret must come back with * enough weight to win, and the drawn cursor layer must go so there are * not two carets. * @@ -195,3 +201,106 @@ describe('composerNativeSelectionTheme', () => { expect(tokens.filter((token) => /[A-Z]/.test(token))).toEqual([]); }); }); + +describe('composerIOSSelectionExtension', () => { + const layerRule = IOS_SELECTION_THEME_SPEC['& .cm-scroller > .cm-selectionLayer']; + const scrollerRule = IOS_SELECTION_THEME_SPEC['& .cm-scroller']; + const selectionBackgroundRule = IOS_SELECTION_THEME_SPEC['& .cm-selectionBackground']; + + test('it compiles and can be installed', () => { + expect(installationError(composerIOSSelectionExtension)).toBeNull(); + }); + + /** + * CodeMirror renders its selection layer at `z-index: -1`, behind the + * text. Inline code and code fences have opaque backgrounds and otherwise + * cover both the selection and the iOS handles. The base value is inline, + * so raising it without `!important` silently does nothing. + */ + test('CodeMirror selection and handles are raised above token backgrounds', () => { + expect(layerRule.zIndex).toBe('100 !important'); + }); + + /** + * The layer now sits over the content and would intercept taps and drags + * by default. It only paints; CodeMirror/WebKit still own the gestures. + */ + test('the layer does not intercept touch', () => { + expect(layerRule.pointerEvents).toBe('none'); + }); + + /** + * A higher z-index cannot escape overflow clipping. CodeMirror's dots + * extend 8px past the range, so the scroller needs that much internal room; + * the matching negative margin keeps the text and composer height fixed. + */ + test('the scroller reserves unclipped room for both handles', () => { + expect(scrollerRule.paddingBlock).toBe('8px'); + expect(scrollerRule.marginBlock).toBe('-8px'); + }); + + test('the CodeMirror fill does not stack over the iOS system highlight', () => { + expect(selectionBackgroundRule.background).toBe('transparent !important'); + }); + + /** + * A second custom layer was visually indistinguishable from duplicate + * native selection UI. iOS must only reposition the one layer that + * CodeMirror already uses for both selection rectangles and handles. + */ + test('it does not add a second selection implementation', () => { + expect(Object.keys(IOS_SELECTION_THEME_SPEC)).toEqual([ + '& .cm-scroller', + '& .cm-scroller > .cm-selectionLayer', + '& .cm-selectionBackground', + ]); + }); +}); + +describe('composerSelectionExtension', () => { + /** + * The split is the point: iOS is the only platform that pays for a visible + * native selection during composition, and CodeMirror 6.43.9 draws its + * handles. Collapsing the two branches into one would + * either restore the latency on iOS or leave every other platform without + * discoverable range selection. + */ + test('the CodeMirror iOS path uses its handles; other platforms keep native selection', () => { + expect(composerSelectionExtension(true)).toBe(composerIOSSelectionExtension); + expect(composerSelectionExtension(false)).toBe(composerNativeSelectionExtension); + }); + + /** + * The composer may remove the native fallback only when CodeMirror's own + * browser predicate enables its replacement handles. This deliberately + * includes CodeMirror's vendor and touch thresholds rather than using a + * broader application-level iOS heuristic. + */ + test('the platform predicate matches CodeMirror 6.43.9', () => { + expect(isCodeMirrorIOSNavigator( + 'Mozilla/5.0 (iPhone; CPU iPhone OS 18_6) Mobile/15E148 Safari/604.1', + 'Apple Computer, Inc.', + 5, + )).toBe(true); + expect(isCodeMirrorIOSNavigator( + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15)', + 'Apple Computer, Inc.', + 5, + )).toBe(true); + expect(isCodeMirrorIOSNavigator( + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15)', + 'Google Inc.', + 5, + )).toBe(false); + expect(isCodeMirrorIOSNavigator( + 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15)', + 'Apple Computer, Inc.', + 0, + )).toBe(false); + expect(isCodeMirrorIOSNavigator( + 'Mozilla/5.0 (Windows NT 10.0; Trident/7.0; rv:11.0)', + 'Apple Computer, Inc.', + 5, + )).toBe(false); + }); +}); diff --git a/packages/ui/src/components/chat/composer/editor/theme.ts b/packages/ui/src/components/chat/composer/editor/theme.ts index 7a103d9d..ccc9a933 100644 --- a/packages/ui/src/components/chat/composer/editor/theme.ts +++ b/packages/ui/src/components/chat/composer/editor/theme.ts @@ -5,6 +5,7 @@ * language layer emits, so the composer and the message list stay in step. */ +import type { Extension } from '@codemirror/state'; import { EditorView } from '@codemirror/view'; /** @@ -78,23 +79,16 @@ export const COMPOSER_EDITOR_THEME_SPEC = { '&.cm-editor.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground': { background: 'color-mix(in srgb, var(--interactive-selection) 55%, transparent)', }, - // The native selection still shows through in places CodeMirror does not - // draw over, such as the placeholder. Same colour as the native-selection - // theme below, for the same reason: the selection token carries its own - // alpha and reads as nearly invisible when mixed down again. - '& ::selection': { - background: 'color-mix(in srgb, var(--primary) 25%, transparent)', - }, }; export const composerEditorTheme = EditorView.theme(COMPOSER_EDITOR_THEME_SPEC); /** - * Every device keeps `drawSelection()` but shows the NATIVE selection through - * it, for two independent reasons: + * Outside CodeMirror's iOS branch, devices keep `drawSelection()` but show the + * NATIVE selection through it, for two independent reasons: * - * - iOS attaches its selection handles (the draggable pins after a - * double-tap) to the *visible* native selection, and `drawSelection()` + * - Their selection drag handles (the draggable pins after a double-tap) + * attach to the *visible* native selection, and `drawSelection()` * hides it with `.cm-line ::selection { background: transparent * !important }`, so the handles never appear and range selection is * undiscoverable. @@ -103,12 +97,15 @@ export const composerEditorTheme = EditorView.theme(COMPOSER_EDITOR_THEME_SPEC); * the selection is invisible inside those spans. The native selection * paints over element backgrounds. * - * Dropping `drawSelection()` entirely is NOT an option: without it CodeMirror - * clears the `nativeSelectionHidden` facet and starts enforcing cursor - * association on the native selection while typing in wrapped text — - * programmatic selection moves that iOS answers with severe input lag (each - * one also resets the keyboard's autocorrect context). Typing must stay on - * the drawn-selection code path; only the paint changes. + * Dropping `drawSelection()` entirely is NOT an option, on any platform: + * without it CodeMirror clears the `nativeSelectionHidden` facet and starts + * enforcing cursor association on the native selection while typing in + * wrapped text — programmatic selection moves that iOS answers with severe + * input lag (each one also resets the keyboard's autocorrect context). Typing + * must stay on the drawn-selection code path; only the paint changes. + * + * CodeMirror's iOS branch does NOT use this arrangement — + * `composerIOSSelectionExtension` below explains why. * * Both rules below fight `drawSelection()`'s own `Prec.highest` theme, so * they carry `!important` and one class more specificity @@ -155,14 +152,103 @@ export const NATIVE_SELECTION_THEME_SPEC = { const composerNativeSelectionTheme = EditorView.theme(NATIVE_SELECTION_THEME_SPEC); /** - * The native-selection arrangement, installed on every device: the theme - * above plus the `.oc-native-range` marker class that scopes its caret rules - * to the moments a range is actually selected. `editorAttributes` + * The native-selection arrangement, installed outside CodeMirror's iOS branch: + * the theme above plus the `.oc-native-range` marker class that scopes its + * caret rules to the moments a range is actually selected. `editorAttributes` * re-evaluates on every update, so the class follows the selection with no * listener of its own. */ -export const composerNativeSelectionExtension = [ +export const composerNativeSelectionExtension: Extension = [ composerNativeSelectionTheme, EditorView.editorAttributes.of((view) => view.state.selection.main.empty ? null : { class: 'oc-native-range' }), ]; + +/** + * When its iOS predicate matches, CodeMirror 6.43.9 draws the range handles + * into the same layer as the selection, so CodeMirror owns both their geometry + * and appearance. + * + * That layer normally renders at `z-index: -1`, behind the content. Inline + * code and code fences have opaque backgrounds and would cover both the tint + * and handles. Raising the one existing layer fixes that without introducing + * a second set of rectangles or trying to imitate WebKit's controls. The + * layer remains transparent to touch so WebKit receives selection gestures. + * + * What iOS avoids is the native-selection workaround above: explicitly + * restoring the native highlight and caret makes WebKit re-measure and repaint + * that UI after every decoration redraw. `composerLanguage.ts` rebuilds the + * whole decoration set on every keystroke, so the cost is felt worst during + * IME composition where each intermediate replacement pays for it. WebKit's + * unavoidable system selection overlay remains the only visible fill. + */ +export const IOS_SELECTION_THEME_SPEC = { + // The handles extend 8px above/below their range. The scroller clips them + // at its own edge even when the layer has a high z-index, so reserve that + // room inside the clipping box and pull the box outward by the same amount. + // Text and composer height stay where they were; only the clip area grows. + '& .cm-scroller': { + marginBlock: '-8px', + paddingBlock: '8px', + }, + '& .cm-scroller > .cm-selectionLayer': { + // CodeMirror writes `z-index: -1` inline. `!important` is intentional: + // without it token backgrounds cover the selection and its handles. + zIndex: '100 !important', + pointerEvents: 'none', + }, + // iOS keeps showing its taller system selection overlay even when + // ::selection is transparent. Painting CodeMirror's themed rectangles as + // well produces two visibly misaligned fills, so only the synthetic + // background is suppressed. The handles in this layer remain visible. + '& .cm-selectionBackground': { + background: 'transparent !important', + }, +}; + +export const composerIOSSelectionExtension: Extension = + EditorView.theme(IOS_SELECTION_THEME_SPEC); + +/** + * Which selection paint the composer installs. The split is the platform's, + * not a preference: iOS is the one place where restoring native selection + * paint and caret costs measurable input latency, and the only place + * CodeMirror supplies replacement drag handles. + * + * The caller can pass the policy, so the choice stays testable and is made + * once per editor rather than once per module load. + */ +export function composerSelectionExtension( + useCodeMirrorIOSHandles: boolean = usesCodeMirrorIOSSelectionHandles(), +): Extension { + return useCodeMirrorIOSHandles + ? composerIOSSelectionExtension + : composerNativeSelectionExtension; +} + +/** + * Mirrors @codemirror/view 6.43.9's iOS predicate. This branch may only rely + * on the drawn handles when CodeMirror itself will create them; a broader iOS + * heuristic could remove the native fallback without installing a replacement. + */ +export function isCodeMirrorIOSNavigator( + userAgent: string, + vendor: string, + maxTouchPoints: number, +): boolean { + const isIE = /Edge\/(\d+)/.test(userAgent) + || /MSIE \d/.test(userAgent) + || /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.test(userAgent); + if (isIE || !/Apple Computer/.test(vendor)) return false; + return /Mobile\/\w+/.test(userAgent) || maxTouchPoints > 2; +} + +function usesCodeMirrorIOSSelectionHandles(): boolean { + const nav = globalThis.navigator; + if (!nav) return false; + return isCodeMirrorIOSNavigator( + nav.userAgent || '', + nav.vendor || '', + nav.maxTouchPoints ?? 0, + ); +}