mirror of
https://github.com/tooot-app/app
synced 2025-01-18 12:15:42 +01:00
Basic auto suggestion is working
This commit is contained in:
parent
c417262528
commit
d8d8a6c1fa
4150
package-lock.json
generated
4150
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -9,7 +9,7 @@ const client = async ({
|
||||
query,
|
||||
body
|
||||
}: {
|
||||
version: 'v1' | 'v2'
|
||||
version?: 'v1' | 'v2'
|
||||
method: 'get' | 'post' | 'delete'
|
||||
instance: 'local' | 'remote'
|
||||
endpoint: string
|
||||
@ -34,8 +34,8 @@ const client = async ({
|
||||
},
|
||||
...(body && { json: body })
|
||||
})
|
||||
} catch {
|
||||
return Promise.reject('ky error')
|
||||
} catch (error) {
|
||||
return Promise.reject('ky error: ' + error)
|
||||
}
|
||||
|
||||
if (response.ok) {
|
||||
|
@ -45,18 +45,20 @@ const Attachment: React.FC<Props> = ({
|
||||
(width / media_attachments[0].meta.original.width) *
|
||||
media_attachments[0].meta.original.height
|
||||
break
|
||||
case 'video':
|
||||
attachment = (
|
||||
<AttachmentVideo
|
||||
media_attachments={media_attachments}
|
||||
sensitive={sensitive}
|
||||
width={width}
|
||||
/>
|
||||
)
|
||||
attachmentHeight =
|
||||
(width / media_attachments[0].meta.original.width) *
|
||||
media_attachments[0].meta.original.height
|
||||
break
|
||||
// Support multiple video
|
||||
// Supoort when video meta is empty
|
||||
// case 'video':
|
||||
// attachment = (
|
||||
// <AttachmentVideo
|
||||
// media_attachments={media_attachments}
|
||||
// sensitive={sensitive}
|
||||
// width={width}
|
||||
// />
|
||||
// )
|
||||
// attachmentHeight =
|
||||
// (width / media_attachments[0].meta.original.width) *
|
||||
// media_attachments[0].meta.original.height
|
||||
// break
|
||||
// case 'audio':
|
||||
// attachment = (
|
||||
// <AttachmentAudio
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Match, MatchConfig } from "./match";
|
||||
import { MentionServices } from "../autolinker";
|
||||
import { Match, MatchConfig } from './match';
|
||||
import { MentionServices } from '../autolinker';
|
||||
/**
|
||||
* @class Autolinker.match.Mention
|
||||
* @extends Autolinker.match.Match
|
||||
|
@ -1,5 +1,5 @@
|
||||
import * as tslib_1 from "tslib";
|
||||
import { Match } from "./match";
|
||||
import { Match } from './match';
|
||||
/**
|
||||
* @class Autolinker.match.Mention
|
||||
* @extends Autolinker.match.Match
|
||||
@ -67,13 +67,16 @@ var MentionMatch = /** @class */ (function (_super) {
|
||||
*/
|
||||
MentionMatch.prototype.getAnchorHref = function () {
|
||||
switch (this.serviceName) {
|
||||
case 'mastodon':
|
||||
return 'https://example.com/' + this.mention;
|
||||
case 'twitter':
|
||||
return 'https://twitter.com/' + this.mention;
|
||||
case 'instagram':
|
||||
return 'https://instagram.com/' + this.mention;
|
||||
case 'soundcloud':
|
||||
return 'https://soundcloud.com/' + this.mention;
|
||||
default: // Shouldn't happen because Autolinker's constructor should block any invalid values, but just in case.
|
||||
default:
|
||||
// Shouldn't happen because Autolinker's constructor should block any invalid values, but just in case.
|
||||
throw new Error('Unknown service name to point mention to: ' + this.serviceName);
|
||||
}
|
||||
};
|
||||
|
@ -1 +1 @@
|
||||
{"version":3,"sources":["../src/match/mention-match.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAe,MAAM,SAAS,CAAC;AAG7C;;;;;;;GAOG;AACH;IAAkC,wCAAK;IAkBtC;;;;OAIG;IACH,sBAAa,GAAuB;QAApC,YACC,kBAAO,GAAG,CAAE,SAIZ;QA1BD;;;;;WAKG;QACc,iBAAW,GAAoB,SAAS,CAAC,CAAE,gGAAgG;QAE5J;;;;WAIG;QACc,aAAO,GAAW,EAAE,CAAC,CAAE,gGAAgG;QAWvI,KAAI,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;QAC3B,KAAI,CAAC,WAAW,GAAG,GAAG,CAAC,WAAW,CAAC;;IACpC,CAAC;IAGD;;;;;OAKG;IACH,8BAAO,GAAP;QACC,OAAO,SAAS,CAAC;IAClB,CAAC;IAGD;;;;OAIG;IACH,iCAAU,GAAV;QACC,OAAO,IAAI,CAAC,OAAO,CAAC;IACrB,CAAC;IAGD;;;;;OAKG;IACH,qCAAc,GAAd;QACC,OAAO,IAAI,CAAC,WAAW,CAAC;IACzB,CAAC;IAGD;;;;OAIG;IACH,oCAAa,GAAb;QACC,QAAQ,IAAI,CAAC,WAAW,EAAG;YAC1B,KAAK,SAAS;gBACb,OAAO,sBAAsB,GAAG,IAAI,CAAC,OAAO,CAAC;YAC9C,KAAK,WAAW;gBACf,OAAO,wBAAwB,GAAG,IAAI,CAAC,OAAO,CAAC;YAChD,KAAK,YAAY;gBAChB,OAAO,yBAAyB,GAAG,IAAI,CAAC,OAAO,CAAC;YAEjD,SAAW,uGAAuG;gBACjH,MAAM,IAAI,KAAK,CAAE,4CAA4C,GAAG,IAAI,CAAC,WAAW,CAAE,CAAC;SACpF;IACF,CAAC;IAGD;;;;OAIG;IACH,oCAAa,GAAb;QACC,OAAO,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC;IAC3B,CAAC;IAGD;;;;;;OAMG;IACH,0CAAmB,GAAnB;QACC,IAAI,gBAAgB,GAAG,iBAAM,mBAAmB,WAAE,EAC9C,WAAW,GAAG,IAAI,CAAC,cAAc,EAAE,CAAC;QAExC,IAAI,WAAW,EAAG;YACjB,gBAAgB,CAAC,IAAI,CAAE,WAAW,CAAE,CAAC;SACrC;QACD,OAAO,gBAAgB,CAAC;IACzB,CAAC;IAEF,mBAAC;AAAD,CA9GA,AA8GC,CA9GiC,KAAK,GA8GtC","file":"mention-match.js","sourcesContent":["import { Match, MatchConfig } from \"./match\";\nimport { MentionServices } from \"../autolinker\";\n\n/**\n * @class Autolinker.match.Mention\n * @extends Autolinker.match.Match\n *\n * Represents a Mention match found in an input string which should be Autolinked.\n *\n * See this class's superclass ({@link Autolinker.match.Match}) for more details.\n */\nexport class MentionMatch extends Match {\n\n\t/**\n\t * @cfg {String} serviceName\n\t *\n\t * The service to point mention matches to. See {@link Autolinker#mention}\n\t * for available values.\n\t */\n\tprivate readonly serviceName: MentionServices = 'twitter'; // default value just to get the above doc comment in the ES5 output and documentation generator\n\n\t/**\n\t * @cfg {String} mention (required)\n\t *\n\t * The Mention that was matched, without the '@' character.\n\t */\n\tprivate readonly mention: string = ''; // default value just to get the above doc comment in the ES5 output and documentation generator\n\n\n\t/**\n\t * @method constructor\n\t * @param {Object} cfg The configuration properties for the Match\n\t * instance, specified in an Object (map).\n\t */\n\tconstructor( cfg: MentionMatchConfig ) {\n\t\tsuper( cfg );\n\n\t\tthis.mention = cfg.mention;\n\t\tthis.serviceName = cfg.serviceName;\n\t}\n\n\n\t/**\n\t * Returns a string name for the type of match that this class represents.\n\t * For the case of MentionMatch, returns 'mention'.\n\t *\n\t * @return {String}\n\t */\n\tgetType() {\n\t\treturn 'mention';\n\t}\n\n\n\t/**\n\t * Returns the mention, without the '@' character.\n\t *\n\t * @return {String}\n\t */\n\tgetMention() {\n\t\treturn this.mention;\n\t}\n\n\n\t/**\n\t * Returns the configured {@link #serviceName} to point the mention to.\n\t * Ex: 'instagram', 'twitter', 'soundcloud'.\n\t *\n\t * @return {String}\n\t */\n\tgetServiceName() {\n\t\treturn this.serviceName;\n\t}\n\n\n\t/**\n\t * Returns the anchor href that should be generated for the match.\n\t *\n\t * @return {String}\n\t */\n\tgetAnchorHref() {\n\t\tswitch( this.serviceName ) {\n\t\t\tcase 'twitter' :\n\t\t\t\treturn 'https://twitter.com/' + this.mention;\n\t\t\tcase 'instagram' :\n\t\t\t\treturn 'https://instagram.com/' + this.mention;\n\t\t\tcase 'soundcloud' :\n\t\t\t\treturn 'https://soundcloud.com/' + this.mention;\n\n\t\t\tdefault : // Shouldn't happen because Autolinker's constructor should block any invalid values, but just in case.\n\t\t\t\tthrow new Error( 'Unknown service name to point mention to: ' + this.serviceName );\n\t\t}\n\t}\n\n\n\t/**\n\t * Returns the anchor text that should be generated for the match.\n\t *\n\t * @return {String}\n\t */\n\tgetAnchorText() {\n\t\treturn '@' + this.mention;\n\t}\n\n\n\t/**\n\t * Returns the CSS class suffixes that should be used on a tag built with\n\t * the match. See {@link Autolinker.match.Match#getCssClassSuffixes} for\n\t * details.\n\t *\n\t * @return {String[]}\n\t */\n\tgetCssClassSuffixes() {\n\t\tlet cssClassSuffixes = super.getCssClassSuffixes(),\n\t\t serviceName = this.getServiceName();\n\n\t\tif( serviceName ) {\n\t\t\tcssClassSuffixes.push( serviceName );\n\t\t}\n\t\treturn cssClassSuffixes;\n\t}\n\n}\n\nexport interface MentionMatchConfig extends MatchConfig {\n\tserviceName: MentionServices;\n\tmention: string;\n}"]}
|
||||
{"version":3,"sources":["../src/match/mention-match.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,KAAK,EAAe,MAAM,SAAS,CAAA;AAG5C;;;;;;;GAOG;AACH;IAAkC,wCAAK;IAgBtC;;;;OAIG;IACH,sBAAa,GAAuB;QAApC,YACC,kBAAM,GAAG,CAAC,SAIV;QAzBD;;;;;WAKG;QACc,iBAAW,GAAoB,SAAS,CAAA,CAAC,gGAAgG;QAE1J;;;;WAIG;QACc,aAAO,GAAW,EAAE,CAAA,CAAC,gGAAgG;QAUrI,KAAI,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAA;QAC1B,KAAI,CAAC,WAAW,GAAG,GAAG,CAAC,WAAW,CAAA;;IACnC,CAAC;IAED;;;;;OAKG;IACH,8BAAO,GAAP;QACC,OAAO,SAAS,CAAA;IACjB,CAAC;IAED;;;;OAIG;IACH,iCAAU,GAAV;QACC,OAAO,IAAI,CAAC,OAAO,CAAA;IACpB,CAAC;IAED;;;;;OAKG;IACH,qCAAc,GAAd;QACC,OAAO,IAAI,CAAC,WAAW,CAAA;IACxB,CAAC;IAED;;;;OAIG;IACH,oCAAa,GAAb;QACC,QAAQ,IAAI,CAAC,WAAW,EAAE;YACzB,KAAK,UAAU;gBACd,OAAO,sBAAsB,GAAG,IAAI,CAAC,OAAO,CAAA;YAC7C,KAAK,SAAS;gBACb,OAAO,sBAAsB,GAAG,IAAI,CAAC,OAAO,CAAA;YAC7C,KAAK,WAAW;gBACf,OAAO,wBAAwB,GAAG,IAAI,CAAC,OAAO,CAAA;YAC/C,KAAK,YAAY;gBAChB,OAAO,yBAAyB,GAAG,IAAI,CAAC,OAAO,CAAA;YAEhD;gBACC,uGAAuG;gBACvG,MAAM,IAAI,KAAK,CACd,4CAA4C,GAAG,IAAI,CAAC,WAAW,CAC/D,CAAA;SACF;IACF,CAAC;IAED;;;;OAIG;IACH,oCAAa,GAAb;QACC,OAAO,GAAG,GAAG,IAAI,CAAC,OAAO,CAAA;IAC1B,CAAC;IAED;;;;;;OAMG;IACH,0CAAmB,GAAnB;QACC,IAAI,gBAAgB,GAAG,iBAAM,mBAAmB,WAAE,EACjD,WAAW,GAAG,IAAI,CAAC,cAAc,EAAE,CAAA;QAEpC,IAAI,WAAW,EAAE;YAChB,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;SAClC;QACD,OAAO,gBAAgB,CAAA;IACxB,CAAC;IACF,mBAAC;AAAD,CA1GA,AA0GC,CA1GiC,KAAK,GA0GtC","file":"mention-match.js","sourcesContent":["import { Match, MatchConfig } from './match'\nimport { MentionServices } from '../autolinker'\n\n/**\n * @class Autolinker.match.Mention\n * @extends Autolinker.match.Match\n *\n * Represents a Mention match found in an input string which should be Autolinked.\n *\n * See this class's superclass ({@link Autolinker.match.Match}) for more details.\n */\nexport class MentionMatch extends Match {\n\t/**\n\t * @cfg {String} serviceName\n\t *\n\t * The service to point mention matches to. See {@link Autolinker#mention}\n\t * for available values.\n\t */\n\tprivate readonly serviceName: MentionServices = 'twitter' // default value just to get the above doc comment in the ES5 output and documentation generator\n\n\t/**\n\t * @cfg {String} mention (required)\n\t *\n\t * The Mention that was matched, without the '@' character.\n\t */\n\tprivate readonly mention: string = '' // default value just to get the above doc comment in the ES5 output and documentation generator\n\n\t/**\n\t * @method constructor\n\t * @param {Object} cfg The configuration properties for the Match\n\t * instance, specified in an Object (map).\n\t */\n\tconstructor (cfg: MentionMatchConfig) {\n\t\tsuper(cfg)\n\n\t\tthis.mention = cfg.mention\n\t\tthis.serviceName = cfg.serviceName\n\t}\n\n\t/**\n\t * Returns a string name for the type of match that this class represents.\n\t * For the case of MentionMatch, returns 'mention'.\n\t *\n\t * @return {String}\n\t */\n\tgetType () {\n\t\treturn 'mention'\n\t}\n\n\t/**\n\t * Returns the mention, without the '@' character.\n\t *\n\t * @return {String}\n\t */\n\tgetMention () {\n\t\treturn this.mention\n\t}\n\n\t/**\n\t * Returns the configured {@link #serviceName} to point the mention to.\n\t * Ex: 'instagram', 'twitter', 'soundcloud'.\n\t *\n\t * @return {String}\n\t */\n\tgetServiceName () {\n\t\treturn this.serviceName\n\t}\n\n\t/**\n\t * Returns the anchor href that should be generated for the match.\n\t *\n\t * @return {String}\n\t */\n\tgetAnchorHref () {\n\t\tswitch (this.serviceName) {\n\t\t\tcase 'mastodon':\n\t\t\t\treturn 'https://example.com/' + this.mention\n\t\t\tcase 'twitter':\n\t\t\t\treturn 'https://twitter.com/' + this.mention\n\t\t\tcase 'instagram':\n\t\t\t\treturn 'https://instagram.com/' + this.mention\n\t\t\tcase 'soundcloud':\n\t\t\t\treturn 'https://soundcloud.com/' + this.mention\n\n\t\t\tdefault:\n\t\t\t\t// Shouldn't happen because Autolinker's constructor should block any invalid values, but just in case.\n\t\t\t\tthrow new Error(\n\t\t\t\t\t'Unknown service name to point mention to: ' + this.serviceName\n\t\t\t\t)\n\t\t}\n\t}\n\n\t/**\n\t * Returns the anchor text that should be generated for the match.\n\t *\n\t * @return {String}\n\t */\n\tgetAnchorText () {\n\t\treturn '@' + this.mention\n\t}\n\n\t/**\n\t * Returns the CSS class suffixes that should be used on a tag built with\n\t * the match. See {@link Autolinker.match.Match#getCssClassSuffixes} for\n\t * details.\n\t *\n\t * @return {String[]}\n\t */\n\tgetCssClassSuffixes () {\n\t\tlet cssClassSuffixes = super.getCssClassSuffixes(),\n\t\t\tserviceName = this.getServiceName()\n\n\t\tif (serviceName) {\n\t\t\tcssClassSuffixes.push(serviceName)\n\t\t}\n\t\treturn cssClassSuffixes\n\t}\n}\n\nexport interface MentionMatchConfig extends MatchConfig {\n\tserviceName: MentionServices\n\tmention: string\n}\n"]}
|
@ -7,7 +7,7 @@ import { MentionMatch } from "../match/mention-match";
|
||||
// called multiple times, thus instantiating MentionMatcher and its RegExp
|
||||
// objects each time (which is very expensive - see https://github.com/gregjacobs/Autolinker.js/issues/314).
|
||||
// See descriptions of the properties where they are used for details about them
|
||||
var mastodonRegex = new RegExp("@[_@." + alphaNumericAndMarksCharsStr + "]{1,}(?![_" + alphaNumericAndMarksCharsStr + "])", 'g');
|
||||
var mastodonRegex = new RegExp("@[_" + alphaNumericAndMarksCharsStr + "]{1,}[@]?[_." + alphaNumericAndMarksCharsStr + "]{0,}(?![_" + alphaNumericAndMarksCharsStr + "])", 'g');
|
||||
var twitterRegex = new RegExp("@[_" + alphaNumericAndMarksCharsStr + "]{1,50}(?![_" + alphaNumericAndMarksCharsStr + "])", 'g'); // lookahead used to make sure we don't match something above 50 characters
|
||||
var instagramRegex = new RegExp("@[_." + alphaNumericAndMarksCharsStr + "]{1,30}(?![_" + alphaNumericAndMarksCharsStr + "])", 'g'); // lookahead used to make sure we don't match something above 30 characters
|
||||
var soundcloudRegex = new RegExp("@[-_." + alphaNumericAndMarksCharsStr + "]{1,50}(?![-_" + alphaNumericAndMarksCharsStr + "])", 'g'); // lookahead used to make sure we don't match something above 50 characters
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,6 +1,7 @@
|
||||
import { Feather } from '@expo/vector-icons'
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Alert,
|
||||
Keyboard,
|
||||
KeyboardAvoidingView,
|
||||
@ -13,11 +14,67 @@ import {
|
||||
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
|
||||
import Autolinker from 'src/modules/autolinker'
|
||||
import { useNavigation } from '@react-navigation/native'
|
||||
import { debounce, differenceWith, isEqual } from 'lodash'
|
||||
import { searchFetch } from '../common/searchFetch'
|
||||
import { useQuery } from 'react-query'
|
||||
import { FlatList } from 'react-native-gesture-handler'
|
||||
|
||||
const Stack = createNativeStackNavigator()
|
||||
|
||||
const Suggestion = React.memo(({ item, index }) => {
|
||||
return (
|
||||
<View key={index}>
|
||||
<Text>{item.acct ? item.acct : item.name}</Text>
|
||||
</View>
|
||||
)
|
||||
})
|
||||
|
||||
const Suggestions = ({
|
||||
type,
|
||||
text
|
||||
}: {
|
||||
type: 'mention' | 'hashtag'
|
||||
text: string
|
||||
}) => {
|
||||
const { status, data } = useQuery(
|
||||
[
|
||||
'Search',
|
||||
{ type: type === 'mention' ? 'accounts' : 'hashtags', term: text }
|
||||
],
|
||||
searchFetch,
|
||||
{ retry: false }
|
||||
)
|
||||
|
||||
let content
|
||||
switch (status) {
|
||||
case 'success':
|
||||
content = data[type === 'mention' ? 'accounts' : 'hashtags'].length ? (
|
||||
<FlatList
|
||||
data={data[type === 'mention' ? 'accounts' : 'hashtags']}
|
||||
renderItem={({ item, index, separators }) => (
|
||||
<Suggestion item={item} index={index} />
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<Text>空无一物</Text>
|
||||
)
|
||||
break
|
||||
case 'loading':
|
||||
content = <ActivityIndicator />
|
||||
break
|
||||
case 'error':
|
||||
content = <Text>搜索错误</Text>
|
||||
break
|
||||
default:
|
||||
content = <></>
|
||||
}
|
||||
|
||||
return content
|
||||
}
|
||||
|
||||
const PostTootMain = () => {
|
||||
const [viewHeight, setViewHeight] = useState(0)
|
||||
const [contentHeight, setContentHeight] = useState(0)
|
||||
const [keyboardHeight, setKeyboardHeight] = useState(0)
|
||||
useEffect(() => {
|
||||
Keyboard.addListener('keyboardDidShow', _keyboardDidShow)
|
||||
@ -39,33 +96,50 @@ const PostTootMain = () => {
|
||||
|
||||
const [charCount, setCharCount] = useState(0)
|
||||
const [formattedText, setFormattedText] = useState<React.ReactNode>()
|
||||
let prevTags = []
|
||||
const [suggestionsShown, setSuggestionsShown] = useState({
|
||||
display: false,
|
||||
tag: undefined
|
||||
})
|
||||
const debouncedSuggestions = useCallback(
|
||||
debounce(tag => setSuggestionsShown({ display: true, tag }), 300),
|
||||
[]
|
||||
)
|
||||
let prevTags: { type: 'url' | 'mention' | 'hashtag'; text: string }[] = []
|
||||
const onChangeText = useCallback(content => {
|
||||
const tags: string[] = []
|
||||
const tags: { type: 'url' | 'mention' | 'hashtag'; text: string }[] = []
|
||||
Autolinker.link(content, {
|
||||
email: true,
|
||||
email: false,
|
||||
phone: false,
|
||||
mention: 'mastodon',
|
||||
hashtag: 'twitter',
|
||||
replaceFn: props => {
|
||||
const tag = props.getMatchedText()
|
||||
tags.push(tag)
|
||||
return tag
|
||||
// @ts-ignore
|
||||
tags.push({ type: props.getType(), text: props.getMatchedText() })
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
const changedTag = differenceWith(prevTags, tags, isEqual)
|
||||
if (changedTag.length) {
|
||||
if (changedTag[0].type !== 'url') {
|
||||
debouncedSuggestions(changedTag[0])
|
||||
}
|
||||
} else {
|
||||
setSuggestionsShown({ display: false, tag: undefined })
|
||||
}
|
||||
prevTags = tags
|
||||
|
||||
let _content = content
|
||||
const children = []
|
||||
tags.forEach(tag => {
|
||||
const parts = _content.split(tag)
|
||||
const parts = _content.split(tag.text)
|
||||
children.push(parts.shift())
|
||||
children.push(
|
||||
<Text style={{ color: 'red' }} key={Math.random()}>
|
||||
{tag}
|
||||
{tag.text}
|
||||
</Text>
|
||||
)
|
||||
_content = parts.join(tag)
|
||||
_content = parts.join(tag.text)
|
||||
})
|
||||
children.push(_content)
|
||||
|
||||
@ -80,17 +154,39 @@ const PostTootMain = () => {
|
||||
>
|
||||
<View style={{ height: viewHeight - keyboardHeight }}>
|
||||
<TextInput
|
||||
style={styles.textInput}
|
||||
style={[
|
||||
styles.textInput,
|
||||
{
|
||||
flex: suggestionsShown.display ? 0 : 1,
|
||||
minHeight: contentHeight + 14
|
||||
}
|
||||
]}
|
||||
autoCapitalize='none'
|
||||
autoCorrect={false}
|
||||
autoFocus
|
||||
enablesReturnKeyAutomatically
|
||||
multiline
|
||||
placeholder='想说点什么'
|
||||
onChangeText={onChangeText}
|
||||
onContentSizeChange={({ nativeEvent }) => {
|
||||
setContentHeight(nativeEvent.contentSize.height)
|
||||
}}
|
||||
scrollEnabled
|
||||
>
|
||||
<Text>{formattedText}</Text>
|
||||
</TextInput>
|
||||
{suggestionsShown.display ? (
|
||||
<View
|
||||
style={[
|
||||
styles.suggestions
|
||||
// { height: viewHeight - contentHeight - keyboardHeight - 44 }
|
||||
]}
|
||||
>
|
||||
<Suggestions {...suggestionsShown.tag} />
|
||||
</View>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
<Pressable style={styles.additions} onPress={() => Keyboard.dismiss()}>
|
||||
<Feather name='paperclip' size={24} />
|
||||
<Feather name='bar-chart-2' size={24} />
|
||||
@ -144,9 +240,12 @@ const styles = StyleSheet.create({
|
||||
flex: 1
|
||||
},
|
||||
textInput: {
|
||||
flex: 1,
|
||||
backgroundColor: 'gray'
|
||||
},
|
||||
suggestions: {
|
||||
flex: 1,
|
||||
backgroundColor: 'lightyellow'
|
||||
},
|
||||
additions: {
|
||||
height: 44,
|
||||
backgroundColor: 'red',
|
||||
|
23
src/stacks/common/searchFetch.ts
Normal file
23
src/stacks/common/searchFetch.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import client from 'src/api/client'
|
||||
|
||||
export const searchFetch = async (
|
||||
{} = {},
|
||||
{
|
||||
type,
|
||||
term,
|
||||
limit = 20
|
||||
}: {
|
||||
type: 'accounts' | 'hashtags' | 'statuses'
|
||||
term: string
|
||||
limit?: number
|
||||
}
|
||||
) => {
|
||||
const res = await client({
|
||||
version: 'v2',
|
||||
method: 'get',
|
||||
instance: 'local',
|
||||
endpoint: 'search',
|
||||
query: { type, q: term, limit }
|
||||
})
|
||||
return Promise.resolve(res.body)
|
||||
}
|
Loading…
Reference in New Issue
Block a user