Skip to content

Commit a11e835

Browse files
committed
fix(mobile): prevent cursor from hiding behind keyboard and toolbar on Android
- Enable avoidIosKeyboard in TenTap editor bridge - Add KeyboardAvoidingView with height behavior for Android - Implement JavaScript injection to auto-scroll cursor into view - Listen for selectionchange, input, and click events
1 parent f4effdc commit a11e835

File tree

3 files changed

+37
-7
lines changed

3 files changed

+37
-7
lines changed

apps/mobile/v1/src/hooks/useNoteEditor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export function useNoteEditor(noteId?: string): UseNoteEditorReturn {
2828
// Initialize editor with TenTapStartKit
2929
const editor = useEditorBridge({
3030
autofocus: false,
31-
avoidIosKeyboard: false,
31+
avoidIosKeyboard: true,
3232
initialContent: '<p></p>',
3333
bridgeExtensions: TenTapStartKit,
3434
});

apps/mobile/v1/src/screens/EditNote/index.tsx

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useState, useEffect } from 'react';
2-
import { View, Text, StyleSheet, Alert, TextInput } from 'react-native';
2+
import { View, Text, StyleSheet, Alert, TextInput, Platform } from 'react-native';
33
import { SafeAreaView } from 'react-native-safe-area-context';
44
import { useRouter, useLocalSearchParams } from 'expo-router';
55
import * as Haptics from 'expo-haptics';
@@ -175,14 +175,44 @@ export default function EditNoteScreen() {
175175
<View style={[styles.divider, { backgroundColor: theme.colors.border, marginHorizontal: -16 }]} />
176176
</View>
177177

178-
<View style={styles.editorContainer}>
178+
<View style={[styles.editorContainer, Platform.OS === 'android' && keyboardHeight > 0 && { marginBottom: keyboardHeight + 60 }]}>
179179
<RichText
180180
editor={editor}
181181
style={{ flex: 1, backgroundColor: theme.colors.background }}
182182
onLoad={handleEditorLoad}
183183
webViewProps={{
184184
bounces: false,
185185
overScrollMode: 'never',
186+
injectedJavaScript: Platform.OS === 'android' ? `
187+
(function() {
188+
function scrollToCursor() {
189+
const selection = window.getSelection();
190+
if (selection && selection.rangeCount > 0) {
191+
const range = selection.getRangeAt(0);
192+
const rect = range.getBoundingClientRect();
193+
const scrollBuffer = 220; // Extra space for toolbar
194+
195+
// Check if cursor is too low on screen
196+
if (rect.bottom > window.innerHeight - scrollBuffer) {
197+
window.scrollBy({
198+
top: rect.bottom - (window.innerHeight - scrollBuffer),
199+
behavior: 'smooth'
200+
});
201+
}
202+
}
203+
}
204+
205+
// Listen for selection changes
206+
document.addEventListener('selectionchange', scrollToCursor);
207+
208+
// Listen for input events
209+
document.addEventListener('input', scrollToCursor);
210+
211+
// Listen for click events
212+
document.addEventListener('click', scrollToCursor);
213+
})();
214+
true;
215+
` : undefined,
186216
}}
187217
/>
188218
</View>

apps/mobile/v1/src/screens/SettingsScreen.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export default function SettingsScreen({ onLogout, navigation }: Props) {
138138
onPress: () => {
139139
Alert.alert(
140140
'Logout',
141-
'Are you sure you want to logout? You&apos;ll need to enter your master password again.',
141+
'Are you sure you want to logout? You\'ll need to enter your master password again.',
142142
[
143143
{ text: 'Cancel', style: 'cancel' },
144144
{ text: 'Logout', style: 'destructive', onPress: onLogout }
@@ -206,7 +206,7 @@ export default function SettingsScreen({ onLogout, navigation }: Props) {
206206
onPress: () => Linking.openURL('https://github.com/typelets/typelets-app'),
207207
},
208208
{
209-
title: "What&apos;s New",
209+
title: "What's New",
210210
subtitle: 'See latest updates and changes',
211211
icon: 'newspaper-outline',
212212
onPress: () => Linking.openURL('https://github.com/typelets/typelets-app/blob/main/CHANGELOG.md'),
@@ -554,7 +554,7 @@ export default function SettingsScreen({ onLogout, navigation }: Props) {
554554
</Text>
555555
</View>
556556
<Text style={[styles.securityFeatureDescription, { color: theme.colors.mutedForeground }]}>
557-
Your master password is the only key to decrypt your notes. It&apos;s never stored on our servers and cannot be recovered if lost.
557+
{`Your master password is the only key to decrypt your notes. It's never stored on our servers and cannot be recovered if lost.`}
558558
</Text>
559559
</View>
560560

@@ -578,7 +578,7 @@ export default function SettingsScreen({ onLogout, navigation }: Props) {
578578
</Text>
579579
</View>
580580
<Text style={[styles.securityFeatureDescription, { color: theme.colors.mutedForeground }]}>
581-
We can&apos;t read your notes, recover your password, or access your data. Your privacy is guaranteed by design.
581+
{`We can't read your notes, recover your password, or access your data. Your privacy is guaranteed by design.`}
582582
</Text>
583583
</View>
584584
</View>

0 commit comments

Comments
 (0)