migrate post composer to unified autocomplete
This commit is contained in:
@@ -29,7 +29,6 @@ import {splitGraphemes} from 'unicode-segmenter/grapheme'
|
||||
|
||||
import {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle'
|
||||
import {blobToDataUri, isUriImage} from '#/lib/media/util'
|
||||
import {useActorAutocompleteFn} from '#/state/queries/actor-autocomplete'
|
||||
import {
|
||||
type LinkFacetMatch,
|
||||
suggestLinkCardUri,
|
||||
@@ -37,9 +36,11 @@ import {
|
||||
import {textInputWebEmitter} from '#/view/com/composer/text-input/textInputWebEmitter'
|
||||
import {atoms as a, useAlf} from '#/alf'
|
||||
import {normalizeTextStyles} from '#/alf/typography'
|
||||
import {useAutocompleteFn} from '#/components/Autocomplete'
|
||||
import {type Emoji} from '#/components/EmojiPicker'
|
||||
import {Portal} from '#/components/Portal'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useFollowsSource} from '#/features/autocomplete/useFollowsSource'
|
||||
import {type TextInputProps} from './TextInput.types'
|
||||
import {type AutocompleteRef, createSuggestion} from './web/Autocomplete'
|
||||
import {LinkDecorator} from './web/LinkDecorator'
|
||||
@@ -60,7 +61,24 @@ export function TextInput({
|
||||
autoFocus,
|
||||
}: TextInputProps) {
|
||||
const {theme: t, fonts} = useAlf()
|
||||
const autocomplete = useActorAutocompleteFn()
|
||||
const follows = useFollowsSource()
|
||||
const autocompleteFn = useAutocompleteFn({
|
||||
type: 'profile',
|
||||
sources: [follows],
|
||||
})
|
||||
/*
|
||||
* Adapter for the tiptap mention plugin, which renders plain profile views.
|
||||
* useCallback keeps the extensions useMemo below stable.
|
||||
*/
|
||||
const autocomplete = useCallback(
|
||||
async ({query}: {query: string}) => {
|
||||
const items = await autocompleteFn(query, 8)
|
||||
return items
|
||||
.filter(item => item.type === 'profile')
|
||||
.map(item => item.profile)
|
||||
},
|
||||
[autocompleteFn],
|
||||
)
|
||||
const modeClass = useColorSchemeStyle('ProseMirror-light', 'ProseMirror-dark')
|
||||
|
||||
const [isDropping, setIsDropping] = useState(false)
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
import {View} from 'react-native'
|
||||
import Animated, {FadeInDown, FadeOut} from 'react-native-reanimated'
|
||||
import {type AppBskyActorDefs} from '@atproto/api'
|
||||
import {Trans} from '@lingui/react/macro'
|
||||
|
||||
import {PressableScale} from '#/lib/custom-animations/PressableScale'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete'
|
||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||
import {atoms as a, platform, useTheme} from '#/alf'
|
||||
import {useAutocomplete} from '#/components/Autocomplete'
|
||||
import {ProfileBadges} from '#/components/ProfileBadges'
|
||||
import {Text} from '#/components/Typography'
|
||||
import {useFollowsSource} from '#/features/autocomplete/useFollowsSource'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
export function Autocomplete({
|
||||
prefix,
|
||||
@@ -22,10 +23,15 @@ export function Autocomplete({
|
||||
const t = useTheme()
|
||||
|
||||
const isActive = !!prefix
|
||||
const {data: suggestions, isFetching} = useActorAutocompleteQuery(
|
||||
prefix,
|
||||
true,
|
||||
)
|
||||
const follows = useFollowsSource()
|
||||
const {items, isFetching} = useAutocomplete({
|
||||
type: 'profile',
|
||||
query: prefix,
|
||||
sources: isActive ? [follows] : undefined,
|
||||
})
|
||||
const suggestions = items
|
||||
.filter(item => item.type === 'profile')
|
||||
.map(item => item.profile)
|
||||
|
||||
if (!isActive) return null
|
||||
|
||||
@@ -41,7 +47,7 @@ export function Autocomplete({
|
||||
t.atoms.border_contrast_high,
|
||||
{marginLeft: -62},
|
||||
]}>
|
||||
{suggestions?.length ? (
|
||||
{suggestions.length ? (
|
||||
suggestions.slice(0, 5).map((item, index, arr) => {
|
||||
return (
|
||||
<AutocompleteProfileCard
|
||||
@@ -70,7 +76,7 @@ function AutocompleteProfileCard({
|
||||
totalItems,
|
||||
onPress,
|
||||
}: {
|
||||
profile: AppBskyActorDefs.ProfileViewBasic
|
||||
profile: bsky.profile.AnyProfileView
|
||||
itemIndex: number
|
||||
totalItems: number
|
||||
onPress: () => void
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {forwardRef, useEffect, useImperativeHandle, useState} from 'react'
|
||||
import {Pressable, View} from 'react-native'
|
||||
import {type AppBskyActorDefs, type ModerationOpts} from '@atproto/api'
|
||||
import {type ModerationOpts} from '@atproto/api'
|
||||
import {Trans} from '@lingui/react/macro'
|
||||
import {ReactRenderer} from '@tiptap/react'
|
||||
import {
|
||||
@@ -11,10 +11,10 @@ import {
|
||||
import tippy, {type Instance as TippyInstance} from 'tippy.js'
|
||||
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {type ActorAutocompleteFn} from '#/state/queries/actor-autocomplete'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import * as ProfileCard from '#/components/ProfileCard'
|
||||
import {Text} from '#/components/Typography'
|
||||
import type * as bsky from '#/types/bsky'
|
||||
|
||||
interface MentionListRef {
|
||||
onKeyDown: (props: SuggestionKeyDownProps) => boolean
|
||||
@@ -24,11 +24,19 @@ export interface AutocompleteRef {
|
||||
maybeClose: () => boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Adapter type for the tiptap mention suggestion plugin, which expects a
|
||||
* function returning plain profile views rather than `AutocompleteItem`s.
|
||||
*/
|
||||
export type MentionAutocompleteFn = (opts: {
|
||||
query: string
|
||||
}) => Promise<bsky.profile.AnyProfileView[]>
|
||||
|
||||
export function createSuggestion({
|
||||
autocomplete,
|
||||
autocompleteRef,
|
||||
}: {
|
||||
autocomplete: ActorAutocompleteFn
|
||||
autocomplete: MentionAutocompleteFn
|
||||
autocompleteRef: React.Ref<AutocompleteRef>
|
||||
}): Omit<SuggestionOptions, 'editor'> {
|
||||
return {
|
||||
@@ -204,7 +212,7 @@ function AutocompleteProfileCard({
|
||||
onHover,
|
||||
moderationOpts,
|
||||
}: {
|
||||
profile: AppBskyActorDefs.ProfileViewBasic
|
||||
profile: bsky.profile.AnyProfileView
|
||||
isSelected: boolean
|
||||
onPress: () => void
|
||||
onHover: () => void
|
||||
|
||||
Reference in New Issue
Block a user