add composer local sources and convo members
This commit is contained in:
@@ -29,6 +29,7 @@ import {
|
|||||||
Autocomplete as AutocompleteBase,
|
Autocomplete as AutocompleteBase,
|
||||||
AutocompleteItemEmoji,
|
AutocompleteItemEmoji,
|
||||||
AutocompleteItemProfile,
|
AutocompleteItemProfile,
|
||||||
|
type LocalSource,
|
||||||
parseAutocompleteItemType,
|
parseAutocompleteItemType,
|
||||||
useAutocomplete,
|
useAutocomplete,
|
||||||
} from '#/components/Autocomplete'
|
} from '#/components/Autocomplete'
|
||||||
@@ -101,6 +102,8 @@ export type ComposerProps = Omit<
|
|||||||
undefined
|
undefined
|
||||||
>['placement']
|
>['placement']
|
||||||
disableEmojiFacets?: boolean
|
disableEmojiFacets?: boolean
|
||||||
|
/** Local datasets weighted above remote results in the mention typeahead. */
|
||||||
|
localSources?: LocalSource[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Composer({
|
export function Composer({
|
||||||
@@ -117,6 +120,7 @@ export function Composer({
|
|||||||
autocompletePlacement,
|
autocompletePlacement,
|
||||||
defaultValue,
|
defaultValue,
|
||||||
disableEmojiFacets = !IS_WEB,
|
disableEmojiFacets = !IS_WEB,
|
||||||
|
localSources,
|
||||||
...rest
|
...rest
|
||||||
}: ComposerProps) {
|
}: ComposerProps) {
|
||||||
const {theme: t, fonts} = useAlf()
|
const {theme: t, fonts} = useAlf()
|
||||||
@@ -377,6 +381,7 @@ export function Composer({
|
|||||||
inverted={autocompletePlacement?.startsWith('top')}
|
inverted={autocompletePlacement?.startsWith('top')}
|
||||||
sift={sift}
|
sift={sift}
|
||||||
activeFacet={activeFacet}
|
activeFacet={activeFacet}
|
||||||
|
localSources={localSources}
|
||||||
onDismiss={() => setActiveFacet(null)}
|
onDismiss={() => setActiveFacet(null)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -392,16 +397,20 @@ function AutocompleteInner({
|
|||||||
inverted,
|
inverted,
|
||||||
sift,
|
sift,
|
||||||
activeFacet,
|
activeFacet,
|
||||||
|
localSources,
|
||||||
onDismiss,
|
onDismiss,
|
||||||
}: {
|
}: {
|
||||||
inverted?: boolean
|
inverted?: boolean
|
||||||
sift: UseSiftReturn
|
sift: UseSiftReturn
|
||||||
activeFacet: TapperActiveFacet
|
activeFacet: TapperActiveFacet
|
||||||
|
localSources?: LocalSource[]
|
||||||
onDismiss: () => void
|
onDismiss: () => void
|
||||||
}) {
|
}) {
|
||||||
|
const itemType = parseAutocompleteItemType(activeFacet.type)
|
||||||
const {items} = useAutocomplete({
|
const {items} = useAutocomplete({
|
||||||
type: parseAutocompleteItemType(activeFacet.type),
|
type: itemType,
|
||||||
query: activeFacet.value,
|
query: activeFacet.value,
|
||||||
|
sources: itemType === 'profile' ? localSources : undefined,
|
||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import {useConvo} from '#/state/messages/convo'
|
||||||
|
import {useSession} from '#/state/session'
|
||||||
|
import {type LocalSource} from '#/components/Autocomplete/types'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Members of the active conversation as an autocomplete LocalSource, so the
|
||||||
|
* mention typeahead in a chat prioritizes the people in it. Must be used
|
||||||
|
* within a ConvoProvider.
|
||||||
|
*/
|
||||||
|
export function useConvoMembersSource(): LocalSource {
|
||||||
|
const convo = useConvo()
|
||||||
|
const {currentAccount} = useSession()
|
||||||
|
const members = convo.convo?.members ?? []
|
||||||
|
|
||||||
|
return {
|
||||||
|
key: 'convo-members',
|
||||||
|
items: members
|
||||||
|
.filter(member => member.did !== currentAccount?.did)
|
||||||
|
.map(member => ({
|
||||||
|
key: member.did,
|
||||||
|
type: 'profile' as const,
|
||||||
|
value: '@' + member.handle,
|
||||||
|
profile: member,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -37,6 +37,8 @@ import {PaperPlaneVertical_Filled_Stroke2_Corner1_Rounded as PaperPlaneIcon} fro
|
|||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import * as Toast from '#/components/Toast'
|
import * as Toast from '#/components/Toast'
|
||||||
import {IS_ANDROID, IS_IOS, IS_LIQUID_GLASS, IS_NATIVE, IS_WEB} from '#/env'
|
import {IS_ANDROID, IS_IOS, IS_LIQUID_GLASS, IS_NATIVE, IS_WEB} from '#/env'
|
||||||
|
import {useConvoMembersSource} from '#/features/autocomplete/useConvoMembersSource'
|
||||||
|
import {useFollowsSource} from '#/features/autocomplete/useFollowsSource'
|
||||||
import {type MessageEmbedState} from './MessageInputEmbed'
|
import {type MessageEmbedState} from './MessageInputEmbed'
|
||||||
|
|
||||||
const MIN_HEIGHT = 40
|
const MIN_HEIGHT = 40
|
||||||
@@ -71,6 +73,8 @@ export function MessageComposer({
|
|||||||
|
|
||||||
const [text, setText] = useState(getDraft)
|
const [text, setText] = useState(getDraft)
|
||||||
useSaveMessageDraft(text)
|
useSaveMessageDraft(text)
|
||||||
|
const convoMembers = useConvoMembersSource()
|
||||||
|
const follows = useFollowsSource()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!replyTo) return
|
if (!replyTo) return
|
||||||
@@ -255,6 +259,7 @@ export function MessageComposer({
|
|||||||
: l({message: 'Message', context: 'description'})
|
: l({message: 'Message', context: 'description'})
|
||||||
}
|
}
|
||||||
autocompletePlacement="top-start"
|
autocompletePlacement="top-start"
|
||||||
|
localSources={[convoMembers, follows]}
|
||||||
internalApiRef={composerInternalApiRef}
|
internalApiRef={composerInternalApiRef}
|
||||||
defaultValue={text}
|
defaultValue={text}
|
||||||
editable={editable}
|
editable={editable}
|
||||||
|
|||||||
Reference in New Issue
Block a user