split text using Graphemer

This commit is contained in:
Samuel Newman
2024-05-09 14:26:16 +01:00
parent ca32bf5e0c
commit c7f9d713ac
+10 -11
View File
@@ -13,11 +13,12 @@ import {
type TextInputSelectionChangeEventData, type TextInputSelectionChangeEventData,
View, View,
} from 'react-native' } from 'react-native'
import {AppBskyRichtextFacet, RichText} from '@atproto/api' import {AppBskyRichtextFacet, RichText, UnicodeString} from '@atproto/api'
import PasteInput, { import PasteInput, {
type PastedFile, type PastedFile,
type PasteInputRef, // @ts-expect-error no types when installing from github type PasteInputRef, // @ts-expect-error no types when installing from github
} from '@mattermost/react-native-paste-input' } from '@mattermost/react-native-paste-input'
import Graphemer from 'graphemer'
import {MAX_GRAPHEME_LENGTH, POST_IMG_MAX} from '#/lib/constants' import {MAX_GRAPHEME_LENGTH, POST_IMG_MAX} from '#/lib/constants'
import {downloadAndResize} from '#/lib/media/manip' import {downloadAndResize} from '#/lib/media/manip'
@@ -211,13 +212,15 @@ export const TextInput = forwardRef(function TextInputImpl(
return style return style
}, [t, fonts]) }, [t, fonts])
const splitter = useMemo(() => new Graphemer(), [])
const textDecorated = useMemo(() => { const textDecorated = useMemo(() => {
let excess let excess
let truncatedRichtext = richtext
if (richtext.graphemeLength > MAX_GRAPHEME_LENGTH) { if (richtext.graphemeLength > MAX_GRAPHEME_LENGTH) {
truncatedRichtext = richtext.clone() const split = splitter.splitGraphemes(richtext.text)
const excessText = const validText = split.slice(0, MAX_GRAPHEME_LENGTH).join('')
truncatedRichtext.unicodeText.slice(MAX_GRAPHEME_LENGTH) const validUnicode = new UnicodeString(validText)
const excessText = split.slice(MAX_GRAPHEME_LENGTH).join('')
richtext.delete(validUnicode.utf8.byteLength, richtext.length)
excess = ( excess = (
<RNText <RNText
key="excess" key="excess"
@@ -229,14 +232,10 @@ export const TextInput = forwardRef(function TextInputImpl(
{excessText} {excessText}
</RNText> </RNText>
) )
truncatedRichtext.delete(
MAX_GRAPHEME_LENGTH,
truncatedRichtext.graphemeLength,
)
} }
let i = 0 let i = 0
const segments = Array.from(truncatedRichtext.segments()).map(segment => { const segments = Array.from(richtext.segments()).map(segment => {
return ( return (
<RNText <RNText
key={i++} key={i++}
@@ -257,7 +256,7 @@ export const TextInput = forwardRef(function TextInputImpl(
} }
return segments return segments
}, [t, richtext, inputTextStyle]) }, [t, richtext, inputTextStyle, splitter])
return ( return (
<View style={[a.flex_1, a.pl_md, hasRightPadding && a.pr_4xl]}> <View style={[a.flex_1, a.pl_md, hasRightPadding && a.pr_4xl]}>