From af2a2247811286a60a323f62e42d38ea6402b2f0 Mon Sep 17 00:00:00 2001 From: Patrick Loser Date: Sun, 16 Aug 2026 04:04:17 +0200 Subject: [PATCH] fix: Novel Screen Scroll Lag, Source Pagination Stalls, and Skeleton Overlap (#1971) * fix * Update pnpm-lock.yaml * fix tests --- package.json | 3 +- pnpm-lock.yaml | 405 +++++++++++++----- src/components/NovelList.tsx | 8 - src/components/__tests__/NovelList.test.ts | 1 - .../novelStore.chapterActions.test.ts | 4 + .../store/novelStore.chapterActions.ts | 13 + src/navigators/Main.tsx | 10 +- .../BrowseSourceScreen/BrowseSourceScreen.tsx | 62 ++- .../BrowseSourceScreen/useBrowseSource.ts | 150 +++++-- .../SourceScreenSkeletonLoading.tsx | 6 +- src/screens/novel/NovelContext.tsx | 47 +- .../novel/components/NovelScreenList.tsx | 22 +- .../__tests__/NovelScreenList.test.tsx | 5 +- 13 files changed, 569 insertions(+), 167 deletions(-) diff --git a/package.json b/package.json index 88f48fd1..60e89b5d 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "@react-navigation/bottom-tabs": "^7.18.11", "@react-navigation/native": "^7.3.11", "@react-navigation/native-stack": "^7.18.3", + "@rozenite/react-navigation-plugin": "^2.0.0", "cheerio": "1.0.0-rc.12", "color": "^5.0.3", "dayjs": "^1.11.21", @@ -73,7 +74,7 @@ "lodash-es": "^4.18.1", "protobufjs": "^8.7.1", "react": "19.2.3", - "react-native": "0.86.0", + "react-native": "^0.86.0", "react-native-device-info": "^15.0.2", "react-native-draggable-flatlist": "^4.0.3", "react-native-drawer-layout": "^4.2.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 221a72d0..38e29532 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -16,7 +16,7 @@ importers: version: 5.2.14(24fcb93f20601afa4f41878e40cdc0fb) '@legendapp/list': specifier: ^3.3.3 - version: 3.3.3(patch_hash=37a9c8d7d9c1bd33c957ba6ea78291c7b08532dc32de4925f3d612cb41f1a659)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3) + version: 3.3.3(patch_hash=37a9c8d7d9c1bd33c957ba6ea78291c7b08532dc32de4925f3d612cb41f1a659)(react-dom@19.2.8(react@19.2.3))(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3) '@noble/ciphers': specifier: ^2.2.0 version: 2.2.0 @@ -47,6 +47,9 @@ importers: '@react-navigation/native-stack': specifier: ^7.18.3 version: 7.18.3(b07337b648742f75a968ee96fc7e36e1) + '@rozenite/react-navigation-plugin': + specifier: ^2.0.0 + version: 2.0.0(@react-navigation/core@7.21.8(react@19.2.3))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.3))(react@19.2.3) cheerio: specifier: 1.0.0-rc.12 version: 1.0.0-rc.12 @@ -61,7 +64,7 @@ importers: version: 1.0.0-beta.22(@op-engineering/op-sqlite@15.2.14(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3))(@sinclair/typebox@0.34.52)(@types/better-sqlite3@7.6.13)(better-sqlite3@12.11.1)(zod@4.4.3) expo: specifier: ^57.0.7 - version: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + version: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) expo-build-properties: specifier: ~57.0.6 version: 57.0.6(expo@57.0.7) @@ -123,7 +126,7 @@ importers: specifier: 19.2.3 version: 19.2.3 react-native: - specifier: 0.86.0 + specifier: ^0.86.0 version: 0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0) react-native-device-info: specifier: ^15.0.2 @@ -415,7 +418,6 @@ packages: '@babel/parser@7.29.7': resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} engines: {node: '>=6.0.0'} - hasBin: true '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.29.7': resolution: {integrity: sha512-j8SrR0zLZrRsC09DlszEx8FpMiwukKffYXMK0d5LmOglO7vGG6sz/BR/20yHqWH+Lnn31JTt2PE3hIWNgM2J6w==} @@ -990,6 +992,33 @@ packages: resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} engines: {node: '>=6.9.0'} + '@base-ui/react@1.7.0': + resolution: {integrity: sha512-j+8QjX44C32jrXD/qyEAGpFr70FRpGL2CY61mQd9nBPWN737CK0xxD1ceJ055rW4RtdvFDT1e7otzdlfxvsYug==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@date-fns/tz': ^1.2.0 + '@types/react': ^17 || ^18 || ^19 + date-fns: ^4.0.0 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@date-fns/tz': + optional: true + '@types/react': + optional: true + date-fns: + optional: true + + '@base-ui/utils@0.3.2': + resolution: {integrity: sha512-oWy1aq/I2GmYjpl4PhEAhzflF8VPGKgZeq0xAWTbfD5KBWyxcN0ZP2+WHSUm/5Z6lVMBDLReLcoXwSYoRc/zNQ==} + peerDependencies: + '@types/react': ^17 || ^18 || ^19 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@types/react': + optional: true + '@bcoe/v8-coverage@0.2.3': resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} @@ -1210,7 +1239,6 @@ packages: '@expo/cli@57.0.9': resolution: {integrity: sha512-41z9z68SynNXasZOjuT1si5Sq5OKL6SLf40ZjikbtZgDuvBO8HaUsaDzsJ0c1UZJ3N+vMzYCc1JUIDyRkVBjkA==} - hasBin: true peerDependencies: expo: '*' expo-router: '*' @@ -1263,7 +1291,6 @@ packages: '@expo/fingerprint@0.20.5': resolution: {integrity: sha512-XCDfmbkTpTsYVq1xvvUJvXjfFQs2Hj+icQACBrc6BZmA91YPr2H3uw8sUX13d+1ij6E8lgVCtsK9jh3J2cN/SQ==} - hasBin: true '@expo/image-utils@0.11.3': resolution: {integrity: sha512-yMVjkndhXm9mct0uMq+ndxqT6FgAnhucdUfmXuQ6V6uE021GOiYCACO+KZ0MB4vearPSvbWTGfi32QQr2qocfQ==} @@ -1365,7 +1392,21 @@ packages: '@expo/xcpretty@4.4.4': resolution: {integrity: sha512-4aQzz9vgxcNXFfo/iyNgDDYfsU5XGKKxWxZopw0cVotHiW+U8IJbIxMaxsINs6bHhtkG3StKNPcOrn3eBuxKPw==} - hasBin: true + + '@floating-ui/core@1.8.0': + resolution: {integrity: sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==} + + '@floating-ui/dom@1.8.0': + resolution: {integrity: sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==} + + '@floating-ui/react-dom@2.1.9': + resolution: {integrity: sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.12': + resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==} '@gorhom/bottom-sheet@5.2.14': resolution: {integrity: sha512-uLQFlDjp9z+jrOFcMSEldPqL5JdaXL3vXOh+juhwoNvXgTsEorJLjHTugXu+YccAG/0KJnShzKCrb71MHBsvJg==} @@ -1590,7 +1631,6 @@ packages: '@react-native-vector-icons/common@13.0.1': resolution: {integrity: sha512-UPC6L3tW5rXCjBn4kgw9RPURUILIg8tFpEY2uaYwU8aCjEHkywNCMcAO8+PvMCDkR6aICPeHYA0OXvMgrjsF4g==} engines: {node: '>=20.19.0 <21.0.0 || >=22.0.0'} - hasBin: true peerDependencies: '@react-native-vector-icons/get-image': ^13.0.0 '@react-native/assets-registry': '*' @@ -1748,10 +1788,20 @@ packages: peerDependencies: react: '>=17' + '@rozenite/agent-bridge@2.0.0': + resolution: {integrity: sha512-yfyQAUOBn0zlPSC3KsA1aaNEWXe9k94RtB3RexOA8+9QPfn1VTN/OGiTAeRsKKNQNkIGzz+VcKYMT0csAkrYZQ==} + engines: {node: '>=20'} + peerDependencies: + react: '>=17' + '@rozenite/agent-shared@1.13.0': resolution: {integrity: sha512-CF5JWUBTpAtTJ1oPZ2lQgT46JcmrzoaN5dL+G92SOPgVsgBinBVCXcY38MGC7mZ/7iM/fccKQPHvbFSric4wjQ==} engines: {node: '>=20'} + '@rozenite/agent-shared@2.0.0': + resolution: {integrity: sha512-xIlRNNCh6TzWoo7YM1oYa+EphN0UlP6hIa9BIp0bBD3rCuZLpuc2T6iT+DmsJVtPECXq1CAIZbifVXuvZEXjeA==} + engines: {node: '>=20'} + '@rozenite/expo-atlas-plugin@1.13.0': resolution: {integrity: sha512-bpER3owQM/7b4JF/n7EUjUA3DuFv38AhUtARqefOMxMwkWt6LPDKpPDLOe8l7jxz1LheOWaAtlvbIN6L/abNxg==} peerDependencies: @@ -1772,6 +1822,17 @@ packages: peerDependencies: react: '>=17' + '@rozenite/plugin-bridge@2.0.0': + resolution: {integrity: sha512-+qzsqnluoYqA0NtOD+phVUPnloC6Nf9ZcRIvUOV231PnXiG52jvbKzavTXMFlZ1L89aKgr5560eglGZEAQ/Blg==} + engines: {node: '>=20'} + peerDependencies: + react: '>=17' + + '@rozenite/react-navigation-plugin@2.0.0': + resolution: {integrity: sha512-zAs3CyKD0x2y+mUlnDiqzgdFy64FyOdxmfR+LinSftFLjhQ+mKGoewXPSo8SLTIgwotwpYayt+lyL7rS74oQQg==} + peerDependencies: + '@react-navigation/core': ^7.12.1 + '@rozenite/runtime@1.13.0': resolution: {integrity: sha512-3U+63lZtNW+D+JRETINZTvD0bYjXDRJd818bSQlNOJNAZ6AQTBShNM+4enYjmJLJApzkfxhLUjVDQ+AwkvlQ2A==} engines: {node: '>=20'} @@ -1789,6 +1850,13 @@ packages: '@rozenite/tools@1.13.0': resolution: {integrity: sha512-fZnEEdyQQNABeCUNAndfdcDRzcXSoojj+USwHMbkCaM7BClPGdurKE/7kewGhYlp901cpahDOGtRF+eXEZ6UIQ==} + '@rozenite/ui@2.0.0': + resolution: {integrity: sha512-irAl5WgvQHnejQy3ujfR+u9S5MEbXCHiXxWs7+LNxEzuBhD0CLMd3E27MUJIyWQ0N/PpDY+JzVOQ7NiOfchSIA==} + engines: {node: '>=20'} + peerDependencies: + react: '>=19' + react-dom: '>=19' + '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} @@ -1804,6 +1872,17 @@ packages: '@sinonjs/fake-timers@10.3.0': resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + '@tanstack/react-table@8.21.3': + resolution: {integrity: sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==} + engines: {node: '>=12'} + peerDependencies: + react: '>=16.8' + react-dom: '>=16.8' + + '@tanstack/table-core@8.21.3': + resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==} + engines: {node: '>=12'} + '@testing-library/react-native@13.3.3': resolution: {integrity: sha512-k6Mjsd9dbZgvY4Bl7P1NIpePQNi+dfYtlJ5voi9KQlynxSyQkfOgJmYGCYmw/aSgH/rUcFvG8u5gd4npzgRDyg==} engines: {node: '>=18'} @@ -2029,7 +2108,6 @@ packages: '@typescript/native-preview@7.0.0-dev.20260707.2': resolution: {integrity: sha512-oUGp+Rep/hqMhPunyinsALUwSlzHINSxitifPiSaeqoKOKD2OlR9NE3TaPqwsl4NlGslsOSUXI1JotWQzpYCPg==} engines: {node: '>=16.20.0'} - hasBin: true '@ungap/structured-clone@1.3.3': resolution: {integrity: sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==} @@ -2157,10 +2235,12 @@ packages: '@xmldom/xmldom@0.8.13': resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==} engines: {node: '>=10.0.0'} + deprecated: this version has critical issues, please update to the latest version '@xmldom/xmldom@0.9.10': resolution: {integrity: sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw==} engines: {node: '>=14.6'} + deprecated: this version has critical issues, please update to the latest version abab@2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} @@ -2193,7 +2273,6 @@ packages: acorn@8.17.0: resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} engines: {node: '>=0.4.0'} - hasBin: true agent-base@6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} @@ -2206,7 +2285,6 @@ packages: agent-cli-detector@0.1.3: resolution: {integrity: sha512-XjBe6lT5sK9xhAn0ToFvdwicsaGvzZkax1iviPnL8sFFYHoagnTTn2E4YTFiyM956iqkOkFcgcWCiER0kkShbQ==} engines: {node: '>=18.18'} - hasBin: true aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} @@ -2414,7 +2492,6 @@ packages: baseline-browser-mapping@2.10.43: resolution: {integrity: sha512-AjYpR78kDWAY3Efj+cDTFH9t9SCoL7OoTp1BOb0mQV7S+6CiLwnWM3FyxhJtdPufDFKzmCSFoUncKjWgJEZTCQ==} engines: {node: '>=6.0.0'} - hasBin: true basic-auth@2.0.1: resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==} @@ -2476,7 +2553,6 @@ packages: browserslist@4.28.6: resolution: {integrity: sha512-FQBYNK15VMslhLHpA7+n+n1GOlF1kId2xcCg7/j95f24AOF6VDYMNH4mFxF7KuaTdv627faazpOAjFzMrfJOUw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true bser@2.1.1: resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} @@ -2564,7 +2640,6 @@ packages: chrome-launcher@0.15.2: resolution: {integrity: sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==} engines: {node: '>=12.13.0'} - hasBin: true chromium-edge-launcher@0.3.0: resolution: {integrity: sha512-p03azHlGjtyRvFEee3cyvtsRYdniSkwjkzmM/KmVnqT5d7QkkwpJBhis/zCLMYdQMVJ5tt140TBNqqrZPaWeFA==} @@ -2579,6 +2654,9 @@ packages: cjs-module-lexer@1.4.3: resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + clean-stack@2.2.0: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} @@ -2615,6 +2693,10 @@ packages: resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} engines: {node: '>=0.8'} + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + co@4.6.0: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} @@ -2740,7 +2822,6 @@ packages: create-jest@29.7.0: resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} @@ -2934,7 +3015,6 @@ packages: drizzle-kit@1.0.0-beta.20: resolution: {integrity: sha512-qMUBnrOQIU+H32aF80BSn7lT1IQuKmofCypmkrKMuOMqvM0bhz5hjCHim1bLcXUzXYRtTSr6U2pe0MSV79WbAg==} deprecated: The 1.0.0-beta line is superseded by the 1.0 release candidate. Install drizzle-kit@rc instead. - hasBin: true drizzle-orm@1.0.0-beta.22: resolution: {integrity: sha512-F+DZyVIvH0oVKa/w08Cle1xfoH+pc+htIXHG/frnMLG72aby9NYYr9oc+9XvghnoO4umxFItduz0OMmQJMnenw==} @@ -3154,7 +3234,6 @@ packages: esbuild@0.25.12: resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} engines: {node: '>=18'} - hasBin: true escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} @@ -3178,7 +3257,6 @@ packages: escodegen@2.1.0: resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} engines: {node: '>=6.0'} - hasBin: true eslint-config-expo@57.0.0: resolution: {integrity: sha512-T7OTN9xrSZYjLw4qTkL1Mn2WfAUVmMGY38+OYAcraI1uiTFVH6jfkSkv84WLTqnneblLcb6AsMDV+SHcUj3hGw==} @@ -3297,7 +3375,6 @@ packages: eslint@9.39.5: resolution: {integrity: sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - hasBin: true peerDependencies: jiti: '*' peerDependenciesMeta: @@ -3311,7 +3388,6 @@ packages: esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} - hasBin: true esquery@1.7.0: resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} @@ -3362,7 +3438,6 @@ packages: expo-atlas@0.4.3: resolution: {integrity: sha512-nN2bouxFvMsqZqLl0ka+eI9Ofida0PcuoE4v+7fHlgyp95X2cCL8Acf0nRKXmmIBEYazdw0d7BAOZfC0b41oxA==} - hasBin: true peerDependencies: expo: '*' @@ -3475,7 +3550,6 @@ packages: expo-modules-autolinking@57.0.8: resolution: {integrity: sha512-YBDgbJHlhhhr3JaKErW6znsIL8zQsh206LaDpWrLHV/WluRwhYfZuF/fhkVN7b/DsRxIu0UeCPExaEPMxlC2Hw==} - hasBin: true expo-modules-core@57.0.6: resolution: {integrity: sha512-hePwOh2+i+EpWrVnv95sQeQ0OD5PYuEuIhmglVLzQVaVBV3zHcRvLAc1rV8ROqUL6YtAQUXjPkoSx1ly2ZdTuQ==} @@ -3526,7 +3600,6 @@ packages: expo@57.0.7: resolution: {integrity: sha512-PJdE0EjoX878OqClmsigVKdT0jCNOAQDRLcvFkeBakxaVyEDhjcQ8baKq2YysYH2g0YNB1rEIpHUiKtluO918A==} - hasBin: true peerDependencies: '@expo/dom-webview': '*' '@expo/metro-runtime': '*' @@ -3573,7 +3646,6 @@ packages: fb-dotslash@0.5.8: resolution: {integrity: sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA==} engines: {node: '>=20'} - hasBin: true fb-watchman@2.0.2: resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} @@ -3911,7 +3983,6 @@ packages: husky@7.0.4: resolution: {integrity: sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ==} engines: {node: '>=12'} - hasBin: true i18n-js@4.5.3: resolution: {integrity: sha512-5/tT6R9t9qlYqGhxGq9I9Ap3WKUaAMq5aRuO1gqAcUqm6xGbL0jwTAjSFjgbx935BAV8QbEzvQOzE796dUlEfA==} @@ -3942,7 +4013,6 @@ packages: image-size@1.2.1: resolution: {integrity: sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==} engines: {node: '>=16.x'} - hasBin: true import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} @@ -3951,7 +4021,6 @@ packages: import-local@3.2.0: resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} engines: {node: '>=8'} - hasBin: true imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} @@ -4035,7 +4104,6 @@ packages: is-docker@2.2.1: resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} engines: {node: '>=8'} - hasBin: true is-document.all@1.0.0: resolution: {integrity: sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==} @@ -4187,7 +4255,6 @@ packages: jest-cli@29.7.0: resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: @@ -4237,7 +4304,6 @@ packages: jest-expo@57.0.2: resolution: {integrity: sha512-xoKiYyu8c0fdBsFMkeFnxoTZ/0g4rLldA9isVb7VJSGBGesmhkVor7YkftkHqQ5rWiZ99IY+/uIrzTgb1nC/UA==} - hasBin: true peerDependencies: '@react-native/jest-preset': ^0.86.0 expo: '*' @@ -4338,7 +4404,6 @@ packages: jest@29.7.0: resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true peerDependencies: node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 peerDependenciesMeta: @@ -4350,18 +4415,15 @@ packages: jiti@2.7.0: resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} - hasBin: true js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} js-yaml@3.15.0: resolution: {integrity: sha512-ttBQIIQPDeLjpPOohtUdXuXUVoA2uIB6fEH9HyJ7234s5mBJ5wTx20njxplLZQgLaOfpmPQA7X2t5AX6tIPbog==} - hasBin: true js-yaml@4.3.0: resolution: {integrity: sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==} - hasBin: true jsbi@4.3.2: resolution: {integrity: sha512-9fqMSQbhJykSeii05nxKl4m6Eqn2P6rOlYiS+C5Dr/HPIU/7yZxu5qzbs40tgaFORiw2Amd0mirjxatXYMkIew==} @@ -4381,7 +4443,6 @@ packages: jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} - hasBin: true json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -4397,12 +4458,10 @@ packages: json5@1.0.2: resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} - hasBin: true json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} - hasBin: true jsx-ast-utils@3.3.5: resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} @@ -4417,7 +4476,6 @@ packages: lan-network@0.2.1: resolution: {integrity: sha512-ONPnazC96VKDntab9j9JKwIWhZ4ZUceB4A9Epu4Ssg0hYFmtHZSeQ+n15nIwTFmcBUKtExOer8WTJ4GF9MO64A==} - hasBin: true launder@1.7.1: resolution: {integrity: sha512-mU6WRz5EusL9ZZuiZ5SO4Y6C0P9PAUR9iwdb6bzj4KDihm28DiHFw+/yk9DBH4f+Pv1wuzQ4e2jV3oQ7mkIqvw==} @@ -4517,7 +4575,6 @@ packages: lint-staged@12.5.0: resolution: {integrity: sha512-BKLUjWDsKquV/JuIcoQW4MSAI3ggwEImF1+sB4zaKvyVx1wBk3FsG7UK9bpnmBTN1pm7EH2BBcMwINJzCRv12g==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - hasBin: true listr2@4.0.5: resolution: {integrity: sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA==} @@ -4572,7 +4629,6 @@ packages: loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true lowlight@1.20.0: resolution: {integrity: sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==} @@ -4587,6 +4643,11 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lucide-react@0.263.1: + resolution: {integrity: sha512-keqxAx97PlaEN89PXZ6ki1N8nRjGWtDa4021GFYLNj0RgruM5odbpl8GHTExj0hhPq3sF6Up0gnxt6TSHu+ovw==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 + make-dir@4.0.0: resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} engines: {node: '>=10'} @@ -4675,7 +4736,6 @@ packages: metro-symbolicate@0.84.4: resolution: {integrity: sha512-OnfpacxUqGPZQ27t8qK9mFa7uqHIlVWeqRqkCbvMvreEBiamEeOn8krKtcwgP5M4cYDPwuSmCTopHMVthqG4zA==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - hasBin: true metro-transform-plugins@0.84.4: resolution: {integrity: sha512-kehr6HbAecqD0/a3xLXobELdPaAmRAl8bel0qagPF4vhZtux93nS8S4eq2kgKt6J2GnQpVjSoW1PXdst04mwow==} @@ -4688,7 +4748,6 @@ packages: metro@0.84.4: resolution: {integrity: sha512-8ETTubqfD6ornDy2zYDvRcKnVDOXdFJsjetYDBsY4oAsb6NJkiwFR+FaMESyGppFmQUyBQA4H4sFGxzcQSGtFA==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - hasBin: true micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} @@ -4713,7 +4772,6 @@ packages: mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} - hasBin: true mimic-fn@1.2.0: resolution: {integrity: sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==} @@ -4759,7 +4817,6 @@ packages: mkdirp@1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} - hasBin: true morgan@1.11.0: resolution: {integrity: sha512-zSkVu3t18r39pw4ixfBKvfZi3y2UOqr7d4WYwcj3m8nXpEQK4rPO6GLzs/CExoRgmX3y9EjmmcXqv6jq0SK46g==} @@ -4777,7 +4834,6 @@ packages: nanoid@3.3.16: resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true napi-build-utils@2.0.0: resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} @@ -4785,7 +4841,6 @@ packages: napi-postinstall@0.3.4: resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - hasBin: true natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -4804,7 +4859,6 @@ packages: nitrogen@0.36.1: resolution: {integrity: sha512-0Q/YQLyE1/iNRNfSEl6vSqXUJEaQQv0GboWYan+Kiy5Vr6kE/F3CrKnvrnDcR6cgFeIYN++eON+Qn3djDVHYvQ==} - hasBin: true node-abi@3.94.0: resolution: {integrity: sha512-W5ZNO5KRPB5TkYmGVD9F6YqhsglXJzE6etpbmT+f6EQElhiX/UTG551cnsRGvLG3fyZEg9HwaDmNmj5nwJ4z9g==} @@ -5042,7 +5096,6 @@ packages: pidtree@0.5.0: resolution: {integrity: sha512-9nxspIM7OpZuhBxPg73Zvyq7j1QMPMPsGKTqRc2XOaFQauDvoNz9fM1Wdkjmeo7l9GXOZiRs97sPkuayl39wjA==} engines: {node: '>=0.10'} - hasBin: true pirates@4.0.7: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} @@ -5076,7 +5129,6 @@ packages: resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} engines: {node: '>=10'} deprecated: No longer maintained. Please contact the author of the relevant native addon; alternatives are available. - hasBin: true prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} @@ -5085,7 +5137,6 @@ packages: prettier@2.8.8: resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} engines: {node: '>=10.13.0'} - hasBin: true pretty-format@29.7.0: resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} @@ -5169,11 +5220,15 @@ packages: rc@1.2.8: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} - hasBin: true react-devtools-core@6.1.5: resolution: {integrity: sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==} + react-dom@19.2.8: + resolution: {integrity: sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==} + peerDependencies: + react: ^19.2.8 + react-freeze@1.0.4: resolution: {integrity: sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==} engines: {node: '>=10'} @@ -5333,7 +5388,6 @@ packages: react-native@0.86.0: resolution: {integrity: sha512-17ALh/dd6AO4pgOVmOO5Axll5PbErEo3XFyLokyzW6usyi+OShIEPwUW26wLPlhVifgSOIfECCH0WN+0IqtJ1w==} engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - hasBin: true peerDependencies: '@react-native/jest-preset': 0.86.0 '@types/react': ^19.1.1 @@ -5348,6 +5402,12 @@ packages: resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} engines: {node: '>=0.10.0'} + react-resizable-panels@4.12.2: + resolution: {integrity: sha512-NwY5LCo4WrxVvDh0xoMML6EMLPONP/8ckKcIdpnojxexoatZdjLiRqLJQjQK5CPkd4SYiB/2M5BVrjZBQtOO7Q==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + react-syntax-highlighter@16.1.1: resolution: {integrity: sha512-PjVawBGy80C6YbC5DDZJeUjBmC7skaoEUdvfFQediQHgCL7aKyVHe57SaJGfQsloGDac+gCpTfRdtxzWWKmCXA==} engines: {node: '>= 16.20.2'} @@ -5359,6 +5419,12 @@ packages: peerDependencies: react: ^19.2.3 + react-virtuoso@4.18.11: + resolution: {integrity: sha512-Qeeq9vqa5seCxACvzbQTUeq3s2/Bu+VlwOMF0jfy3E/ZKHLiXWwJpXBhv2rckqYkvm1XRVFLCBMCmqCU8JNEJg==} + peerDependencies: + react: '>=16 || >=17 || >= 18 || >= 19' + react-dom: '>=16 || >=17 || >= 18 || >=19' + react@19.2.3: resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} engines: {node: '>=0.10.0'} @@ -5401,7 +5467,6 @@ packages: regjsparser@0.13.2: resolution: {integrity: sha512-NgRBy2Nx/bE+9F27nVHnqcN5HjyLmecqsqx2PJHu3/IEtADD4WuxuXIVExD5PoSDFVrl78dOonfcOe5O+5nbzQ==} - hasBin: true require-directory@2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} @@ -5416,6 +5481,9 @@ packages: reselect@4.1.8: resolution: {integrity: sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==} + reselect@5.2.0: + resolution: {integrity: sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==} + resolve-cwd@3.0.0: resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} engines: {node: '>=8'} @@ -5441,12 +5509,10 @@ packages: resolve@1.22.12: resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} engines: {node: '>= 0.4'} - hasBin: true resolve@2.0.0-next.7: resolution: {integrity: sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==} engines: {node: '>= 0.4'} - hasBin: true restore-cursor@2.0.0: resolution: {integrity: sha512-6IzJLuGi4+R14vwagDHX+JrXmPVtPpn4mffDJ1UdR7/Edm87fl6yi8mMBIVvFtJaNTUvjughmW4hwLhRG7gC1Q==} @@ -5507,12 +5573,10 @@ packages: semver@6.3.1: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true semver@7.8.5: resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} - hasBin: true send@0.19.2: resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} @@ -5827,6 +5891,12 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + tailwind-merge@3.6.0: + resolution: {integrity: sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==} + + tailwindcss@4.2.2: + resolution: {integrity: sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==} + tar-fs@2.1.5: resolution: {integrity: sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==} @@ -5841,7 +5911,6 @@ packages: terser@5.49.0: resolution: {integrity: sha512-SNiDnXyHSrxVcIOtVbULzcTmniUiwcV7Nwdyj1twVubeTmbjoa8p69KKDpfkdoOavuM4/GRm1+ykI8qqnavHoA==} engines: {node: '>=10'} - hasBin: true test-exclude@6.0.0: resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} @@ -5897,6 +5966,9 @@ packages: tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + tw-animate-css@1.4.0: + resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -5940,7 +6012,6 @@ packages: typescript@6.0.3: resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} engines: {node: '>=14.17'} - hasBin: true unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} @@ -5986,7 +6057,6 @@ packages: update-browserslist-db@1.2.3: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} - hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -6019,7 +6089,6 @@ packages: uuid@7.0.3: resolution: {integrity: sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==} deprecated: uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028). - hasBin: true v8-to-istanbul@9.3.0: resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} @@ -6099,7 +6168,6 @@ packages: which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} - hasBin: true word-wrap@1.2.5: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} @@ -6188,7 +6256,6 @@ packages: yaml@2.9.0: resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} engines: {node: '>= 14.6'} - hasBin: true yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} @@ -7102,6 +7169,29 @@ snapshots: '@babel/helper-string-parser': 7.29.7 '@babel/helper-validator-identifier': 7.29.7 + '@base-ui/react@1.7.0(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.3))(react@19.2.3)': + dependencies: + '@babel/runtime': 7.29.7 + '@base-ui/utils': 0.3.2(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.3))(react@19.2.3) + '@floating-ui/react-dom': 2.1.9(react-dom@19.2.8(react@19.2.3))(react@19.2.3) + '@floating-ui/utils': 0.2.12 + react: 19.2.3 + react-dom: 19.2.8(react@19.2.3) + use-sync-external-store: 1.6.0(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.17 + + '@base-ui/utils@0.3.2(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.3))(react@19.2.3)': + dependencies: + '@babel/runtime': 7.29.7 + '@floating-ui/utils': 0.2.12 + react: 19.2.3 + react-dom: 19.2.8(react@19.2.3) + reselect: 5.2.0 + use-sync-external-store: 1.6.0(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.17 + '@bcoe/v8-coverage@0.2.3': {} '@callstack/react-theme-provider@3.0.9(react@19.2.3)': @@ -7256,7 +7346,7 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 - '@expo/cli@57.0.9(2d3b22c2103703c17c2fb47b72790f37)': + '@expo/cli@57.0.9(63ca68fcd1f3d0bd8b3ae037df52e0d5)': dependencies: '@expo/code-signing-certificates': 0.0.6 '@expo/config': 57.0.5(supports-color@9.4.0)(typescript@6.0.3) @@ -7275,7 +7365,7 @@ snapshots: '@expo/plist': 0.8.1 '@expo/prebuild-config': 57.0.8(supports-color@9.4.0)(typescript@6.0.3) '@expo/require-utils': 57.0.3(supports-color@9.4.0)(typescript@6.0.3) - '@expo/router-server': 57.0.3(expo-constants@57.0.6(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(supports-color@9.4.0))(expo-font@57.0.1(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3))(expo-server@57.0.1)(expo@57.0.7)(react@19.2.3)(supports-color@9.4.0) + '@expo/router-server': 57.0.3(expo-constants@57.0.6(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(supports-color@9.4.0))(expo-font@57.0.1(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3))(expo-server@57.0.1)(expo@57.0.7)(react-dom@19.2.8(react@19.2.3))(react@19.2.3)(supports-color@9.4.0) '@expo/schema-utils': 57.0.2 '@expo/spawn-async': 1.8.0 '@expo/ws-tunnel': 2.0.0(ws@8.21.1) @@ -7292,7 +7382,7 @@ snapshots: connect: 3.7.0(supports-color@9.4.0) debug: 4.4.3(supports-color@9.4.0) dnssd-advertise: 1.1.6 - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) expo-server: 57.0.1 fetch-nodeshim: 0.4.10 getenv: 2.0.0 @@ -7389,7 +7479,7 @@ snapshots: '@expo/dom-webview@57.0.1(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3)': dependencies: - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) react: 19.2.3 react-native: 0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0) @@ -7456,7 +7546,7 @@ snapshots: dependencies: '@expo/dom-webview': 57.0.1(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3) anser: 1.4.10 - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) react: 19.2.3 react-native: 0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0) stacktrace-parser: 0.1.11 @@ -7487,7 +7577,7 @@ snapshots: postcss: 8.5.19 resolve-from: 5.0.0 optionalDependencies: - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) transitivePeerDependencies: - bufferutil - supports-color @@ -7571,14 +7661,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@expo/router-server@57.0.3(expo-constants@57.0.6(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(supports-color@9.4.0))(expo-font@57.0.1(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3))(expo-server@57.0.1)(expo@57.0.7)(react@19.2.3)(supports-color@9.4.0)': + '@expo/router-server@57.0.3(expo-constants@57.0.6(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(supports-color@9.4.0))(expo-font@57.0.1(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3))(expo-server@57.0.1)(expo@57.0.7)(react-dom@19.2.8(react@19.2.3))(react@19.2.3)(supports-color@9.4.0)': dependencies: debug: 4.4.3(supports-color@9.4.0) - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) expo-constants: 57.0.6(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(supports-color@9.4.0) expo-font: 57.0.1(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3) expo-server: 57.0.1 react: 19.2.3 + optionalDependencies: + react-dom: 19.2.8(react@19.2.3) transitivePeerDependencies: - supports-color @@ -7611,6 +7703,23 @@ snapshots: chalk: 4.1.2 js-yaml: 4.3.0 + '@floating-ui/core@1.8.0': + dependencies: + '@floating-ui/utils': 0.2.12 + + '@floating-ui/dom@1.8.0': + dependencies: + '@floating-ui/core': 1.8.0 + '@floating-ui/utils': 0.2.12 + + '@floating-ui/react-dom@2.1.9(react-dom@19.2.8(react@19.2.3))(react@19.2.3)': + dependencies: + '@floating-ui/dom': 1.8.0 + react: 19.2.3 + react-dom: 19.2.8(react@19.2.3) + + '@floating-ui/utils@0.2.12': {} + '@gorhom/bottom-sheet@5.2.14(24fcb93f20601afa4f41878e40cdc0fb)': dependencies: '@gorhom/portal': 1.0.14(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3) @@ -7858,11 +7967,12 @@ snapshots: dependencies: jsbi: 4.3.2 - '@legendapp/list@3.3.3(patch_hash=37a9c8d7d9c1bd33c957ba6ea78291c7b08532dc32de4925f3d612cb41f1a659)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3)': + '@legendapp/list@3.3.3(patch_hash=37a9c8d7d9c1bd33c957ba6ea78291c7b08532dc32de4925f3d612cb41f1a659)(react-dom@19.2.8(react@19.2.3))(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3)': dependencies: react: 19.2.3 use-sync-external-store: 1.6.0(react@19.2.3) optionalDependencies: + react-dom: 19.2.8(react@19.2.3) react-native: 0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0) '@material/material-color-utilities@0.3.0': {} @@ -7887,7 +7997,7 @@ snapshots: dependencies: '@material/material-color-utilities': 0.3.0 color: 4.2.3 - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) react: 19.2.3 react-native: 0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0) @@ -7901,7 +8011,7 @@ snapshots: react: 19.2.3 react-native: 0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0) optionalDependencies: - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) '@react-native-vector-icons/common@13.0.1(@react-native/assets-registry@0.86.0)(expo-font@57.0.1(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3))(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3)': dependencies: @@ -8148,10 +8258,21 @@ snapshots: react: 19.2.3 tslib: 2.8.1 + '@rozenite/agent-bridge@2.0.0(react@19.2.3)': + dependencies: + '@rozenite/agent-shared': 2.0.0 + '@rozenite/plugin-bridge': 2.0.0(react@19.2.3) + react: 19.2.3 + tslib: 2.8.1 + '@rozenite/agent-shared@1.13.0': dependencies: tslib: 2.8.1 + '@rozenite/agent-shared@2.0.0': + dependencies: + tslib: 2.8.1 + '@rozenite/expo-atlas-plugin@1.13.0(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0)': dependencies: '@rozenite/plugin-bridge': 1.13.0(react@19.2.3) @@ -8192,6 +8313,26 @@ snapshots: react: 19.2.3 tslib: 2.8.1 + '@rozenite/plugin-bridge@2.0.0(react@19.2.3)': + dependencies: + react: 19.2.3 + tslib: 2.8.1 + + '@rozenite/react-navigation-plugin@2.0.0(@react-navigation/core@7.21.8(react@19.2.3))(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.3))(react@19.2.3)': + dependencies: + '@react-navigation/core': 7.21.8(react@19.2.3) + '@rozenite/agent-bridge': 2.0.0(react@19.2.3) + '@rozenite/agent-shared': 2.0.0 + '@rozenite/plugin-bridge': 2.0.0(react@19.2.3) + '@rozenite/ui': 2.0.0(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.3))(react@19.2.3) + fast-deep-equal: 3.1.3 + transitivePeerDependencies: + - '@date-fns/tz' + - '@types/react' + - date-fns + - react + - react-dom + '@rozenite/runtime@1.13.0': dependencies: tslib: 2.8.1 @@ -8205,6 +8346,26 @@ snapshots: '@rozenite/tools@1.13.0': {} + '@rozenite/ui@2.0.0(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.3))(react@19.2.3)': + dependencies: + '@base-ui/react': 1.7.0(@types/react@19.2.17)(react-dom@19.2.8(react@19.2.3))(react@19.2.3) + '@tanstack/react-table': 8.21.3(react-dom@19.2.8(react@19.2.3))(react@19.2.3) + class-variance-authority: 0.7.1 + clsx: 2.1.1 + lucide-react: 0.263.1(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.8(react@19.2.3) + react-resizable-panels: 4.12.2(react-dom@19.2.8(react@19.2.3))(react@19.2.3) + react-virtuoso: 4.18.11(react-dom@19.2.8(react@19.2.3))(react@19.2.3) + tailwind-merge: 3.6.0 + tailwindcss: 4.2.2 + tslib: 2.8.1 + tw-animate-css: 1.4.0 + transitivePeerDependencies: + - '@date-fns/tz' + - '@types/react' + - date-fns + '@rtsao/scc@1.1.0': {} '@sinclair/typebox@0.27.12': {} @@ -8219,6 +8380,14 @@ snapshots: dependencies: '@sinonjs/commons': 3.0.1 + '@tanstack/react-table@8.21.3(react-dom@19.2.8(react@19.2.3))(react@19.2.3)': + dependencies: + '@tanstack/table-core': 8.21.3 + react: 19.2.3 + react-dom: 19.2.8(react@19.2.3) + + '@tanstack/table-core@8.21.3': {} + '@testing-library/react-native@13.3.3(jest@29.7.0(@types/node@26.1.1)(supports-color@9.4.0))(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react-test-renderer@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: jest-matcher-utils: 30.4.1 @@ -8889,7 +9058,7 @@ snapshots: react-refresh: 0.14.2 optionalDependencies: '@babel/runtime': 7.29.7 - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) transitivePeerDependencies: - '@babel/core' - supports-color @@ -9113,6 +9282,10 @@ snapshots: cjs-module-lexer@1.4.3: {} + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + clean-stack@2.2.0: {} cli-cursor@2.1.0: @@ -9149,6 +9322,8 @@ snapshots: clone@1.0.4: {} + clsx@2.1.1: {} + co@4.6.0: {} code-block-writer@13.0.3: {} @@ -9920,7 +10095,7 @@ snapshots: expo-asset@57.0.6(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0)(typescript@6.0.3): dependencies: '@expo/image-utils': 0.11.3(supports-color@9.4.0)(typescript@6.0.3) - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) expo-constants: 57.0.6(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(supports-color@9.4.0) react: 19.2.3 react-native: 0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0) @@ -9935,7 +10110,7 @@ snapshots: chalk: 4.1.2 compression: 1.8.1(supports-color@9.4.0) connect: 3.7.0(supports-color@9.4.0) - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) express: 4.22.2(supports-color@9.4.0) freeport-async: 2.0.0 getenv: 2.0.0 @@ -9949,27 +10124,27 @@ snapshots: expo-build-properties@57.0.6(expo@57.0.7): dependencies: '@expo/schema-utils': 57.0.2 - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) resolve-from: 5.0.0 semver: 7.8.5 expo-clipboard@57.0.1(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3): dependencies: - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) react: 19.2.3 react-native: 0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0) expo-constants@57.0.6(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(supports-color@9.4.0): dependencies: '@expo/env': 2.4.2(supports-color@9.4.0) - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) react-native: 0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0) transitivePeerDependencies: - supports-color expo-dev-client@57.0.7(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0)): dependencies: - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) expo-dev-launcher: 57.0.7(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0)) expo-dev-menu: 57.0.7(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0)) expo-dev-menu-interface: 57.0.0(expo@57.0.7) @@ -9981,44 +10156,44 @@ snapshots: expo-dev-launcher@57.0.7(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0)): dependencies: '@expo/schema-utils': 57.0.2 - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) expo-dev-menu: 57.0.7(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0)) expo-manifests: 57.0.1(expo@57.0.7) react-native: 0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0) expo-dev-menu-interface@57.0.0(expo@57.0.7): dependencies: - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) expo-dev-menu@57.0.7(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0)): dependencies: - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) expo-dev-menu-interface: 57.0.0(expo@57.0.7) react-native: 0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0) expo-document-picker@57.0.1(expo@57.0.7): dependencies: - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) expo-file-system@57.0.1(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0)): dependencies: - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) react-native: 0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0) expo-font@57.0.1(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3): dependencies: - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) fontfaceobserver: 2.3.0 react: 19.2.3 react-native: 0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0) expo-haptics@57.0.1(expo@57.0.7): dependencies: - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) expo-image@57.0.1(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3): dependencies: - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) react: 19.2.3 react-native: 0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0) sf-symbols-typescript: 2.2.0 @@ -10027,12 +10202,12 @@ snapshots: expo-keep-awake@57.0.1(expo@57.0.7)(react@19.2.3): dependencies: - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) react: 19.2.3 expo-linear-gradient@57.0.1(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3): dependencies: - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) react: 19.2.3 react-native: 0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0) @@ -10048,13 +10223,13 @@ snapshots: expo-localization@57.0.1(expo@57.0.7)(react@19.2.3): dependencies: - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) react: 19.2.3 rtl-detect: 1.1.2 expo-manifests@57.0.1(expo@57.0.7): dependencies: - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) expo-json-utils: 57.0.1 expo-modules-autolinking@57.0.8(supports-color@9.4.0)(typescript@6.0.3): @@ -10084,7 +10259,7 @@ snapshots: expo-navigation-bar@57.0.2(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0): dependencies: debug: 4.4.3(supports-color@9.4.0) - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) react: 19.2.3 react-native: 0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0) transitivePeerDependencies: @@ -10094,13 +10269,13 @@ snapshots: expo-speech@57.0.1(expo@57.0.7): dependencies: - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) expo-splash-screen@57.0.4(expo@57.0.7)(supports-color@9.4.0)(typescript@6.0.3): dependencies: '@expo/config-plugins': 57.0.5(supports-color@9.4.0)(typescript@6.0.3) '@expo/image-utils': 0.11.3(supports-color@9.4.0)(typescript@6.0.3) - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) xml2js: 0.6.0 transitivePeerDependencies: - supports-color @@ -10108,17 +10283,17 @@ snapshots: expo-updates-interface@57.0.1(expo@57.0.7): dependencies: - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) expo-web-browser@57.0.1(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0)): dependencies: - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) react-native: 0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0) - expo@57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213): + expo@57.0.7(b68ae321bfe3a8002856ab9a07fab30e): dependencies: '@babel/runtime': 7.29.7 - '@expo/cli': 57.0.9(2d3b22c2103703c17c2fb47b72790f37) + '@expo/cli': 57.0.9(63ca68fcd1f3d0bd8b3ae037df52e0d5) '@expo/config': 57.0.5(supports-color@9.4.0)(typescript@6.0.3) '@expo/config-plugins': 57.0.5(supports-color@9.4.0)(typescript@6.0.3) '@expo/devtools': 57.0.1(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3) @@ -10143,6 +10318,7 @@ snapshots: whatwg-url-minimum: 0.1.2 optionalDependencies: '@expo/dom-webview': 57.0.1(expo@57.0.7)(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3) + react-dom: 19.2.8(react@19.2.3) react-native-webview: 13.17.0(react-native@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(@react-native/jest-preset@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(react@19.2.3)(supports-color@9.4.0))(@react-native/metro-config@0.86.0(@babel/core@7.29.7(supports-color@9.4.0))(supports-color@9.4.0))(@types/react@19.2.17)(react@19.2.3)(supports-color@9.4.0))(react@19.2.3) transitivePeerDependencies: - '@babel/core' @@ -11021,7 +11197,7 @@ snapshots: server-only: 0.0.1 stacktrace-js: 2.0.2 optionalDependencies: - expo: 57.0.7(09a92d6f4cb27d968ea2a7d0b76b3213) + expo: 57.0.7(b68ae321bfe3a8002856ab9a07fab30e) transitivePeerDependencies: - '@babel/core' - bufferutil @@ -11495,6 +11671,10 @@ snapshots: dependencies: yallist: 3.1.1 + lucide-react@0.263.1(react@19.2.3): + dependencies: + react: 19.2.3 + make-dir@4.0.0: dependencies: semver: 7.8.5 @@ -12190,6 +12370,11 @@ snapshots: - bufferutil - utf-8-validate + react-dom@19.2.8(react@19.2.3): + dependencies: + react: 19.2.3 + scheduler: 0.27.0 + react-freeze@1.0.4(react@19.2.3): dependencies: react: 19.2.3 @@ -12407,6 +12592,11 @@ snapshots: react-refresh@0.14.2: {} + react-resizable-panels@4.12.2(react-dom@19.2.8(react@19.2.3))(react@19.2.3): + dependencies: + react: 19.2.3 + react-dom: 19.2.8(react@19.2.3) + react-syntax-highlighter@16.1.1(react@19.2.3): dependencies: '@babel/runtime': 7.29.7 @@ -12423,6 +12613,11 @@ snapshots: react-is: 19.2.7 scheduler: 0.27.0 + react-virtuoso@4.18.11(react-dom@19.2.8(react@19.2.3))(react@19.2.3): + dependencies: + react: 19.2.3 + react-dom: 19.2.8(react@19.2.3) + react@19.2.3: {} readable-stream@3.6.2: @@ -12496,6 +12691,8 @@ snapshots: reselect@4.1.8: {} + reselect@5.2.0: {} + resolve-cwd@3.0.0: dependencies: resolve-from: 5.0.0 @@ -12970,6 +13167,10 @@ snapshots: symbol-tree@3.2.4: {} + tailwind-merge@3.6.0: {} + + tailwindcss@4.2.2: {} + tar-fs@2.1.5: dependencies: chownr: 1.1.4 @@ -13055,6 +13256,8 @@ snapshots: dependencies: safe-buffer: 5.2.1 + tw-animate-css@1.4.0: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 diff --git a/src/components/NovelList.tsx b/src/components/NovelList.tsx index 7b59959f..118ac389 100644 --- a/src/components/NovelList.tsx +++ b/src/components/NovelList.tsx @@ -54,14 +54,6 @@ export const extendNovelList = ( } } - extension.push({ - id: undefined, - cover: '', - name: '', - path: '__loading-row', - completeRow: 2, - }); - return [...data, ...extension]; }; diff --git a/src/components/__tests__/NovelList.test.ts b/src/components/__tests__/NovelList.test.ts index 802e986b..844ea1ff 100644 --- a/src/components/__tests__/NovelList.test.ts +++ b/src/components/__tests__/NovelList.test.ts @@ -59,7 +59,6 @@ describe('NovelList helpers', () => { '/two', '__loading-filler-0', '__loading-filler-1', - '__loading-row', ]); }); }); diff --git a/src/hooks/persisted/useNovel/__tests__/novelStore.chapterActions.test.ts b/src/hooks/persisted/useNovel/__tests__/novelStore.chapterActions.test.ts index 5dded9fa..94384a39 100644 --- a/src/hooks/persisted/useNovel/__tests__/novelStore.chapterActions.test.ts +++ b/src/hooks/persisted/useNovel/__tests__/novelStore.chapterActions.test.ts @@ -326,6 +326,10 @@ describe('novelStore.chapterActions', () => { ); const request = harness.actions.loadUpToBatch(1); + // The store action defers the batched read to the idle callback (a + // macrotask in the test environment); let that tick run so the mocked + // load starts before the generation is invalidated. + await new Promise(resolve => setTimeout(resolve, 0)); harness.chapterRequestCoordinator.invalidate(); resolveLoad(); await request; diff --git a/src/hooks/persisted/useNovel/store/novelStore.chapterActions.ts b/src/hooks/persisted/useNovel/store/novelStore.chapterActions.ts index e1d3b5d6..90d5a23a 100644 --- a/src/hooks/persisted/useNovel/store/novelStore.chapterActions.ts +++ b/src/hooks/persisted/useNovel/store/novelStore.chapterActions.ts @@ -1,5 +1,6 @@ import { ChapterFilterKey, ChapterOrderKey } from '@database/constants'; import { ChapterInfo } from '@database/types'; +import { runWhenIdle } from '@utils/runWhenIdle'; import { createBootstrapService } from '../store-helper/bootstrapService'; import { bookmarkChaptersAction, @@ -154,6 +155,11 @@ export const createNovelStoreChapterActions = ({ continue; } + // Same deferral as getNextChapterBatch: the batched reads are + // synchronous 1000-row materialisations that must not run mid-scroll. + await new Promise(resolve => { + runWhenIdle(() => resolve(), 1000); + }); await bootstrapService.loadUpToBatch({ targetBatch: nextTarget, novel: state.novel, @@ -192,6 +198,13 @@ export const createNovelStoreChapterActions = ({ promise: Promise.resolve(), }; request.promise = (async () => { + // The batched read materialises up to 1000 chapter rows on the JS + // thread synchronously; running it inside the scroll callback stalls + // the list at every batch boundary on novels with >1000 chapters + // (measured frame drops). Defer it until the thread is idle. + await new Promise(resolve => { + runWhenIdle(() => resolve(), 1000); + }); const result = await bootstrapService.getNextChapterBatch({ novel: state.novel, pages: state.pages, diff --git a/src/navigators/Main.tsx b/src/navigators/Main.tsx index 65a76aab..ca1165b0 100644 --- a/src/navigators/Main.tsx +++ b/src/navigators/Main.tsx @@ -1,4 +1,4 @@ -import { useEffect } from 'react'; +import { useEffect, useRef } from 'react'; import { DefaultTheme, NavigationContainer } from '@react-navigation/native'; import { createNativeStackNavigator } from '@react-navigation/native-stack'; @@ -38,6 +38,7 @@ import { backgroundTasks } from '@services/backgroundTasks'; import ReaderStack from './ReaderStack'; import { LibraryContextProvider } from '@components/Context/LibraryContext'; import { UpdateContextProvider } from '@components/Context/UpdateContext'; +import { useReactNavigationDevTools } from '@rozenite/react-navigation-plugin'; const Stack = createNativeStackNavigator(); const MainNavigator = () => { @@ -67,12 +68,17 @@ const MainNavigator = () => { } }, [isOnboarded, refreshPlugins, updateLibraryOnLaunch]); + const navigationRef = useRef(null); + + // Enable React Navigation DevTools in development + useReactNavigationDevTools({ ref: navigationRef }); + if (!isOnboarded) { return ; } - return ( + ref={navigationRef} theme={{ colors: { ...DefaultTheme.colors, diff --git a/src/screens/BrowseSourceScreen/BrowseSourceScreen.tsx b/src/screens/BrowseSourceScreen/BrowseSourceScreen.tsx index 217f3816..2bfa6619 100644 --- a/src/screens/BrowseSourceScreen/BrowseSourceScreen.tsx +++ b/src/screens/BrowseSourceScreen/BrowseSourceScreen.tsx @@ -85,6 +85,50 @@ const BrowseSourceScreen = ({ route, navigation }: BrowseSourceScreenProps) => { const { bottom, right } = useSafeAreaInsets(); const filterSheetRef = useRef(null); + const lastFetchDistanceRef = useRef(Infinity); + const lastContentHeightRef = useRef(0); + const lastOffsetYRef = useRef(-1); + const handleScroll = (event: { + nativeEvent: { + contentOffset: { y: number }; + contentSize: { height: number }; + layoutMeasurement: { height: number }; + }; + }) => { + const { contentOffset, contentSize, layoutMeasurement } = event.nativeEvent; + const distanceFromEnd = + contentSize.height - (contentOffset.y + layoutMeasurement.height); + const offsetMoved = contentOffset.y !== lastOffsetYRef.current; + lastOffsetYRef.current = contentOffset.y; + + // A page appended (the end moved away). Re-arm the gate so the next user + // scroll toward the end fetches again. Content-size-only events (offset + // unchanged) never fetch on their own — that is what turned the old + // onEndReached flow into a loop on sources that never return an empty + // page (measured: htmlparser2 hot on every frame). + if (contentSize.height !== lastContentHeightRef.current) { + lastContentHeightRef.current = contentSize.height; + if (offsetMoved) { + lastFetchDistanceRef.current = Infinity; + } + } + if (!offsetMoved) { + return; + } + if ( + distanceFromEnd < layoutMeasurement.height * 1.5 && + distanceFromEnd < lastFetchDistanceRef.current + ) { + lastFetchDistanceRef.current = distanceFromEnd; + if (searchText) { + if (hasNextSearchPage) { + searchNextPage(); + } + } else if (hasNextPage) { + fetchNextPage(); + } + } + }; return ( { + ) : null + } renderItem={({ item }) => { const inLibrary = novelInLibrary(pluginId, item.path); @@ -148,16 +198,8 @@ const BrowseSourceScreen = ({ route, navigation }: BrowseSourceScreenProps) => { /> ); }} - onEndReached={() => { - if (searchText) { - if (hasNextSearchPage) { - searchNextPage(); - } - } else if (hasNextPage) { - fetchNextPage(); - } - }} - onEndReachedThreshold={1.5} + onScroll={handleScroll} + scrollEventThrottle={32} /> )} {!showLatestNovels && filterValues && !searchText ? ( diff --git a/src/screens/BrowseSourceScreen/useBrowseSource.ts b/src/screens/BrowseSourceScreen/useBrowseSource.ts index 283eeb97..395fc2a9 100644 --- a/src/screens/BrowseSourceScreen/useBrowseSource.ts +++ b/src/screens/BrowseSourceScreen/useBrowseSource.ts @@ -23,44 +23,84 @@ export const useBrowseSource = ( const isScreenMounted = useRef(true); + // Serialize page fetches: onEndReached bursts (threshold 1.5 with a short + // list) can bump currentPage several times before the first request settles. + // Without a queue, that spawns concurrent out-of-order page fetches — each + // append re-renders the whole grid and remounts the "loading more" shimmer + // cells, which reads as stutter while scrolling the source list. + const fetchQueueRef = useRef>(Promise.resolve()); + // Bumped whenever the list is reset to page 1 (refetch, filters); queued + // fetches from an older generation are discarded so they cannot append + // stale pages onto a fresh list. + const generationRef = useRef(0); + // Highest page whose items are in the list, and highest page requested. + // `fetchNextPage` always asks for `lastLoaded + 1`, so a failed/empty + // fetch is retried on the next approach instead of being skipped past. + const lastLoadedPageRef = useRef(0); + const requestedPageRef = useRef(1); + const fetchNovels = useCallback( - async (page: number, filters?: FilterToValues) => { - if (isScreenMounted.current === true) { + (page: number, filters?: FilterToValues) => { + const run = async () => { + if (!isScreenMounted.current) { + return; + } + const generation = generationRef.current; try { const plugin = getPlugin(pluginId); if (!plugin) { throw new Error(`Unknown plugin: ${pluginId}`); } - await plugin - .popularNovels(page, { - showLatestNovels, - filters, - }) - .then(res => { - setNovels(prevState => - page === 1 ? res : [...prevState, ...res], - ); - if (!res.length) { - setHasNextPage(false); - } - }) - .catch(e => { - setError(e.message); - setHasNextPage(false); - }); + const res = await plugin.popularNovels(page, { + showLatestNovels, + filters, + }); + if (generation !== generationRef.current) { + return; + } + setNovels(prevState => (page === 1 ? res : [...prevState, ...res])); + lastLoadedPageRef.current = Math.max(lastLoadedPageRef.current, page); + if (!res.length) { + setHasNextPage(false); + } setFilterValues(plugin.filters); } catch (err: unknown) { - setError(`${err}`); + if (generation !== generationRef.current) { + return; + } + setError(err instanceof Error ? err.message : `${err}`); + // A failed page fetch must not permanently end the list: sources + // rate-limit and transient network errors are common, and once + // `hasNextPage` flips false nothing ever retries (the screen stays + // mounted behind the reader, so the dead state persists even after + // navigating away and back). Un-request the failed page so the next + // approach retries it; only a successful empty response marks the end. + requestedPageRef.current = Math.min( + requestedPageRef.current, + page - 1, + ); } finally { - setIsLoading(false); + if (generation === generationRef.current) { + setIsLoading(false); + } } - } + }; + fetchQueueRef.current = fetchQueueRef.current.then(run, run); + return fetchQueueRef.current; }, [pluginId, showLatestNovels], ); const fetchNextPage = () => { - if (hasNextPage) setCurrentPage(prevState => prevState + 1); + if (!hasNextPage) { + return; + } + const next = lastLoadedPageRef.current + 1; + if (next <= requestedPageRef.current) { + return; + } + requestedPageRef.current = next; + void fetchNovels(next, selectedFilters); }; /** @@ -73,15 +113,17 @@ export const useBrowseSource = ( }, []); useEffect(() => { - // eslint-disable-next-line react-hooks/set-state-in-effect fetchNovels(currentPage, selectedFilters); }, [fetchNovels, currentPage, selectedFilters]); const refetchNovels = () => { + generationRef.current += 1; setError(''); setIsLoading(true); setNovels([]); setCurrentPage(1); + lastLoadedPageRef.current = 0; + requestedPageRef.current = 1; fetchNovels(1, selectedFilters); }; @@ -91,8 +133,11 @@ export const useBrowseSource = ( ); const setFilters = (filters?: FilterToValues) => { + generationRef.current += 1; setIsLoading(true); setCurrentPage(1); + lastLoadedPageRef.current = 0; + requestedPageRef.current = 1; fetchNovels(1, filters); setSelectedFilters(filters); }; @@ -119,48 +164,89 @@ export const useSearchSource = (pluginId: string) => { const [searchText, setSearchText] = useState(''); const searchSource = (searchTerm: string) => { + searchGenerationRef.current += 1; setSearchResults([]); setHasNextSearchPage(true); setCurrentPage(1); + lastLoadedPageRef.current = 0; + requestedPageRef.current = 1; setSearchText(searchTerm); setIsSearching(true); }; const isScreenMounted = useRef(true); + // Serialize page fetches — see useBrowseSource.fetchNovels for why. + const fetchQueueRef = useRef>(Promise.resolve()); + // Bumped whenever a new search starts; queued fetches from a previous + // search are discarded so they cannot append stale results onto a new one. + const searchGenerationRef = useRef(0); + // Same last-loaded/requested page tracking as useBrowseSource so failed + // pages are retried instead of skipped. + const lastLoadedPageRef = useRef(0); + const requestedPageRef = useRef(1); + const fetchNovels = useCallback( - async (localSearchText: string, page: number) => { - if (isScreenMounted.current === true) { + (localSearchText: string, page: number) => { + const run = async () => { + if (!isScreenMounted.current) { + return; + } + const generation = searchGenerationRef.current; try { const plugin = getPlugin(pluginId); if (!plugin) { throw new Error(`Unknown plugin: ${pluginId}`); } const res = await plugin.searchNovels(localSearchText, page); + if (generation !== searchGenerationRef.current) { + return; + } setSearchResults(prevState => page === 1 ? res : [...prevState, ...res], ); + lastLoadedPageRef.current = Math.max(lastLoadedPageRef.current, page); if (!res.length) { setHasNextSearchPage(false); } } catch (err: unknown) { + if (generation !== searchGenerationRef.current) { + return; + } setSearchError(`${err}`); - setHasNextSearchPage(false); + // See fetchNovels: a transient failure must not permanently end + // pagination; un-request the failed page so the next approach + // retries it. + requestedPageRef.current = Math.min( + requestedPageRef.current, + page - 1, + ); } finally { - setIsSearching(false); + if (generation === searchGenerationRef.current) { + setIsSearching(false); + } } - } + }; + fetchQueueRef.current = fetchQueueRef.current.then(run, run); + return fetchQueueRef.current; }, [pluginId], ); const searchNextPage = () => { - if (hasNextSearchPage) setCurrentPage(prevState => prevState + 1); + if (!hasNextSearchPage) { + return; + } + const next = lastLoadedPageRef.current + 1; + if (next <= requestedPageRef.current) { + return; + } + requestedPageRef.current = next; + void fetchNovels(searchText, next); }; useEffect(() => { if (searchText) { - // eslint-disable-next-line react-hooks/set-state-in-effect fetchNovels(searchText, currentPage); } }, [currentPage, fetchNovels, searchText]); @@ -170,6 +256,8 @@ export const useSearchSource = (pluginId: string) => { setSearchResults([]); setCurrentPage(1); setHasNextSearchPage(true); + lastLoadedPageRef.current = 0; + requestedPageRef.current = 1; }, []); return { diff --git a/src/screens/browse/loadingAnimation/SourceScreenSkeletonLoading.tsx b/src/screens/browse/loadingAnimation/SourceScreenSkeletonLoading.tsx index 55a7c9e8..d91da55d 100644 --- a/src/screens/browse/loadingAnimation/SourceScreenSkeletonLoading.tsx +++ b/src/screens/browse/loadingAnimation/SourceScreenSkeletonLoading.tsx @@ -77,7 +77,11 @@ const SourceScreenSkeletonLoading: React.FC = ({ return renderLoadingNovel(completeRow); } - if (displayMode === DisplayModes.List) { + // completeRow === 2: a single full-width trailing row (rendered as the + // list footer), not a screen-filling grid. + if (completeRow === 2) { + items = [1]; + } else if (displayMode === DisplayModes.List) { items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; } else { for (let i = 1; i * pictureHeight < window.height - 100; i++) { diff --git a/src/screens/novel/NovelContext.tsx b/src/screens/novel/NovelContext.tsx index 8377ca3c..08c3beb5 100644 --- a/src/screens/novel/NovelContext.tsx +++ b/src/screens/novel/NovelContext.tsx @@ -1,4 +1,10 @@ -import React, { createContext, useContext, useEffect, useMemo } from 'react'; +import React, { + createContext, + useContext, + useEffect, + useMemo, + useRef, +} from 'react'; import { RouteProp } from '@react-navigation/native'; import { useStore } from 'zustand'; import { ReaderStackParamList } from '@navigators/types'; @@ -30,11 +36,24 @@ const NovelStoreContext = createContext(null); const NovelLayoutContext = createContext(null); export function NovelContextProvider({ children, route }: Props) { + const params = (route.params ?? {}) as { + novel?: { path: string; pluginId: string }; + path?: string; + pluginId?: string; + id?: number; + }; const initialNovel = - 'id' in route.params ? (route.params as NovelInfo) : undefined; + params.id !== undefined ? (params as unknown as NovelInfo) : undefined; - const { path, pluginId } = - 'novel' in route.params ? route.params.novel : route.params; + // The ReaderStack's route can carry Chapter-shaped params ({ novel, + // chapter }) or a stale first-mount params object (ReaderStack.tsx falls + // back to `useRef`'d params while a transition leaves `route.params` + // momentarily nullish). Guard both the key and the value: a malformed + // params object must degrade to the path-based bootstrap instead of + // throwing while reading `.path` off `undefined` (measured: "Cannot read + // property 'path' of undefined" when opening a novel from the library + // after a plugin open). + const { path = '', pluginId = '' } = params.novel ?? params; const { switchNovelToLibrary } = useLibraryContext(); const { defaultChapterSort } = useAppSettings(); @@ -58,6 +77,26 @@ export function NovelContextProvider({ children, route }: Props) { } }, [novelStore]); + const gcHandleRef = useRef<{ cancel: () => void } | null>(null); + useEffect(() => { + // A new novel screen mounted; drop any reclaim still pending from the + // previous one so the collection cannot pause this screen's bootstrap. + gcHandleRef.current?.cancel(); + gcHandleRef.current = null; + return () => { + // The store (full chapter list) and the fetch/parse garbage from an + // uncached bootstrap are released here. Hermes' concurrent GC only runs + // on allocation pressure, so without a nudge the dead objects sit in the + // heap and the heap cap ratchets up with every novel opened — the GC + // cost of scrolling then grows until the app is restarted (measured: + // +5 MB of collectible garbage per uncached open; forced GC dropped the + // cap 54.5 MB -> 50.3 MB). Reclaim after the pop transition finishes + // (~300 ms) so the collection cannot hitch the animation. + const timer = setTimeout(() => globalThis.gc?.(), 600); + gcHandleRef.current = { cancel: () => clearTimeout(timer) }; + }; + }, []); + const { bottom, top } = useSafeAreaInsets(); const layoutValue = useMemo( diff --git a/src/screens/novel/components/NovelScreenList.tsx b/src/screens/novel/components/NovelScreenList.tsx index 02573f24..cd90d051 100644 --- a/src/screens/novel/components/NovelScreenList.tsx +++ b/src/screens/novel/components/NovelScreenList.tsx @@ -5,7 +5,13 @@ import { useCallback, useMemo, useRef, useState } from 'react'; import { ChapterInfo, NovelInfo } from '@database/types'; import { useAppSettings, useDownload, useTheme } from '@hooks/persisted'; import { getString } from '@i18n/translations'; -import { RefreshControl, useWindowDimensions, View } from 'react-native'; +import { + type NativeScrollEvent, + type NativeSyntheticEvent, + RefreshControl, + useWindowDimensions, + View, +} from 'react-native'; import { runOnJS, SharedValue, @@ -19,8 +25,7 @@ import PageNavigationBottomSheet from './PageNavigationBottomSheet'; import * as Haptics from 'expo-haptics'; import { ChapterListSkeleton } from '@components/Skeleton/Skeleton'; import { BottomSheetModalMethods } from '@gorhom/bottom-sheet/lib/typescript/types'; -import { LegendListRef } from '@legendapp/list/react-native'; -import { AnimatedLegendList } from '@legendapp/list/reanimated'; +import { LegendList, LegendListRef } from '@legendapp/list/react-native'; import PagePaginationControl from './PagePaginationControl'; import { useNovelActions, useNovelValue } from '../NovelContext'; import { UseBooleanReturnType } from '@hooks/index'; @@ -166,7 +171,12 @@ const NovelScreenList = ({ [headerOpacity, lastRead, screenHeight, useFabForContinueReading], ); - const listSharedValues = useMemo(() => ({ scrollOffset }), [scrollOffset]); + const scrollHandler = useCallback( + (event: NativeSyntheticEvent) => { + scrollOffset.value = event.nativeEvent.contentOffset.y; + }, + [scrollOffset], + ); // --- Stable callbacks --- @@ -411,7 +421,7 @@ const NovelScreenList = ({ return ( <> - diff --git a/src/screens/novel/components/__tests__/NovelScreenList.test.tsx b/src/screens/novel/components/__tests__/NovelScreenList.test.tsx index 17966f0c..5e048007 100644 --- a/src/screens/novel/components/__tests__/NovelScreenList.test.tsx +++ b/src/screens/novel/components/__tests__/NovelScreenList.test.tsx @@ -45,12 +45,12 @@ jest.mock('react-native-safe-area-context', () => ({ useSafeAreaInsets: () => ({ top: 0, bottom: 0 }), })); -jest.mock('@legendapp/list/reanimated', () => { +jest.mock('@legendapp/list/react-native', () => { const React = require('react'); const { View } = require('react-native'); return { - AnimatedLegendList: ({ data, renderItem, ListHeaderComponent }: any) => + LegendList: ({ data, renderItem, ListHeaderComponent }: any) => React.createElement( View, null, @@ -63,6 +63,7 @@ jest.mock('@legendapp/list/reanimated', () => { ), ), ), + LegendListRef: {}, }; });