diff options
author | Samuel Newman <mozzius@protonmail.com> | 2025-08-29 03:03:12 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-08-28 17:03:12 -0700 |
commit | 8a4398608acac5f44e8d3c0ea8f6976b8ae1119a (patch) | |
tree | 7e7f75a11d12403efd4069ba00c4e362254a5d1a /src/view/com/composer/text-input/TextInput.web.tsx | |
parent | 27c105856868da9c25a0e8732ff625a602967287 (diff) | |
download | voidsky-8a4398608acac5f44e8d3c0ea8f6976b8ae1119a.tar.zst |
Close web mention suggestions popup on `Escape` (#8605)
* alf web typeahead * fix type error * fix escape behaviour * change selection on hover * rm React. * undo random change
Diffstat (limited to 'src/view/com/composer/text-input/TextInput.web.tsx')
-rw-r--r-- | src/view/com/composer/text-input/TextInput.web.tsx | 104 |
1 files changed, 49 insertions, 55 deletions
diff --git a/src/view/com/composer/text-input/TextInput.web.tsx b/src/view/com/composer/text-input/TextInput.web.tsx index cb7ed194a..9f6cc6ae2 100644 --- a/src/view/com/composer/text-input/TextInput.web.tsx +++ b/src/view/com/composer/text-input/TextInput.web.tsx @@ -1,4 +1,11 @@ -import React, {useRef} from 'react' +import { + useCallback, + useEffect, + useImperativeHandle, + useMemo, + useRef, + useState, +} from 'react' import {StyleSheet, View} from 'react-native' import Animated, {FadeIn, FadeOut} from 'react-native-reanimated' import {AppBskyRichtextFacet, RichText} from '@atproto/api' @@ -16,7 +23,6 @@ import {EditorContent, type JSONContent, useEditor} from '@tiptap/react' import Graphemer from 'graphemer' import {useColorSchemeStyle} from '#/lib/hooks/useColorSchemeStyle' -import {usePalette} from '#/lib/hooks/usePalette' import {blobToDataUri, isUriImage} from '#/lib/media/util' import {useActorAutocompleteFn} from '#/state/queries/actor-autocomplete' import { @@ -27,57 +33,34 @@ import {textInputWebEmitter} from '#/view/com/composer/text-input/textInputWebEm import {atoms as a, useAlf} from '#/alf' import {normalizeTextStyles} from '#/alf/typography' import {Portal} from '#/components/Portal' -import {Text} from '../../util/text/Text' -import {createSuggestion} from './web/Autocomplete' +import {Text} from '#/components/Typography' +import {type TextInputProps} from './TextInput.types' +import {type AutocompleteRef, createSuggestion} from './web/Autocomplete' import {type Emoji} from './web/EmojiPicker' import {LinkDecorator} from './web/LinkDecorator' import {TagDecorator} from './web/TagDecorator' -export interface TextInputRef { - focus: () => void - blur: () => void - getCursorPosition: () => DOMRect | undefined -} - -interface TextInputProps { - richtext: RichText - placeholder: string - suggestedLinks: Set<string> - webForceMinHeight: boolean - hasRightPadding: boolean - isActive: boolean - setRichText: (v: RichText | ((v: RichText) => RichText)) => void - onPhotoPasted: (uri: string) => void - onPressPublish: (richtext: RichText) => void - onNewLink: (uri: string) => void - onError: (err: string) => void - onFocus: () => void -} - -export const TextInput = React.forwardRef(function TextInputImpl( - { - richtext, - placeholder, - webForceMinHeight, - hasRightPadding, - isActive, - setRichText, - onPhotoPasted, - onPressPublish, - onNewLink, - onFocus, - }: // onError, TODO - TextInputProps, +export function TextInput({ ref, -) { + richtext, + placeholder, + webForceMinHeight, + hasRightPadding, + isActive, + setRichText, + onPhotoPasted, + onPressPublish, + onNewLink, + onFocus, +}: TextInputProps) { const {theme: t, fonts} = useAlf() const autocomplete = useActorAutocompleteFn() - const pal = usePalette('default') const modeClass = useColorSchemeStyle('ProseMirror-light', 'ProseMirror-dark') - const [isDropping, setIsDropping] = React.useState(false) + const [isDropping, setIsDropping] = useState(false) + const autocompleteRef = useRef<AutocompleteRef>(null) - const extensions = React.useMemo( + const extensions = useMemo( () => [ Document, LinkDecorator, @@ -86,7 +69,7 @@ export const TextInput = React.forwardRef(function TextInputImpl( HTMLAttributes: { class: 'mention', }, - suggestion: createSuggestion({autocomplete}), + suggestion: createSuggestion({autocomplete, autocompleteRef}), }), Paragraph, Placeholder.configure({ @@ -99,7 +82,7 @@ export const TextInput = React.forwardRef(function TextInputImpl( [autocomplete, placeholder], ) - React.useEffect(() => { + useEffect(() => { if (!isActive) { return } @@ -109,7 +92,7 @@ export const TextInput = React.forwardRef(function TextInputImpl( } }, [onPressPublish, isActive]) - React.useEffect(() => { + useEffect(() => { if (!isActive) { return } @@ -119,7 +102,7 @@ export const TextInput = React.forwardRef(function TextInputImpl( } }, [isActive, onPhotoPasted]) - React.useEffect(() => { + useEffect(() => { if (!isActive) { return } @@ -296,13 +279,13 @@ export const TextInput = React.forwardRef(function TextInputImpl( [modeClass], ) - const onEmojiInserted = React.useCallback( + const onEmojiInserted = useCallback( (emoji: Emoji) => { editor?.chain().focus().insertContent(emoji.native).run() }, [editor], ) - React.useEffect(() => { + useEffect(() => { if (!isActive) { return } @@ -312,7 +295,7 @@ export const TextInput = React.forwardRef(function TextInputImpl( } }, [onEmojiInserted, isActive]) - React.useImperativeHandle(ref, () => ({ + useImperativeHandle(ref, () => ({ focus: () => { editor?.chain().focus() }, @@ -323,9 +306,10 @@ export const TextInput = React.forwardRef(function TextInputImpl( const pos = editor?.state.selection.$anchor.pos return pos ? editor?.view.coordsAtPos(pos) : undefined }, + maybeClosePopup: () => autocompleteRef.current?.maybeClose() ?? false, })) - const inputStyle = React.useMemo(() => { + const inputStyle = useMemo(() => { const style = normalizeTextStyles( [a.text_lg, a.leading_snug, t.atoms.text], { @@ -360,10 +344,20 @@ export const TextInput = React.forwardRef(function TextInputImpl( style={styles.dropContainer} entering={FadeIn.duration(80)} exiting={FadeOut.duration(80)}> - <View style={[pal.view, pal.border, styles.dropModal]}> + <View + style={[ + t.atoms.bg, + t.atoms.border_contrast_low, + styles.dropModal, + ]}> <Text - type="lg" - style={[pal.text, pal.borderDark, styles.dropText]}> + style={[ + a.text_lg, + a.font_bold, + t.atoms.text_contrast_medium, + t.atoms.border_contrast_high, + styles.dropText, + ]}> <Trans>Drop to add images</Trans> </Text> </View> @@ -372,7 +366,7 @@ export const TextInput = React.forwardRef(function TextInputImpl( )} </> ) -}) +} function editorJsonToText( json: JSONContent, |