Place cursor position in between the phrase modifier (#6828)

This commit is contained in:
Elias Nahum
2022-12-06 18:36:48 +02:00
committed by GitHub
parent 00039cb21b
commit 5e3e7b151e
6 changed files with 77 additions and 18 deletions

View File

@@ -47,6 +47,7 @@ export type SearchRef = {
cancel: () => void;
clear: () => void;
focus: () => void;
setNativeProps(nativeProps: object): void;
}
const getStyleSheet = makeStyleSheetFromTheme((theme: Theme) => ({
@@ -151,6 +152,9 @@ const Search = forwardRef<SearchRef, SearchProps>((props: SearchProps, ref) => {
focus: () => {
searchRef.current?.focus();
},
setNativeProps: (nativeProps: object) => {
searchRef.current?.setNativeProps(nativeProps);
},
}), [searchRef]);
return (

View File

@@ -1,9 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react';
import React, {Dispatch, RefObject, SetStateAction} from 'react';
import Animated from 'react-native-reanimated';
import {SearchRef} from '@components/search';
import {TeamModel} from '@database/models/server';
import Modifiers from './modifiers';
@@ -15,19 +16,21 @@ type Props = {
recentSearches: TeamSearchHistoryModel[];
scrollEnabled: Animated.SharedValue<boolean>;
searchValue?: string;
setRecentValue: (value: string) => void;
setSearchValue: (value: string) => void;
setRecentValue: Dispatch<SetStateAction<string>>;
searchRef: RefObject<SearchRef>;
setSearchValue: Dispatch<SetStateAction<string>>;
setTeamId: (value: string) => void;
teamId: string;
teamName: string;
teams: TeamModel[];
}
const Initial = ({recentSearches, scrollEnabled, searchValue, setRecentValue, teamId, teamName, teams, setTeamId, setSearchValue}: Props) => {
const Initial = ({recentSearches, scrollEnabled, searchValue, setRecentValue, searchRef, teamId, teamName, teams, setTeamId, setSearchValue}: Props) => {
return (
<>
<Modifiers
searchValue={searchValue}
searchRef={searchRef}
setSearchValue={setSearchValue}
setTeamId={setTeamId}
teamId={teamId}

View File

@@ -1,12 +1,13 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useCallback, useEffect, useMemo, useRef, useState} from 'react';
import React, {Dispatch, RefObject, SetStateAction, useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {IntlShape, useIntl} from 'react-intl';
import {View} from 'react-native';
import Animated, {useSharedValue, useAnimatedStyle, withTiming} from 'react-native-reanimated';
import FormattedText from '@components/formatted_text';
import {SearchRef} from '@components/search';
import {useTheme} from '@context/theme';
import {TeamModel} from '@database/models/server';
import TeamPickerIcon from '@screens/home/search/team_picker_icon';
@@ -73,6 +74,7 @@ const getModifiersSectionsData = (intl: IntlShape): ModifierItem[] => {
term: '""',
testID: 'search.modifier.phrases',
description: formatMessage({id: 'mobile.search.modifier.phrases', defaultMessage: ' messages with phrases'}),
cursorPosition: -1,
},
];
return sectionsData;
@@ -80,13 +82,14 @@ const getModifiersSectionsData = (intl: IntlShape): ModifierItem[] => {
type Props = {
scrollEnabled: Animated.SharedValue<boolean>;
setSearchValue: (value: string) => void;
searchRef: RefObject<SearchRef>;
setSearchValue: Dispatch<SetStateAction<string>>;
searchValue?: string;
setTeamId: (id: string) => void;
teamId: string;
teams: TeamModel[];
}
const Modifiers = ({scrollEnabled, searchValue, setSearchValue, setTeamId, teamId, teams}: Props) => {
const Modifiers = ({scrollEnabled, searchValue, setSearchValue, searchRef, setTeamId, teamId, teams}: Props) => {
const theme = useTheme();
const intl = useIntl();
@@ -130,6 +133,7 @@ const Modifiers = ({scrollEnabled, searchValue, setSearchValue, setTeamId, teamI
<Modifier
key={item.term}
item={item}
searchRef={searchRef}
searchValue={searchValue}
setSearchValue={setSearchValue}
/>

View File

@@ -1,10 +1,11 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useCallback} from 'react';
import React, {Dispatch, RefObject, SetStateAction, useCallback} from 'react';
import {StyleSheet} from 'react-native';
import OptionItem from '@components/option_item';
import {SearchRef} from '@components/search';
import {preventDoubleTap} from '@utils/tap';
const styles = StyleSheet.create({
@@ -14,18 +15,20 @@ const styles = StyleSheet.create({
});
export type ModifierItem = {
description: string;
testID: string;
term: string;
cursorPosition?: number;
description: string;
testID: string;
term: string;
}
type Props = {
item: ModifierItem;
setSearchValue: (value: string) => void;
setSearchValue: Dispatch<SetStateAction<string>>;
searchValue?: string;
searchRef: RefObject<SearchRef>;
}
const Modifier = ({item, searchValue, setSearchValue}: Props) => {
const Modifier = ({item, searchRef, searchValue, setSearchValue}: Props) => {
const handlePress = useCallback(() => {
addModifierTerm(item.term);
}, [item.term, searchValue]);
@@ -41,6 +44,12 @@ const Modifier = ({item, searchValue, setSearchValue}: Props) => {
}
setSearchValue(newValue);
if (item.cursorPosition) {
const position = newValue.length + item.cursorPosition;
requestAnimationFrame(() => {
searchRef.current?.setNativeProps({selection: {start: position, end: position}});
});
}
});
return (

View File

@@ -240,6 +240,7 @@ const SearchScreen = ({teamId, teams}: Props) => {
scrollEnabled={scrollEnabled}
searchValue={searchValue}
setRecentValue={handleRecentSearch}
searchRef={searchRef}
setSearchValue={handleModifierTextChange}
setTeamId={setSearchTeamId}
teamId={searchTeamId}

View File

@@ -1,5 +1,5 @@
diff --git a/node_modules/react-native-elements/dist/searchbar/SearchBar-android.js b/node_modules/react-native-elements/dist/searchbar/SearchBar-android.js
index 1bfd2b4..436e870 100644
index 1bfd2b4..a4f6f77 100644
--- a/node_modules/react-native-elements/dist/searchbar/SearchBar-android.js
+++ b/node_modules/react-native-elements/dist/searchbar/SearchBar-android.js
@@ -10,7 +10,7 @@ var __rest = (this && this.__rest) || function (s, e) {
@@ -11,7 +11,7 @@ index 1bfd2b4..436e870 100644
import { renderNode } from '../helpers';
import Input from '../input/Input';
import Icon from '../icons/Icon';
@@ -68,24 +68,17 @@ class SearchBar extends Component {
@@ -68,24 +68,20 @@ class SearchBar extends Component {
};
this.onBlur = (event) => {
this.props.onBlur(event);
@@ -24,7 +24,9 @@ index 1bfd2b4..436e870 100644
};
- this._keyboardDidHide = () => {
- this.cancel();
- };
+ this.setNativeProps = (nativeProps: object) => {
+ this.input.setNativeProps && this.input.setNativeProps(nativeProps);
};
const { value = '' } = props;
this.state = {
hasFocus: false,
@@ -38,10 +40,20 @@ index 1bfd2b4..436e870 100644
render() {
var _a;
diff --git a/node_modules/react-native-elements/dist/searchbar/SearchBar-ios.js b/node_modules/react-native-elements/dist/searchbar/SearchBar-ios.js
index 8fe90be..3daf517 100644
index 8fe90be..69ab1ff 100644
--- a/node_modules/react-native-elements/dist/searchbar/SearchBar-ios.js
+++ b/node_modules/react-native-elements/dist/searchbar/SearchBar-ios.js
@@ -85,6 +85,11 @@ class SearchBar extends Component {
@@ -78,6 +78,9 @@ class SearchBar extends Component {
this.props.onChangeText(text);
this.setState({ isEmpty: text === '' });
};
+ this.setNativeProps = (nativeProps: object) => {
+ this.input.setNativeProps && this.input.setNativeProps(nativeProps);
+ };
const { value } = props;
this.state = {
hasFocus: false,
@@ -85,6 +88,11 @@ class SearchBar extends Component {
cancelButtonWidth: null,
};
}
@@ -53,3 +65,29 @@ index 8fe90be..3daf517 100644
render() {
var _a, _b, _c, _d, _e, _f, _g;
const _h = this.props, { theme, cancelButtonProps, cancelButtonTitle, clearIcon, containerStyle, leftIconContainerStyle, rightIconContainerStyle, inputContainerStyle, inputStyle, placeholderTextColor, showLoading, loadingProps, searchIcon, showCancel } = _h, attributes = __rest(_h, ["theme", "cancelButtonProps", "cancelButtonTitle", "clearIcon", "containerStyle", "leftIconContainerStyle", "rightIconContainerStyle", "inputContainerStyle", "inputStyle", "placeholderTextColor", "showLoading", "loadingProps", "searchIcon", "showCancel"]);
diff --git a/node_modules/react-native-elements/dist/searchbar/SearchBar.d.ts b/node_modules/react-native-elements/dist/searchbar/SearchBar.d.ts
index 61844a8..a22a37c 100644
--- a/node_modules/react-native-elements/dist/searchbar/SearchBar.d.ts
+++ b/node_modules/react-native-elements/dist/searchbar/SearchBar.d.ts
@@ -21,6 +21,7 @@ export declare type SearchBarBaseProps = React.ComponentPropsWithRef<typeof Text
onBlur?(): void;
onChangeText?(text: string): void;
onCancel?(): void;
+ setNativeProps: (nativeProps: object) => void;
};
export declare type SearchBarProps = SearchBarBaseProps & SearchBarDefaultProps & SearchBarAndroidProps & SearchBarIosProps;
declare class SearchBar extends React.Component<SearchBarProps & Partial<ThemeProps<SearchBarProps>>> {
diff --git a/node_modules/react-native-elements/dist/searchbar/SearchBar.js b/node_modules/react-native-elements/dist/searchbar/SearchBar.js
index 43db650..6e8ebf5 100644
--- a/node_modules/react-native-elements/dist/searchbar/SearchBar.js
+++ b/node_modules/react-native-elements/dist/searchbar/SearchBar.js
@@ -23,6 +23,9 @@ class SearchBar extends React.Component {
this.cancel = () => {
this.searchbar.cancel && this.searchbar.cancel();
};
+ this.setNativeProps = (nativeProps: object) => {
+ this.searchbar.setNativeProps && this.searchbar.setNativeProps(nativeProps);
+ };
}
render() {
const Component = SEARCHBAR_COMPONENTS[this.props.platform] || DefaultSearchBar;