Lex refactor (#362)
* Remove the hackcheck for upgrades * Rename the PostEmbeds folder to match the codebase style * Updates to latest lex refactor * Update to use new bsky agent * Update to use api package's richtext library * Switch to upsertProfile * Add TextEncoder/TextDecoder polyfill * Add Intl.Segmenter polyfill * Update composer to calculate lengths by grapheme * Fix detox * Fix login in e2e * Create account e2e passing * Implement an e2e mocking framework * Don't use private methods on mobx models as mobx can't track them * Add tooling for e2e-specific builds and add e2e media-picker mock * Add some tests and fix some bugs around profile editing * Add shell tests * Add home screen tests * Add thread screen tests * Add tests for other user profile screens * Add search screen tests * Implement profile imagery change tools and tests * Update to new embed behaviors * Add post tests * Fix to profile-screen test * Fix session resumption * Update web composer to new api * 1.11.0 * Fix pagination cursor parameters * Add quote posts to notifications * Fix embed layouts * Remove youtube inline player and improve tap handling on link cards * Reset minimal shell mode on all screen loads and feed swipes (close #299) * Update podfile.lock * Improve post notfound UI (close #366) * Bump atproto packages
This commit is contained in:
parent
19f3a2fa92
commit
a3334a01a2
133 changed files with 3103 additions and 2839 deletions
|
@ -9,13 +9,13 @@ import PasteInput, {
|
|||
PastedFile,
|
||||
PasteInputRef,
|
||||
} from '@mattermost/react-native-paste-input'
|
||||
import {AppBskyRichtextFacet, RichText} from '@atproto/api'
|
||||
import isEqual from 'lodash.isequal'
|
||||
import {UserAutocompleteViewModel} from 'state/models/user-autocomplete-view'
|
||||
import {Autocomplete} from './mobile/Autocomplete'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
import {useStores} from 'state/index'
|
||||
import {cleanError} from 'lib/strings/errors'
|
||||
import {detectLinkables, extractEntities} from 'lib/strings/rich-text-detection'
|
||||
import {getImageDim} from 'lib/media/manip'
|
||||
import {cropAndCompressFlow} from 'lib/media/picker'
|
||||
import {getMentionAt, insertMentionAt} from 'lib/strings/mention-manip'
|
||||
|
@ -33,11 +33,11 @@ export interface TextInputRef {
|
|||
}
|
||||
|
||||
interface TextInputProps {
|
||||
text: string
|
||||
richtext: RichText
|
||||
placeholder: string
|
||||
suggestedLinks: Set<string>
|
||||
autocompleteView: UserAutocompleteViewModel
|
||||
onTextChanged: (v: string) => void
|
||||
setRichText: (v: RichText) => void
|
||||
onPhotoPasted: (uri: string) => void
|
||||
onSuggestedLinksChanged: (uris: Set<string>) => void
|
||||
onError: (err: string) => void
|
||||
|
@ -51,11 +51,11 @@ interface Selection {
|
|||
export const TextInput = React.forwardRef(
|
||||
(
|
||||
{
|
||||
text,
|
||||
richtext,
|
||||
placeholder,
|
||||
suggestedLinks,
|
||||
autocompleteView,
|
||||
onTextChanged,
|
||||
setRichText,
|
||||
onPhotoPasted,
|
||||
onSuggestedLinksChanged,
|
||||
onError,
|
||||
|
@ -92,7 +92,9 @@ export const TextInput = React.forwardRef(
|
|||
|
||||
const onChangeText = React.useCallback(
|
||||
(newText: string) => {
|
||||
onTextChanged(newText)
|
||||
const newRt = new RichText({text: newText})
|
||||
newRt.detectFacetsWithoutResolution()
|
||||
setRichText(newRt)
|
||||
|
||||
const prefix = getMentionAt(
|
||||
newText,
|
||||
|
@ -105,20 +107,21 @@ export const TextInput = React.forwardRef(
|
|||
autocompleteView.setActive(false)
|
||||
}
|
||||
|
||||
const ents = extractEntities(newText)?.filter(
|
||||
ent => ent.type === 'link',
|
||||
)
|
||||
const set = new Set(ents ? ents.map(e => e.value) : [])
|
||||
const set: Set<string> = new Set()
|
||||
if (newRt.facets) {
|
||||
for (const facet of newRt.facets) {
|
||||
for (const feature of facet.features) {
|
||||
if (AppBskyRichtextFacet.isLink(feature)) {
|
||||
set.add(feature.uri)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isEqual(set, suggestedLinks)) {
|
||||
onSuggestedLinksChanged(set)
|
||||
}
|
||||
},
|
||||
[
|
||||
onTextChanged,
|
||||
autocompleteView,
|
||||
suggestedLinks,
|
||||
onSuggestedLinksChanged,
|
||||
],
|
||||
[setRichText, autocompleteView, suggestedLinks, onSuggestedLinksChanged],
|
||||
)
|
||||
|
||||
const onPaste = React.useCallback(
|
||||
|
@ -159,31 +162,35 @@ export const TextInput = React.forwardRef(
|
|||
const onSelectAutocompleteItem = React.useCallback(
|
||||
(item: string) => {
|
||||
onChangeText(
|
||||
insertMentionAt(text, textInputSelection.current?.start || 0, item),
|
||||
insertMentionAt(
|
||||
richtext.text,
|
||||
textInputSelection.current?.start || 0,
|
||||
item,
|
||||
),
|
||||
)
|
||||
autocompleteView.setActive(false)
|
||||
},
|
||||
[onChangeText, text, autocompleteView],
|
||||
[onChangeText, richtext, autocompleteView],
|
||||
)
|
||||
|
||||
const textDecorated = React.useMemo(() => {
|
||||
let i = 0
|
||||
return detectLinkables(text).map(v => {
|
||||
if (typeof v === 'string') {
|
||||
return Array.from(richtext.segments()).map(segment => {
|
||||
if (!segment.facet) {
|
||||
return (
|
||||
<Text key={i++} style={[pal.text, styles.textInputFormatting]}>
|
||||
{v}
|
||||
{segment.text}
|
||||
</Text>
|
||||
)
|
||||
} else {
|
||||
return (
|
||||
<Text key={i++} style={[pal.link, styles.textInputFormatting]}>
|
||||
{v.link}
|
||||
{segment.text}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
})
|
||||
}, [text, pal.link, pal.text])
|
||||
}, [richtext, pal.link, pal.text])
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react'
|
||||
import {StyleSheet, View} from 'react-native'
|
||||
import {RichText} from '@atproto/api'
|
||||
import {useEditor, EditorContent, JSONContent} from '@tiptap/react'
|
||||
import {Document} from '@tiptap/extension-document'
|
||||
import {Link} from '@tiptap/extension-link'
|
||||
|
@ -17,11 +18,11 @@ export interface TextInputRef {
|
|||
}
|
||||
|
||||
interface TextInputProps {
|
||||
text: string
|
||||
richtext: RichText
|
||||
placeholder: string
|
||||
suggestedLinks: Set<string>
|
||||
autocompleteView: UserAutocompleteViewModel
|
||||
onTextChanged: (v: string) => void
|
||||
setRichText: (v: RichText) => void
|
||||
onPhotoPasted: (uri: string) => void
|
||||
onSuggestedLinksChanged: (uris: Set<string>) => void
|
||||
onError: (err: string) => void
|
||||
|
@ -30,11 +31,11 @@ interface TextInputProps {
|
|||
export const TextInput = React.forwardRef(
|
||||
(
|
||||
{
|
||||
text,
|
||||
richtext,
|
||||
placeholder,
|
||||
suggestedLinks,
|
||||
autocompleteView,
|
||||
onTextChanged,
|
||||
setRichText,
|
||||
// onPhotoPasted, TODO
|
||||
onSuggestedLinksChanged,
|
||||
}: // onError, TODO
|
||||
|
@ -60,15 +61,15 @@ export const TextInput = React.forwardRef(
|
|||
}),
|
||||
Text,
|
||||
],
|
||||
content: text,
|
||||
content: richtext.text.toString(),
|
||||
autofocus: true,
|
||||
editable: true,
|
||||
injectCSS: true,
|
||||
onUpdate({editor: editorProp}) {
|
||||
const json = editorProp.getJSON()
|
||||
|
||||
const newText = editorJsonToText(json).trim()
|
||||
onTextChanged(newText)
|
||||
const newRt = new RichText({text: editorJsonToText(json).trim()})
|
||||
setRichText(newRt)
|
||||
|
||||
const newSuggestedLinks = new Set(editorJsonToLinks(json))
|
||||
if (!isEqual(newSuggestedLinks, suggestedLinks)) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue