authorgravatar for adityaradhika13@gmail.comAditya Vardhan Sharma <adityaradhika13@gmail.com> 2026-07-30 23:20:33+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-07-31 00:20:33+02:00
logcb11a71d632e0fb9e7a1fe8c0a95f35583c9cf11
tree4b57fe700f5c5141cb41d226d53141fbde159614
parent41124c726001498bb09e6c1b3eaff71e6ca0b43d
signature Signed by PGP key B5690EEEBB952194

fix(mobile): accept Android clipboard images in composer (#4836)


1 files changed, 61 insertions(+), 56 deletions(-)

apps/mobile/src/native/T3ComposerEditor.native.tsx+61-56
......@@ -1,5 +1,6 @@
11import { collectComposerInlineTokens } from "@t3tools/shared/composerInlineTokens";
22import { requireNativeView } from "expo";
3import { TextInputWrapper } from "expo-paste-input";
34import {
45 useCallback,
56 useEffect,
......@@ -9,12 +10,13 @@ import {
910 useState,
1011 type Ref,
1112} from "react";
12import type { NativeSyntheticEvent, StyleProp, ViewProps, ViewStyle } from "react-native";
13import type { NativeSyntheticEvent, ViewProps } from "react-native";
1314import { Image, StyleSheet } from "react-native";
1415
1516import { markdownFileIconSource } from "@t3tools/mobile-markdown-text/file-icons";
1617import { resolveMarkdownFileIcon } from "@t3tools/mobile-markdown-text/links";
1718import { MOBILE_TYPOGRAPHY } from "../lib/typography";
19import { useNativePaste } from "../lib/useNativePaste";
1820import { useFontFamily } from "../lib/useFontFamily";
1921import { useThemeColor } from "../lib/useThemeColor";
2022import {
......@@ -117,6 +119,7 @@ export function ComposerEditor({
117119 const skillBorder = useThemeColor("--color-inline-skill-border");
118120 const skillText = useThemeColor("--color-inline-skill-foreground");
119121 const fileTint = useThemeColor("--color-icon-muted");
122 const handlePaste = useNativePaste((uris) => onPasteImages?.(uris));
120123
121124 useImperativeHandle(
122125 ref,
......@@ -221,61 +224,63 @@ export function ComposerEditor({
221224 const resolvedTextStyle = StyleSheet.flatten(textStyle) ?? {};
222225 const regularFontFamily = useFontFamily("regular");
223226 return (
224 <NativeView
225 ref={nativeRef}
226 controlledDocumentJson={controlledDocumentJson}
227 themeJson={themeJson}
228 placeholder={props.placeholder ?? ""}
229 fontFamily={
230 typeof resolvedTextStyle.fontFamily === "string"
231 ? resolvedTextStyle.fontFamily
232 : regularFontFamily
233 }
234 fontSize={
235 typeof resolvedTextStyle.fontSize === "number"
236 ? resolvedTextStyle.fontSize
237 : MOBILE_TYPOGRAPHY.body.fontSize
238 }
239 lineHeight={
240 typeof resolvedTextStyle.lineHeight === "number"
241 ? resolvedTextStyle.lineHeight
242 : MOBILE_TYPOGRAPHY.body.lineHeight
243 }
244 contentInsetVertical={contentInsetVertical}
245 singleLineCentered={props.singleLineCentered ?? false}
246 editable={props.editable ?? true}
247 scrollEnabled={props.scrollEnabled ?? true}
248 autoFocus={props.autoFocus ?? false}
249 autoCorrect={props.autoCorrect ?? true}
250 spellCheck={props.spellCheck ?? true}
251 style={style as StyleProp<ViewStyle>}
252 onComposerChange={(event) => {
253 const acknowledgedEventCount = acceptNativeEvent(
254 event.nativeEvent.eventCount,
255 event.nativeEvent.value,
256 event.nativeEvent.selection,
257 );
258 if (acknowledgedEventCount === false) return;
259 onChangeText(event.nativeEvent.value);
260 onSelectionChange?.(event.nativeEvent.selection);
261 setMostRecentEventCount(acknowledgedEventCount);
262 setNativeEventSequence((sequence) => sequence + 1);
263 }}
264 onComposerSelectionChange={(event) => {
265 const acknowledgedEventCount = acceptNativeEvent(
266 event.nativeEvent.eventCount,
267 event.nativeEvent.value,
268 event.nativeEvent.selection,
269 );
270 if (acknowledgedEventCount === false) return;
271 onSelectionChange?.(event.nativeEvent.selection);
272 setMostRecentEventCount(acknowledgedEventCount);
273 setNativeEventSequence((sequence) => sequence + 1);
274 }}
275 onComposerPasteImages={(event) => onPasteImages?.(event.nativeEvent.uris)}
276 onComposerFocus={onFocus}
277 onComposerBlur={onBlur}
278 />
227 <TextInputWrapper onPaste={handlePaste} style={[{ minHeight: 0 }, style]}>
228 <NativeView
229 ref={nativeRef}
230 controlledDocumentJson={controlledDocumentJson}
231 themeJson={themeJson}
232 placeholder={props.placeholder ?? ""}
233 fontFamily={
234 typeof resolvedTextStyle.fontFamily === "string"
235 ? resolvedTextStyle.fontFamily
236 : regularFontFamily
237 }
238 fontSize={
239 typeof resolvedTextStyle.fontSize === "number"
240 ? resolvedTextStyle.fontSize
241 : MOBILE_TYPOGRAPHY.body.fontSize
242 }
243 lineHeight={
244 typeof resolvedTextStyle.lineHeight === "number"
245 ? resolvedTextStyle.lineHeight
246 : MOBILE_TYPOGRAPHY.body.lineHeight
247 }
248 contentInsetVertical={contentInsetVertical}
249 singleLineCentered={props.singleLineCentered ?? false}
250 editable={props.editable ?? true}
251 scrollEnabled={props.scrollEnabled ?? true}
252 autoFocus={props.autoFocus ?? false}
253 autoCorrect={props.autoCorrect ?? true}
254 spellCheck={props.spellCheck ?? true}
255 style={{ flex: 1, minHeight: 0 }}
256 onComposerChange={(event) => {
257 const acknowledgedEventCount = acceptNativeEvent(
258 event.nativeEvent.eventCount,
259 event.nativeEvent.value,
260 event.nativeEvent.selection,
261 );
262 if (acknowledgedEventCount === false) return;
263 onChangeText(event.nativeEvent.value);
264 onSelectionChange?.(event.nativeEvent.selection);
265 setMostRecentEventCount(acknowledgedEventCount);
266 setNativeEventSequence((sequence) => sequence + 1);
267 }}
268 onComposerSelectionChange={(event) => {
269 const acknowledgedEventCount = acceptNativeEvent(
270 event.nativeEvent.eventCount,
271 event.nativeEvent.value,
272 event.nativeEvent.selection,
273 );
274 if (acknowledgedEventCount === false) return;
275 onSelectionChange?.(event.nativeEvent.selection);
276 setMostRecentEventCount(acknowledgedEventCount);
277 setNativeEventSequence((sequence) => sequence + 1);
278 }}
279 onComposerPasteImages={(event) => onPasteImages?.(event.nativeEvent.uris)}
280 onComposerFocus={onFocus}
281 onComposerBlur={onBlur}
282 />
283 </TextInputWrapper>
279284 );
280285}
281286