Skip to content

Commit

Permalink
Merge pull request Expensify#30514 from pasyukevich/feature/migrate-M…
Browse files Browse the repository at this point in the history
…entionSuggestions

[TS migration] Migrate 'MentionSuggestions.js' component to TypeScript
  • Loading branch information
MonilBhavsar authored Nov 15, 2023
2 parents e0bccf0 + 9fbce16 commit e953a65
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 72 deletions.
Original file line number Diff line number Diff line change
@@ -1,73 +1,61 @@
import PropTypes from 'prop-types';
import React from 'react';
import {View} from 'react-native';
import _ from 'underscore';
import getStyledTextArray from '@libs/GetStyledTextArray';
import styles from '@styles/styles';
import * as StyleUtils from '@styles/StyleUtils';
import themeColors from '@styles/themes/default';
import CONST from '@src/CONST';
import {Icon} from '@src/types/onyx/OnyxCommon';
import AutoCompleteSuggestions from './AutoCompleteSuggestions';
import Avatar from './Avatar';
import avatarPropTypes from './avatarPropTypes';
import Text from './Text';

const propTypes = {
/** The index of the highlighted mention */
highlightedMentionIndex: PropTypes.number,
type Mention = {
/** Display name of the user */
text: string;

/** Array of suggested mentions */
mentions: PropTypes.arrayOf(
PropTypes.shape({
/** Display name of the user */
text: PropTypes.string,
/** Email/phone number of the user */
alternateText: string;

/** Array of icons of the user. We use the first element of this array */
icons: Icon[];
};

/** Email/phone number of the user */
alternateText: PropTypes.string,
type MentionSuggestionsProps = {
/** The index of the highlighted mention */
highlightedMentionIndex?: number;

/** Array of icons of the user. We use the first element of this array */
icons: PropTypes.arrayOf(avatarPropTypes),
}),
).isRequired,
/** Array of suggested mentions */
mentions: Mention[];

/** Fired when the user selects an mention */
onSelect: PropTypes.func.isRequired,
onSelect: () => void;

/** Mention prefix that follows the @ sign */
prefix: PropTypes.string.isRequired,
prefix: string;

/** Show that we can use large mention picker.
* Depending on available space and whether the input is expanded, we can have a small or large mention suggester.
* When this value is false, the suggester will have a height of 2.5 items. When this value is true, the height can be up to 5 items. */
isMentionPickerLarge: PropTypes.bool.isRequired,
isMentionPickerLarge: boolean;

/** Meaures the parent container's position and dimensions. */
measureParentContainer: PropTypes.func,
};

const defaultProps = {
highlightedMentionIndex: 0,
measureParentContainer: () => {},
measureParentContainer: () => void;
};

/**
* Create unique keys for each mention item
* @param {Object} item
* @param {Number} index
* @returns {String}
*/
const keyExtractor = (item) => item.alternateText;
const keyExtractor = (item: Mention) => item.alternateText;

function MentionSuggestions(props) {
function MentionSuggestions({prefix, mentions, highlightedMentionIndex = 0, onSelect, isMentionPickerLarge, measureParentContainer = () => {}}: MentionSuggestionsProps) {
/**
* Render a suggestion menu item component.
* @param {Object} item
* @returns {JSX.Element}
*/
const renderSuggestionMenuItem = (item) => {
const renderSuggestionMenuItem = (item: Mention) => {
const isIcon = item.text === CONST.AUTO_COMPLETE_SUGGESTER.HERE_TEXT;
const styledDisplayName = getStyledTextArray(item.text, props.prefix);
const styledHandle = item.text === item.alternateText ? '' : getStyledTextArray(item.alternateText, props.prefix);
const styledDisplayName = getStyledTextArray(item.text, prefix);
const styledHandle = item.text === item.alternateText ? undefined : getStyledTextArray(item.alternateText, prefix);

return (
<View style={[styles.autoCompleteSuggestionContainer, styles.ph2]}>
Expand All @@ -85,8 +73,9 @@ function MentionSuggestions(props) {
style={[styles.mentionSuggestionsText, styles.flexShrink1]}
numberOfLines={1}
>
{_.map(styledDisplayName, ({text, isColored}, i) => (
{styledDisplayName?.map(({text, isColored}, i) => (
<Text
// eslint-disable-next-line react/no-array-index-key
key={`${text}${i}`}
style={[StyleUtils.getColoredBackgroundStyle(isColored), styles.mentionSuggestionsDisplayName]}
>
Expand All @@ -98,13 +87,13 @@ function MentionSuggestions(props) {
style={[styles.mentionSuggestionsText, styles.flex1]}
numberOfLines={1}
>
{_.map(
styledHandle,
{styledHandle?.map(
({text, isColored}, i) =>
text !== '' && (
Boolean(text) && (
<Text
// eslint-disable-next-line react/no-array-index-key
key={`${text}${i}`}
style={[StyleUtils.getColoredBackgroundStyle(isColored), styles.mentionSuggestionsHandle, {...(isColored && {color: styles.text})}]}
style={[StyleUtils.getColoredBackgroundStyle(isColored), styles.mentionSuggestionsHandle]}
>
{text}
</Text>
Expand All @@ -117,20 +106,18 @@ function MentionSuggestions(props) {

return (
<AutoCompleteSuggestions
suggestions={props.mentions}
suggestions={mentions}
renderSuggestionMenuItem={renderSuggestionMenuItem}
keyExtractor={keyExtractor}
highlightedSuggestionIndex={props.highlightedMentionIndex}
onSelect={props.onSelect}
isSuggestionPickerLarge={props.isMentionPickerLarge}
highlightedSuggestionIndex={highlightedMentionIndex}
onSelect={onSelect}
isSuggestionPickerLarge={isMentionPickerLarge}
accessibilityLabelExtractor={keyExtractor}
measureParentContainer={props.measureParentContainer}
measureParentContainer={measureParentContainer}
/>
);
}

MentionSuggestions.propTypes = propTypes;
MentionSuggestions.defaultProps = defaultProps;
MentionSuggestions.displayName = 'MentionSuggestions';

export default MentionSuggestions;
2 changes: 1 addition & 1 deletion src/styles/StyleUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1018,7 +1018,7 @@ function getAutoCompleteSuggestionContainerStyle(itemsHeight: number): ViewStyle
/**
* Select the correct color for text.
*/
function getColoredBackgroundStyle(isColored: boolean): TextStyle {
function getColoredBackgroundStyle(isColored: boolean): StyleProp<TextStyle> {
return {backgroundColor: isColored ? themeColors.link : undefined};
}

Expand Down
21 changes: 0 additions & 21 deletions src/styles/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,10 +328,6 @@ const styles = (theme: ThemeColors) =>
textAlign: 'left',
},

textUnderline: {
textDecorationLine: 'underline',
},

verticalAlignMiddle: {
verticalAlign: 'middle',
},
Expand Down Expand Up @@ -392,10 +388,6 @@ const styles = (theme: ThemeColors) =>
fontSize: variables.fontSizeLarge,
},

textXLarge: {
fontSize: variables.fontSizeXLarge,
},

textXXLarge: {
fontSize: variables.fontSizeXXLarge,
},
Expand All @@ -415,11 +407,6 @@ const styles = (theme: ThemeColors) =>
fontWeight: fontWeightBold,
},

textItalic: {
fontFamily: fontFamily.EXP_NEUE_ITALIC,
fontStyle: 'italic',
},

textHeadline: {
...headlineFont,
...whiteSpace.preWrap,
Expand All @@ -436,10 +423,6 @@ const styles = (theme: ThemeColors) =>
lineHeight: variables.lineHeightSizeh1,
},

textDecorationNoLine: {
textDecorationLine: 'none',
},

textWhite: {
color: theme.textLight,
},
Expand All @@ -448,10 +431,6 @@ const styles = (theme: ThemeColors) =>
color: theme.link,
},

textUppercase: {
textTransform: 'uppercase',
},

textNoWrap: {
...whiteSpace.noWrap,
},
Expand Down
7 changes: 5 additions & 2 deletions src/types/onyx/OnyxCommon.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as React from 'react';
import {SvgProps} from 'react-native-svg';
import {ValueOf} from 'type-fest';
import CONST from '@src/CONST';

Expand All @@ -11,9 +12,11 @@ type ErrorFields<TKey extends string = string> = Record<TKey, Errors | null | un
type Errors = Record<string, string>;

type Icon = {
source: React.ReactNode | string;
type: 'avatar' | 'workspace';
source: string | React.FC<SvgProps>;
type: typeof CONST.ICON_TYPE_AVATAR | typeof CONST.ICON_TYPE_WORKSPACE;
name: string;
id: number | string;
fallbackIcon?: string | React.FC<SvgProps>;
};

export type {Icon, PendingAction, PendingFields, ErrorFields, Errors};

0 comments on commit e953a65

Please sign in to comment.