From e7abbcd5cb86dbb3b82ecc27e2c777f6ef45f9d4 Mon Sep 17 00:00:00 2001 From: Chai Date: Tue, 18 Aug 2026 19:18:44 -0400 Subject: [PATCH 1/3] fix(mobile): restore chat height after keyboard dismiss --- package.json | 1 + .../src/screens/chat-keyboard-layout.test.ts | 24 ++++++++++++++++++- ...ct-native-keyboard-controller@1.18.5.patch | 24 +++++++++++++++++++ pnpm-lock.yaml | 7 ++++-- 4 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 patches/react-native-keyboard-controller@1.18.5.patch diff --git a/package.json b/package.json index e596e59c8..e182c2ea1 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ }, "patchedDependencies": { "@langchain/core": "patches/@langchain__core.patch", + "react-native-keyboard-controller@1.18.5": "patches/react-native-keyboard-controller@1.18.5.patch", "react-native-track-player@4.1.2": "patches/react-native-track-player@4.1.2.patch" } }, diff --git a/packages/app-expo/src/screens/chat-keyboard-layout.test.ts b/packages/app-expo/src/screens/chat-keyboard-layout.test.ts index ad4603daa..e31acc0af 100644 --- a/packages/app-expo/src/screens/chat-keyboard-layout.test.ts +++ b/packages/app-expo/src/screens/chat-keyboard-layout.test.ts @@ -4,11 +4,13 @@ import { fileURLToPath } from "node:url"; import { describe, expect, it } from "vitest"; const chatScreens = ["ChatScreen.tsx", "BookChatScreen.tsx"] as const; +const screensDir = dirname(fileURLToPath(import.meta.url)); +const repoRoot = resolve(screensDir, "../../../.."); describe("Android chat keyboard layout", () => { for (const screen of chatScreens) { it(`${screen} keeps ChatInput inside Android keyboard avoidance`, () => { - const source = readFileSync(resolve(dirname(fileURLToPath(import.meta.url)), screen), "utf8"); + const source = readFileSync(resolve(screensDir, screen), "utf8"); expect(source).toMatch( /import\s+\{\s*KeyboardAvoidingView\s*\}\s+from\s+"react-native-keyboard-controller";/, @@ -18,4 +20,24 @@ describe("Android chat keyboard layout", () => { ); }); } + + it("clears the controller height style after keyboard dismissal", () => { + const rootPackage = JSON.parse(readFileSync(resolve(repoRoot, "package.json"), "utf8")) as { + pnpm?: { patchedDependencies?: Record }; + }; + expect(rootPackage.pnpm?.patchedDependencies?.["react-native-keyboard-controller@1.18.5"]).toBe( + "patches/react-native-keyboard-controller@1.18.5.patch", + ); + + const controllerSource = readFileSync( + resolve( + repoRoot, + "node_modules/react-native-keyboard-controller/src/components/KeyboardAvoidingView/index.tsx", + ), + "utf8", + ); + expect(controllerSource).toMatch( + /case "height":[\s\S]*?return \{ height: undefined, flex: undefined \};/, + ); + }); }); diff --git a/patches/react-native-keyboard-controller@1.18.5.patch b/patches/react-native-keyboard-controller@1.18.5.patch new file mode 100644 index 000000000..82bc88f96 --- /dev/null +++ b/patches/react-native-keyboard-controller@1.18.5.patch @@ -0,0 +1,24 @@ +diff --git a/src/components/KeyboardAvoidingView/index.tsx b/src/components/KeyboardAvoidingView/index.tsx +--- a/src/components/KeyboardAvoidingView/index.tsx ++++ b/src/components/KeyboardAvoidingView/index.tsx +@@ -162 +162 @@ const KeyboardAvoidingView = forwardRef< +- return {}; ++ return { height: undefined, flex: undefined }; +diff --git a/lib/module/components/KeyboardAvoidingView/index.js b/lib/module/components/KeyboardAvoidingView/index.js +--- a/lib/module/components/KeyboardAvoidingView/index.js ++++ b/lib/module/components/KeyboardAvoidingView/index.js +@@ -86 +86,4 @@ const KeyboardAvoidingView = /*#__PURE__*/forwardRef(({ +- return {}; ++ return { ++ height: undefined, ++ flex: undefined ++ }; +diff --git a/lib/commonjs/components/KeyboardAvoidingView/index.js b/lib/commonjs/components/KeyboardAvoidingView/index.js +--- a/lib/commonjs/components/KeyboardAvoidingView/index.js ++++ b/lib/commonjs/components/KeyboardAvoidingView/index.js +@@ -94 +94,4 @@ const KeyboardAvoidingView = /*#__PURE__*/(0, _react.forwardRef)(({ +- return {}; ++ return { ++ height: undefined, ++ flex: undefined ++ }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 560ef437a..2b8908475 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,6 +13,9 @@ patchedDependencies: '@langchain/core': hash: fsq4dynshckwono4lsk3t4tbui path: patches/@langchain__core.patch + react-native-keyboard-controller@1.18.5: + hash: 47i6k7s3krhp6nvp3ike6dgoee + path: patches/react-native-keyboard-controller@1.18.5.patch react-native-track-player@4.1.2: hash: 6yypjhgtziznwgcfqr66ckjxdy path: patches/react-native-track-player@4.1.2.patch @@ -408,7 +411,7 @@ importers: version: 1.11.0(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0)) react-native-keyboard-controller: specifier: 1.18.5 - version: 1.18.5(react-native-reanimated@4.1.1(@babel/core@7.29.0)(react-native-worklets@0.5.1(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) + version: 1.18.5(patch_hash=47i6k7s3krhp6nvp3ike6dgoee)(react-native-reanimated@4.1.1(@babel/core@7.29.0)(react-native-worklets@0.5.1(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) react-native-markdown-display: specifier: ^7.0.2 version: 7.0.2(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) @@ -18683,7 +18686,7 @@ snapshots: react: 19.1.0 react-native: 0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0) - react-native-keyboard-controller@1.18.5(react-native-reanimated@4.1.1(@babel/core@7.29.0)(react-native-worklets@0.5.1(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): + react-native-keyboard-controller@1.18.5(patch_hash=47i6k7s3krhp6nvp3ike6dgoee)(react-native-reanimated@4.1.1(@babel/core@7.29.0)(react-native-worklets@0.5.1(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): dependencies: react: 19.1.0 react-native: 0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0) From fcde2a95f2af3f08234420d09d5ca40f8bb3ade6 Mon Sep 17 00:00:00 2001 From: Chai Date: Tue, 18 Aug 2026 20:51:11 -0400 Subject: [PATCH 2/3] fix(mobile): use padding for chat keyboard avoidance --- package.json | 1 - .../app-expo/src/screens/BookChatScreen.tsx | 2 +- packages/app-expo/src/screens/ChatScreen.tsx | 2 +- .../src/screens/chat-keyboard-layout.test.ts | 15 ++++++------ ...ct-native-keyboard-controller@1.18.5.patch | 24 ------------------- pnpm-lock.yaml | 22 +++++++++-------- 6 files changed, 21 insertions(+), 45 deletions(-) delete mode 100644 patches/react-native-keyboard-controller@1.18.5.patch diff --git a/package.json b/package.json index e182c2ea1..e596e59c8 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,6 @@ }, "patchedDependencies": { "@langchain/core": "patches/@langchain__core.patch", - "react-native-keyboard-controller@1.18.5": "patches/react-native-keyboard-controller@1.18.5.patch", "react-native-track-player@4.1.2": "patches/react-native-track-player@4.1.2.patch" } }, diff --git a/packages/app-expo/src/screens/BookChatScreen.tsx b/packages/app-expo/src/screens/BookChatScreen.tsx index 208c38953..f5c4e21b4 100644 --- a/packages/app-expo/src/screens/BookChatScreen.tsx +++ b/packages/app-expo/src/screens/BookChatScreen.tsx @@ -530,7 +530,7 @@ export function BookChatScreen({ route, navigation }: Props) { diff --git a/packages/app-expo/src/screens/ChatScreen.tsx b/packages/app-expo/src/screens/ChatScreen.tsx index 3b8e01859..bf84ce315 100644 --- a/packages/app-expo/src/screens/ChatScreen.tsx +++ b/packages/app-expo/src/screens/ChatScreen.tsx @@ -468,7 +468,7 @@ export function ChatScreen() { {/* Content */} diff --git a/packages/app-expo/src/screens/chat-keyboard-layout.test.ts b/packages/app-expo/src/screens/chat-keyboard-layout.test.ts index e31acc0af..aa2af7674 100644 --- a/packages/app-expo/src/screens/chat-keyboard-layout.test.ts +++ b/packages/app-expo/src/screens/chat-keyboard-layout.test.ts @@ -16,18 +16,19 @@ describe("Android chat keyboard layout", () => { /import\s+\{\s*KeyboardAvoidingView\s*\}\s+from\s+"react-native-keyboard-controller";/, ); expect(source).toMatch( - //, + //, ); + expect(source).not.toMatch(/ { + it("does not patch the controller height behavior", () => { const rootPackage = JSON.parse(readFileSync(resolve(repoRoot, "package.json"), "utf8")) as { pnpm?: { patchedDependencies?: Record }; }; - expect(rootPackage.pnpm?.patchedDependencies?.["react-native-keyboard-controller@1.18.5"]).toBe( - "patches/react-native-keyboard-controller@1.18.5.patch", - ); + expect( + rootPackage.pnpm?.patchedDependencies?.["react-native-keyboard-controller@1.18.5"], + ).toBeUndefined(); const controllerSource = readFileSync( resolve( @@ -36,8 +37,6 @@ describe("Android chat keyboard layout", () => { ), "utf8", ); - expect(controllerSource).toMatch( - /case "height":[\s\S]*?return \{ height: undefined, flex: undefined \};/, - ); + expect(controllerSource).toMatch(/case "padding":\s*return \{ paddingBottom: bottom \};/); }); }); diff --git a/patches/react-native-keyboard-controller@1.18.5.patch b/patches/react-native-keyboard-controller@1.18.5.patch deleted file mode 100644 index 82bc88f96..000000000 --- a/patches/react-native-keyboard-controller@1.18.5.patch +++ /dev/null @@ -1,24 +0,0 @@ -diff --git a/src/components/KeyboardAvoidingView/index.tsx b/src/components/KeyboardAvoidingView/index.tsx ---- a/src/components/KeyboardAvoidingView/index.tsx -+++ b/src/components/KeyboardAvoidingView/index.tsx -@@ -162 +162 @@ const KeyboardAvoidingView = forwardRef< -- return {}; -+ return { height: undefined, flex: undefined }; -diff --git a/lib/module/components/KeyboardAvoidingView/index.js b/lib/module/components/KeyboardAvoidingView/index.js ---- a/lib/module/components/KeyboardAvoidingView/index.js -+++ b/lib/module/components/KeyboardAvoidingView/index.js -@@ -86 +86,4 @@ const KeyboardAvoidingView = /*#__PURE__*/forwardRef(({ -- return {}; -+ return { -+ height: undefined, -+ flex: undefined -+ }; -diff --git a/lib/commonjs/components/KeyboardAvoidingView/index.js b/lib/commonjs/components/KeyboardAvoidingView/index.js ---- a/lib/commonjs/components/KeyboardAvoidingView/index.js -+++ b/lib/commonjs/components/KeyboardAvoidingView/index.js -@@ -94 +94,4 @@ const KeyboardAvoidingView = /*#__PURE__*/(0, _react.forwardRef)(({ -- return {}; -+ return { -+ height: undefined, -+ flex: undefined -+ }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2b8908475..8318ec67a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,9 +13,6 @@ patchedDependencies: '@langchain/core': hash: fsq4dynshckwono4lsk3t4tbui path: patches/@langchain__core.patch - react-native-keyboard-controller@1.18.5: - hash: 47i6k7s3krhp6nvp3ike6dgoee - path: patches/react-native-keyboard-controller@1.18.5.patch react-native-track-player@4.1.2: hash: 6yypjhgtziznwgcfqr66ckjxdy path: patches/react-native-track-player@4.1.2.patch @@ -411,7 +408,7 @@ importers: version: 1.11.0(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0)) react-native-keyboard-controller: specifier: 1.18.5 - version: 1.18.5(patch_hash=47i6k7s3krhp6nvp3ike6dgoee)(react-native-reanimated@4.1.1(@babel/core@7.29.0)(react-native-worklets@0.5.1(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) + version: 1.18.5(react-native-reanimated@4.1.1(@babel/core@7.29.0)(react-native-worklets@0.5.1(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) react-native-markdown-display: specifier: ^7.0.2 version: 7.0.2(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0) @@ -7479,18 +7476,22 @@ packages: onnxruntime-common@1.21.0: resolution: {integrity: sha512-Q632iLLrtCAVOTO65dh2+mNbQir/QNTVBG3h/QdZBpns7mZ0RYbLRBgGABPbpU9351AgYy7SJf1WaeVwMrBFPQ==} - onnxruntime-common@1.24.3: - resolution: {integrity: sha512-GeuPZO6U/LBJXvwdaqHbuUmoXiEdeCjWi/EG7Y1HNnDwJYuk6WUbNXpF6luSUY8yASul3cmUlLGrCCL1ZgVXqA==} - onnxruntime-common@1.22.0-dev.20250409-89f8206ba4: resolution: {integrity: sha512-vDJMkfCfb0b1A836rgHj+ORuZf4B4+cc2bASQtpeoJLueuFc5DuYwjIZUBrSvx/fO5IrLjLz+oTrB3pcGlhovQ==} + onnxruntime-common@1.24.3: + resolution: {integrity: sha512-GeuPZO6U/LBJXvwdaqHbuUmoXiEdeCjWi/EG7Y1HNnDwJYuk6WUbNXpF6luSUY8yASul3cmUlLGrCCL1ZgVXqA==} + onnxruntime-node@1.21.0: resolution: {integrity: sha512-NeaCX6WW2L8cRCSqy3bInlo5ojjQqu2fD3D+9W5qb5irwxhEyWKXeH2vZ8W9r6VxaMPUan+4/7NDwZMtouZxEw==} os: [win32, darwin, linux] onnxruntime-react-native@1.24.3: resolution: {integrity: sha512-vMxFcnO1YDtT6auv719Zk0Zj/EXujqeEzSjTe5W7A915qaRrM4pRfXlI4ye/ExOwcTan7NYVZ/wpLX+YBU2aWQ==} + engines: {node: '>=18'} + peerDependencies: + react: 19.1.0 + react-native: '*' onnxruntime-web@1.22.0-dev.20250409-89f8206ba4: resolution: {integrity: sha512-0uS76OPgH0hWCPrFKlL8kYVV7ckM7t/36HfbgoFw6Nd0CZVVbQC4PkrR8mBX8LtNUFZO25IQBqV2Hx2ho3FlbQ==} @@ -8799,6 +8800,7 @@ packages: tsconfck@3.1.6: resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} engines: {node: ^18 || >=20} + deprecated: unmaintained hasBin: true peerDependencies: typescript: ^5.0.0 @@ -18085,10 +18087,10 @@ snapshots: onnxruntime-common@1.21.0: {} - onnxruntime-common@1.24.3: {} - onnxruntime-common@1.22.0-dev.20250409-89f8206ba4: {} + onnxruntime-common@1.24.3: {} + onnxruntime-node@1.21.0: dependencies: global-agent: 3.0.0 @@ -18686,7 +18688,7 @@ snapshots: react: 19.1.0 react-native: 0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0) - react-native-keyboard-controller@1.18.5(patch_hash=47i6k7s3krhp6nvp3ike6dgoee)(react-native-reanimated@4.1.1(@babel/core@7.29.0)(react-native-worklets@0.5.1(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): + react-native-keyboard-controller@1.18.5(react-native-reanimated@4.1.1(@babel/core@7.29.0)(react-native-worklets@0.5.1(@babel/core@7.29.0)(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0))(react-native@0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0): dependencies: react: 19.1.0 react-native: 0.81.5(@babel/core@7.29.0)(@types/react@19.1.17)(react@19.1.0) From 05595d40a8022bf84240f2f142dce37341008635 Mon Sep 17 00:00:00 2001 From: Chai Date: Tue, 18 Aug 2026 20:51:24 -0400 Subject: [PATCH 3/3] chore: keep upstream lockfile unchanged --- pnpm-lock.yaml | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8318ec67a..560ef437a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7476,22 +7476,18 @@ packages: onnxruntime-common@1.21.0: resolution: {integrity: sha512-Q632iLLrtCAVOTO65dh2+mNbQir/QNTVBG3h/QdZBpns7mZ0RYbLRBgGABPbpU9351AgYy7SJf1WaeVwMrBFPQ==} - onnxruntime-common@1.22.0-dev.20250409-89f8206ba4: - resolution: {integrity: sha512-vDJMkfCfb0b1A836rgHj+ORuZf4B4+cc2bASQtpeoJLueuFc5DuYwjIZUBrSvx/fO5IrLjLz+oTrB3pcGlhovQ==} - onnxruntime-common@1.24.3: resolution: {integrity: sha512-GeuPZO6U/LBJXvwdaqHbuUmoXiEdeCjWi/EG7Y1HNnDwJYuk6WUbNXpF6luSUY8yASul3cmUlLGrCCL1ZgVXqA==} + onnxruntime-common@1.22.0-dev.20250409-89f8206ba4: + resolution: {integrity: sha512-vDJMkfCfb0b1A836rgHj+ORuZf4B4+cc2bASQtpeoJLueuFc5DuYwjIZUBrSvx/fO5IrLjLz+oTrB3pcGlhovQ==} + onnxruntime-node@1.21.0: resolution: {integrity: sha512-NeaCX6WW2L8cRCSqy3bInlo5ojjQqu2fD3D+9W5qb5irwxhEyWKXeH2vZ8W9r6VxaMPUan+4/7NDwZMtouZxEw==} os: [win32, darwin, linux] onnxruntime-react-native@1.24.3: resolution: {integrity: sha512-vMxFcnO1YDtT6auv719Zk0Zj/EXujqeEzSjTe5W7A915qaRrM4pRfXlI4ye/ExOwcTan7NYVZ/wpLX+YBU2aWQ==} - engines: {node: '>=18'} - peerDependencies: - react: 19.1.0 - react-native: '*' onnxruntime-web@1.22.0-dev.20250409-89f8206ba4: resolution: {integrity: sha512-0uS76OPgH0hWCPrFKlL8kYVV7ckM7t/36HfbgoFw6Nd0CZVVbQC4PkrR8mBX8LtNUFZO25IQBqV2Hx2ho3FlbQ==} @@ -8800,7 +8796,6 @@ packages: tsconfck@3.1.6: resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} engines: {node: ^18 || >=20} - deprecated: unmaintained hasBin: true peerDependencies: typescript: ^5.0.0 @@ -18087,10 +18082,10 @@ snapshots: onnxruntime-common@1.21.0: {} - onnxruntime-common@1.22.0-dev.20250409-89f8206ba4: {} - onnxruntime-common@1.24.3: {} + onnxruntime-common@1.22.0-dev.20250409-89f8206ba4: {} + onnxruntime-node@1.21.0: dependencies: global-agent: 3.0.0