diff --git a/src/CONST.ts b/src/CONST.ts index 82f6e2e7bb6a..d929a01e030a 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -2305,8 +2305,8 @@ const CONST = { // eslint-disable-next-line max-len, no-misleading-character-class EMOJI: /[\p{Extended_Pictographic}\u200d\u{1f1e6}-\u{1f1ff}\u{1f3fb}-\u{1f3ff}\u{e0020}-\u{e007f}\u20E3\uFE0F]|[#*0-9]\uFE0F?\u20E3/gu, - // eslint-disable-next-line max-len, no-misleading-character-class - EMOJIS: /[\p{Extended_Pictographic}](\u200D[\p{Extended_Pictographic}]|[\u{1F3FB}-\u{1F3FF}]|[\u{E0020}-\u{E007F}]|\uFE0F|\u20E3)*|[\u{1F1E6}-\u{1F1FF}]{2}|[#*0-9]\uFE0F?\u20E3/gu, + // eslint-disable-next-line max-len, no-misleading-character-class, no-empty-character-class + EMOJIS: /[\p{Extended_Pictographic}](\u200D[\p{Extended_Pictographic}]|[\u{1F3FB}-\u{1F3FF}]|[\u{E0020}-\u{E007F}]|\uFE0F|\u20E3)*|[\u{1F1E6}-\u{1F1FF}]{2}|[#*0-9]\uFE0F?\u20E3/du, // eslint-disable-next-line max-len, no-misleading-character-class EMOJI_SKIN_TONES: /[\u{1f3fb}-\u{1f3ff}]/gu, diff --git a/src/components/Composer/index.native.tsx b/src/components/Composer/index.native.tsx index d5dc4c12afc0..9c380eb336c3 100644 --- a/src/components/Composer/index.native.tsx +++ b/src/components/Composer/index.native.tsx @@ -39,9 +39,9 @@ function Composer( ) { const textInput = useRef(null); const {isFocused, shouldResetFocusRef} = useResetComposerFocus(textInput); - const textContainsOnlyEmojis = useMemo(() => EmojiUtils.containsOnlyEmojis(value ?? ''), [value]); + const doesTextContainOnlyEmojis = useMemo(() => EmojiUtils.containsOnlyEmojis(value ?? ''), [value]); const theme = useTheme(); - const markdownStyle = useMarkdownStyle(value, !isGroupPolicyReport ? excludeReportMentionStyle : excludeNoStyles); + const markdownStyle = useMarkdownStyle(doesTextContainOnlyEmojis, !isGroupPolicyReport ? excludeReportMentionStyle : excludeNoStyles); const styles = useThemeStyles(); const StyleUtils = useStyleUtils(); @@ -73,7 +73,10 @@ function Composer( }, [shouldClear, onClear]); const maxHeightStyle = useMemo(() => StyleUtils.getComposerMaxHeightStyle(maxLines, isComposerFullSize), [StyleUtils, isComposerFullSize, maxLines]); - const composerStyle = useMemo(() => StyleSheet.flatten([style, textContainsOnlyEmojis ? styles.onlyEmojisTextLineHeight : {}]), [style, textContainsOnlyEmojis, styles]); + const composerStyle = useMemo( + () => StyleSheet.flatten([style, doesTextContainOnlyEmojis ? styles.onlyEmojisTextLineHeight : styles.emojisWithTextLineHeight]), + [style, doesTextContainOnlyEmojis, styles], + ); return ( , ) { - const textContainsOnlyEmojis = useMemo(() => EmojiUtils.containsOnlyEmojis(value ?? ''), [value]); + const doesTextContainOnlyEmojis = useMemo(() => EmojiUtils.containsOnlyEmojis(value ?? ''), [value]); const theme = useTheme(); const styles = useThemeStyles(); - const markdownStyle = useMarkdownStyle(value, !isGroupPolicyReport ? excludeReportMentionStyle : excludeNoStyles); + const markdownStyle = useMarkdownStyle(doesTextContainOnlyEmojis, !isGroupPolicyReport ? excludeReportMentionStyle : excludeNoStyles); const StyleUtils = useStyleUtils(); const textRef = useRef(null); const textInput = useRef(null); @@ -345,10 +345,9 @@ function Composer( scrollStyleMemo, StyleUtils.getComposerMaxHeightStyle(maxLines, isComposerFullSize), isComposerFullSize ? ({height: '100%', maxHeight: 'none' as DimensionValue} as TextStyle) : undefined, - textContainsOnlyEmojis ? styles.onlyEmojisTextLineHeight : {}, ], - [style, styles.rtlTextRenderForSafari, styles.onlyEmojisTextLineHeight, scrollStyleMemo, StyleUtils, maxLines, isComposerFullSize, textContainsOnlyEmojis], + [style, styles.rtlTextRenderForSafari, scrollStyleMemo, StyleUtils, maxLines, isComposerFullSize], ); return ( diff --git a/src/components/InlineCodeBlock/WrappedText.tsx b/src/components/InlineCodeBlock/WrappedText.tsx index 3045c15c471b..e77f5dba4eda 100644 --- a/src/components/InlineCodeBlock/WrappedText.tsx +++ b/src/components/InlineCodeBlock/WrappedText.tsx @@ -37,7 +37,8 @@ function getTextMatrix(text: string): string[][] { * Validates if the text contains any emoji */ function containsEmoji(text: string): boolean { - return CONST.REGEX.EMOJIS.test(text); + const emojisRegex = new RegExp(CONST.REGEX.EMOJIS, CONST.REGEX.EMOJIS.flags.concat('g')); + return emojisRegex.test(text); } function WrappedText({children, wordStyles, textStyles}: WrappedTextProps) { diff --git a/src/components/SelectionList/Search/UserInfoCell.tsx b/src/components/SelectionList/Search/UserInfoCell.tsx index 2a5a7da51979..d89220935dc5 100644 --- a/src/components/SelectionList/Search/UserInfoCell.tsx +++ b/src/components/SelectionList/Search/UserInfoCell.tsx @@ -32,7 +32,7 @@ function UserInfoCell({participant, displayName}: UserInfoCellProps) { /> {displayName} diff --git a/src/components/SelectionList/UserListItem.tsx b/src/components/SelectionList/UserListItem.tsx index 104990cf479c..119ebd9fd535 100644 --- a/src/components/SelectionList/UserListItem.tsx +++ b/src/components/SelectionList/UserListItem.tsx @@ -12,6 +12,7 @@ import useLocalize from '@hooks/useLocalize'; import useStyleUtils from '@hooks/useStyleUtils'; import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; +import variables from '@styles/variables'; import CONST from '@src/CONST'; import BaseListItem from './BaseListItem'; import type {ListItem, UserListItemProps} from './types'; @@ -131,6 +132,7 @@ function UserListItem({ {!!item.alternateText && ( diff --git a/src/components/TextInput/BaseTextInput/index.tsx b/src/components/TextInput/BaseTextInput/index.tsx index 685d54d86765..7764bdad0a60 100644 --- a/src/components/TextInput/BaseTextInput/index.tsx +++ b/src/components/TextInput/BaseTextInput/index.tsx @@ -386,6 +386,7 @@ function BaseTextInput( // Add disabled color theme when field is not editable. inputProps.disabled && styles.textInputDisabled, styles.pointerEventsAuto, + isMarkdownEnabled ? {lineHeight: variables.lineHeightMarkdownEnabledInput} : null, ]} multiline={isMultiline} maxLength={maxLength} diff --git a/src/components/TextWithTooltip/index.native.tsx b/src/components/TextWithTooltip/index.android.tsx similarity index 100% rename from src/components/TextWithTooltip/index.native.tsx rename to src/components/TextWithTooltip/index.android.tsx diff --git a/src/components/TextWithTooltip/index.ios.tsx b/src/components/TextWithTooltip/index.ios.tsx new file mode 100644 index 000000000000..f7c325b6d14e --- /dev/null +++ b/src/components/TextWithTooltip/index.ios.tsx @@ -0,0 +1,31 @@ +import React, {useMemo} from 'react'; +import Text from '@components/Text'; +import * as EmojiUtils from '@libs/EmojiUtils'; +import CONST from '@src/CONST'; +import type TextWithTooltipProps from './types'; + +function TextWithTooltip({text, style, emojiFontSize, numberOfLines = 1}: TextWithTooltipProps) { + const processedTextArray = useMemo(() => { + const emojisRegex = new RegExp(CONST.REGEX.EMOJIS, CONST.REGEX.EMOJIS.flags.concat('g')); + const doesTextContainEmojis = !!(emojiFontSize && emojisRegex.test(text)); + + if (!doesTextContainEmojis) { + return []; + } + + return EmojiUtils.splitTextWithEmojis(text); + }, [emojiFontSize, text]); + + return ( + + {processedTextArray.length !== 0 ? processedTextArray.map(({text: textItem, isEmoji}) => (isEmoji ? {textItem} : textItem)) : text} + + ); +} + +TextWithTooltip.displayName = 'TextWithTooltip'; + +export default TextWithTooltip; diff --git a/src/components/TextWithTooltip/types.ts b/src/components/TextWithTooltip/types.ts index 4705e2b69a68..1df5af02b67a 100644 --- a/src/components/TextWithTooltip/types.ts +++ b/src/components/TextWithTooltip/types.ts @@ -12,6 +12,9 @@ type TextWithTooltipProps = { /** Custom number of lines for text wrapping */ numberOfLines?: number; + + /** Emoji font size */ + emojiFontSize?: number; }; export default TextWithTooltipProps; diff --git a/src/hooks/useMarkdownStyle.ts b/src/hooks/useMarkdownStyle.ts index c7e9bf2c0218..b3b2b33ae71a 100644 --- a/src/hooks/useMarkdownStyle.ts +++ b/src/hooks/useMarkdownStyle.ts @@ -1,16 +1,13 @@ import type {MarkdownStyle} from '@expensify/react-native-live-markdown'; import {useMemo} from 'react'; -import {containsOnlyEmojis} from '@libs/EmojiUtils'; import FontUtils from '@styles/utils/FontUtils'; import variables from '@styles/variables'; import useTheme from './useTheme'; const defaultEmptyArray: Array = []; -function useMarkdownStyle(message: string | null = null, excludeStyles: Array = defaultEmptyArray): MarkdownStyle { +function useMarkdownStyle(doesInputContainOnlyEmojis?: boolean, excludeStyles: Array = defaultEmptyArray): MarkdownStyle { const theme = useTheme(); - const hasMessageOnlyEmojis = message != null && message.length > 0 && containsOnlyEmojis(message); - const emojiFontSize = hasMessageOnlyEmojis ? variables.fontSizeOnlyEmojis : variables.fontSizeNormal; // this map is used to reset the styles that are not needed - passing undefined value can break the native side const nonStylingDefaultValues: Record = useMemo( @@ -37,7 +34,7 @@ function useMarkdownStyle(message: string | null = null, excludeStyles: Array lastMatchIndexEnd) { + splitText.push({ + text: text.slice(lastMatchIndexEnd, matchIndexStart), + isEmoji: false, + }); + } + + splitText.push({ + text: text.slice(matchIndexStart, matchIndexEnd), + isEmoji: true, + }); + + lastMatchIndexEnd = matchIndexEnd; + } + } while (regexResult !== null); + + if (lastMatchIndexEnd < text.length) { + splitText.push({ + text: text.slice(lastMatchIndexEnd, text.length), + isEmoji: false, + }); + } + + return splitText; +} + +export type {HeaderIndice, EmojiPickerList, EmojiSpacer, EmojiPickerListItem, TextWithEmoji}; export { findEmojiByName, @@ -611,4 +664,5 @@ export { hasAccountIDEmojiReacted, getRemovedSkinToneEmoji, getSpacersIndexes, + splitTextWithEmojis, }; diff --git a/src/libs/ValidationUtils.ts b/src/libs/ValidationUtils.ts index 64cae69e0b15..cb2304fc46a4 100644 --- a/src/libs/ValidationUtils.ts +++ b/src/libs/ValidationUtils.ts @@ -41,7 +41,9 @@ function isValidAddress(value: FormValue): boolean { return false; } - if (!CONST.REGEX.ANY_VALUE.test(value) || value.match(CONST.REGEX.EMOJIS)) { + const emojisRegex = new RegExp(CONST.REGEX.EMOJIS, CONST.REGEX.EMOJIS.flags.concat('g')); + + if (!CONST.REGEX.ANY_VALUE.test(value) || value.match(emojisRegex)) { return false; } @@ -331,7 +333,8 @@ function isValidRoutingNumber(routingNumber: string): boolean { * Checks that the provided name doesn't contain any emojis */ function isValidCompanyName(name: string) { - return !name.match(CONST.REGEX.EMOJIS); + const emojisRegex = new RegExp(CONST.REGEX.EMOJIS, CONST.REGEX.EMOJIS.flags.concat('g')); + return !name.match(emojisRegex); } function isValidReportName(name: string) { diff --git a/src/pages/home/report/ReportActionItemFragment.tsx b/src/pages/home/report/ReportActionItemFragment.tsx index 088ee9eb2b6e..7c0974f74a4b 100644 --- a/src/pages/home/report/ReportActionItemFragment.tsx +++ b/src/pages/home/report/ReportActionItemFragment.tsx @@ -2,7 +2,6 @@ import React, {memo} from 'react'; import type {StyleProp, TextStyle} from 'react-native'; import RenderHTML from '@components/RenderHTML'; import Text from '@components/Text'; -import UserDetailsTooltip from '@components/UserDetailsTooltip'; import useLocalize from '@hooks/useLocalize'; import useNetwork from '@hooks/useNetwork'; import useThemeStyles from '@hooks/useThemeStyles'; @@ -15,6 +14,7 @@ import type {Message} from '@src/types/onyx/ReportAction'; import type ReportActionName from '@src/types/onyx/ReportActionName'; import AttachmentCommentFragment from './comment/AttachmentCommentFragment'; import TextCommentFragment from './comment/TextCommentFragment'; +import ReportActionItemMessageHeaderSender from './ReportActionItemMessageHeaderSender'; type ReportActionItemFragmentProps = { /** Users accountID */ @@ -159,18 +159,13 @@ function ReportActionItemFragment({ } return ( - - - {fragment?.text} - - + fragmentText={fragment.text} + actorIcon={actorIcon} + isSingleLine={isSingleLine} + /> ); } case 'LINK': diff --git a/src/pages/home/report/ReportActionItemMessageHeaderSender.tsx b/src/pages/home/report/ReportActionItemMessageHeaderSender.tsx new file mode 100644 index 000000000000..e31f8c55947f --- /dev/null +++ b/src/pages/home/report/ReportActionItemMessageHeaderSender.tsx @@ -0,0 +1,58 @@ +import React, {useMemo} from 'react'; +import Text from '@components/Text'; +import UserDetailsTooltip from '@components/UserDetailsTooltip'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as EmojiUtils from '@libs/EmojiUtils'; +import CONST from '@src/CONST'; +import type * as OnyxCommon from '@src/types/onyx/OnyxCommon'; + +type ReportActionItemMessageHeaderSenderProps = { + /** Text to display */ + fragmentText: string; + + /** Users accountID */ + accountID: number; + + /** Should this fragment be contained in a single line? */ + isSingleLine?: boolean; + + /** The accountID of the copilot who took this action on behalf of the user */ + delegateAccountID?: number; + + /** Actor icon */ + actorIcon?: OnyxCommon.Icon; +}; + +function ReportActionItemMessageHeaderSender({fragmentText, accountID, delegateAccountID, actorIcon, isSingleLine}: ReportActionItemMessageHeaderSenderProps) { + const styles = useThemeStyles(); + + const processedTextArray = useMemo(() => { + const emojisRegex = new RegExp(CONST.REGEX.EMOJIS, CONST.REGEX.EMOJIS.flags.concat('g')); + const doesTextContainEmojis = emojisRegex.test(fragmentText); + + if (!doesTextContainEmojis) { + return []; + } + + return EmojiUtils.splitTextWithEmojis(fragmentText); + }, [fragmentText]); + + return ( + + + {processedTextArray.length !== 0 ? processedTextArray.map(({text, isEmoji}) => (isEmoji ? {text} : text)) : fragmentText} + + + ); +} + +ReportActionItemMessageHeaderSender.displayName = 'ReportActionItemMessageHeaderSender'; + +export default ReportActionItemMessageHeaderSender; diff --git a/src/pages/home/report/comment/TextCommentFragment.tsx b/src/pages/home/report/comment/TextCommentFragment.tsx index 68827de96172..3474881e3fee 100644 --- a/src/pages/home/report/comment/TextCommentFragment.tsx +++ b/src/pages/home/report/comment/TextCommentFragment.tsx @@ -17,6 +17,7 @@ import type {OriginalMessageSource} from '@src/types/onyx/OriginalMessage'; import type {Message} from '@src/types/onyx/ReportAction'; import RenderCommentHTML from './RenderCommentHTML'; import shouldRenderAsText from './shouldRenderAsText'; +import TextWithEmojiFragment from './TextWithEmojiFragment'; type TextCommentFragmentProps = { /** The reportAction's source */ @@ -44,19 +45,19 @@ type TextCommentFragmentProps = { function TextCommentFragment({fragment, styleAsDeleted, styleAsMuted = false, source, style, displayAsGroup, iouMessage = ''}: TextCommentFragmentProps) { const theme = useTheme(); const styles = useThemeStyles(); - const {html = '', text} = fragment ?? {}; + const {html = '', text = ''} = fragment ?? {}; const {translate} = useLocalize(); const {shouldUseNarrowLayout} = useResponsiveLayout(); // If the only difference between fragment.text and fragment.html is
tags and emoji tag // on native, we render it as text, not as html // on other device, only render it as text if the only difference is
tag - const containsOnlyEmojis = EmojiUtils.containsOnlyEmojis(text ?? ''); - if (!shouldRenderAsText(html, text ?? '') && !(containsOnlyEmojis && styleAsDeleted)) { - const editedTag = fragment?.isEdited ? `` : ''; + const doesTextContainOnlyEmojis = EmojiUtils.containsOnlyEmojis(text ?? ''); + if (!shouldRenderAsText(html, text ?? '') && !(doesTextContainOnlyEmojis && styleAsDeleted)) { + const editedTag = fragment?.isEdited ? `` : ''; const htmlWithDeletedTag = styleAsDeleted ? `${html}` : html; - const htmlContent = containsOnlyEmojis ? Str.replaceAll(htmlWithDeletedTag, '', '') : htmlWithDeletedTag; + const htmlContent = doesTextContainOnlyEmojis ? Str.replaceAll(htmlWithDeletedTag, '', '') : htmlWithDeletedTag; let htmlWithTag = editedTag ? `${htmlContent}${editedTag}` : htmlContent; if (styleAsMuted) { @@ -72,40 +73,55 @@ function TextCommentFragment({fragment, styleAsDeleted, styleAsMuted = false, so } const message = isEmpty(iouMessage) ? text : iouMessage; + const emojisRegex = new RegExp(CONST.REGEX.EMOJIS, CONST.REGEX.EMOJIS.flags.concat('g')); return ( - + - - {convertToLTR(message ?? '')} - - {fragment?.isEdited && ( + {emojisRegex.test(message ?? '') && !doesTextContainOnlyEmojis ? ( + + ) : ( <> - {' '} - - - {translate('reportActionCompose.edited')} + {convertToLTR(message ?? '')} + {!!fragment?.isEdited && ( + <> + + {' '} + + + {translate('reportActionCompose.edited')} + + + )} )} diff --git a/src/pages/home/report/comment/TextWithEmojiFragment.tsx b/src/pages/home/report/comment/TextWithEmojiFragment.tsx new file mode 100644 index 000000000000..cc0da8f81fb0 --- /dev/null +++ b/src/pages/home/report/comment/TextWithEmojiFragment.tsx @@ -0,0 +1,85 @@ +import React, {useMemo} from 'react'; +import type {StyleProp, TextStyle} from 'react-native'; +import Text from '@components/Text'; +import useLocalize from '@hooks/useLocalize'; +import useResponsiveLayout from '@hooks/useResponsiveLayout'; +import useTheme from '@hooks/useTheme'; +import useThemeStyles from '@hooks/useThemeStyles'; +import * as DeviceCapabilities from '@libs/DeviceCapabilities'; +import * as EmojiUtils from '@libs/EmojiUtils'; +import variables from '@styles/variables'; +import CONST from '@src/CONST'; + +type TextWithEmojiFragmentProps = { + /** The message to be displayed */ + message: string; + + /** Additional styles to add after local styles. */ + passedStyles?: StyleProp; + + /** Should this message fragment be styled as deleted? */ + styleAsDeleted?: boolean; + + /** Should this message fragment be styled as muted? */ + styleAsMuted?: boolean; + + /** Should "(edited)" suffix be rendered? */ + isEdited?: boolean; + + /** Does message contain only emojis? */ + hasEmojisOnly?: boolean; +}; + +function TextWithEmojiFragment({message, passedStyles, styleAsDeleted, styleAsMuted, isEdited, hasEmojisOnly}: TextWithEmojiFragmentProps) { + const styles = useThemeStyles(); + const {translate} = useLocalize(); + const theme = useTheme(); + const {shouldUseNarrowLayout} = useResponsiveLayout(); + + const processedTextArray = useMemo(() => EmojiUtils.splitTextWithEmojis(message), [message]); + + return ( + + {processedTextArray.map(({text, isEmoji}) => + isEmoji ? ( + {text} + ) : ( + + {text} + + ), + )} + + {isEdited && ( + <> + + {' '} + + + {translate('reportActionCompose.edited')} + + + )} + + ); +} + +TextWithEmojiFragment.displayName = 'TextWithEmojiFragment'; + +export default TextWithEmojiFragment; diff --git a/src/pages/settings/InitialSettingsPage.tsx b/src/pages/settings/InitialSettingsPage.tsx index 39e3dc9a8989..b208e63909a8 100755 --- a/src/pages/settings/InitialSettingsPage.tsx +++ b/src/pages/settings/InitialSettingsPage.tsx @@ -29,6 +29,8 @@ import useTheme from '@hooks/useTheme'; import useThemeStyles from '@hooks/useThemeStyles'; import useWaitForNavigation from '@hooks/useWaitForNavigation'; import * as CurrencyUtils from '@libs/CurrencyUtils'; +import {splitTextWithEmojis} from '@libs/EmojiUtils'; +import type {TextWithEmoji} from '@libs/EmojiUtils'; import Navigation from '@libs/Navigation/Navigation'; import * as SubscriptionUtils from '@libs/SubscriptionUtils'; import * as UserUtils from '@libs/UserUtils'; @@ -364,9 +366,16 @@ function InitialSettingsPage({session, userWallet, bankAccountList, fundList, wa const generalMenuItems = useMemo(() => getMenuItemsSection(generalMenuItemsData), [generalMenuItemsData, getMenuItemsSection]); const workspaceMenuItems = useMemo(() => getMenuItemsSection(workspaceMenuItemsData), [workspaceMenuItemsData, getMenuItemsSection]); - const currentUserDetails = currentUserPersonalDetails; - const avatarURL = currentUserDetails?.avatar ?? ''; - const accountID = currentUserDetails?.accountID ?? '-1'; + const avatarURL = currentUserPersonalDetails?.avatar ?? ''; + const accountID = currentUserPersonalDetails?.accountID ?? '-1'; + + const processedTextArray: TextWithEmoji[] = useMemo(() => { + const doesUsernameContainEmojis = CONST.REGEX.EMOJIS.test(currentUserPersonalDetails?.displayName ?? ''); + if (!doesUsernameContainEmojis) { + return []; + } + return splitTextWithEmojis(currentUserPersonalDetails?.displayName ?? ''); + }, [currentUserPersonalDetails?.displayName]); const headerContent = ( @@ -416,7 +425,7 @@ function InitialSettingsPage({session, userWallet, bankAccountList, fundList, wa Navigation.navigate(ROUTES.PROFILE_AVATAR.getRoute(String(accountID)))} previewSource={UserUtils.getFullSizeAvatar(avatarURL, accountID)} - originalFileName={currentUserDetails.originalFileName} + originalFileName={currentUserPersonalDetails.originalFileName} headerTitle={translate('profilePage.profileAvatar')} - fallbackIcon={currentUserDetails?.fallbackIcon} + fallbackIcon={currentUserPersonalDetails?.fallbackIcon} editIconStyle={styles.smallEditIconAccount} /> - - {currentUserPersonalDetails.displayName ? currentUserPersonalDetails.displayName : formatPhoneNumber(session?.email ?? '')} - + {processedTextArray.length !== 0 ? ( + + {processedTextArray.map(({text, isEmoji}) => (isEmoji ? {text} : text))} + + ) : ( + + {currentUserPersonalDetails.displayName ? currentUserPersonalDetails.displayName : formatPhoneNumber(session?.email ?? '')} + + )} {!!currentUserPersonalDetails.displayName && ( @@ -114,6 +115,7 @@ function DisplayNamePage({isLoadingApp = true, currentUserPersonalDetails}: Disp role={CONST.ROLE.PRESENTATION} defaultValue={currentUserDetails.lastName ?? ''} spellCheck={false} + isMarkdownEnabled /> diff --git a/src/styles/index.ts b/src/styles/index.ts index 24da2ae9b3f3..3f0173ddf446 100644 --- a/src/styles/index.ts +++ b/src/styles/index.ts @@ -409,7 +409,7 @@ const styles = (theme: ThemeColors) => color: theme.text, ...FontUtils.fontFamily.platform.EXP_NEUE_BOLD, fontSize: variables.fontSizeSmall, - lineHeight: variables.lineHeightSmall, + lineHeight: variables.lineHeightNormal, }, textMicroSupporting: { @@ -1706,7 +1706,34 @@ const styles = (theme: ThemeColors) => }, onlyEmojisTextLineHeight: { - lineHeight: variables.fontSizeOnlyEmojisHeight, + lineHeight: variables.lineHeightEmojisOnlyComposer, + }, + + emojisWithTextLineHeight: { + lineHeight: variables.lineHeightEmojisWithTextComposer, + }, + + emojisWithinText: { + fontSize: variables.fontSizeEmojisWithinText, + lineHeight: variables.lineHeightComment, + }, + + emojisWithinDisplayName: { + fontSize: variables.fontSizeEmojisWithinText, + lineHeight: variables.lineHeightDisplayName, + }, + + emojisOnlyComposer: { + paddingTop: variables.emojiOnlyComposerPaddingTop, + paddingBottom: variables.emojiOnlyComposerPaddingBottom, + }, + + enhancedLineHeight: { + lineHeight: variables.lineHeightComment, + }, + + initialSettingsUsernameEmoji: { + fontSize: variables.fontSizeUsernameEmoji, }, createMenuPositionSidebar: (windowHeight: number) => @@ -2029,7 +2056,7 @@ const styles = (theme: ThemeColors) => color: theme.heading, ...FontUtils.fontFamily.platform.EXP_NEUE_BOLD, fontSize: variables.fontSizeNormal, - lineHeight: variables.lineHeightXLarge, + lineHeight: variables.lineHeightXXLarge, ...wordBreak.breakWord, }, diff --git a/src/styles/variables.ts b/src/styles/variables.ts index e0720ad1d836..4d6eac4f1a13 100644 --- a/src/styles/variables.ts +++ b/src/styles/variables.ts @@ -48,8 +48,6 @@ export default { defaultAvatarPreviewSize: 360, fabBottom: 25, breadcrumbsFontSize: getValueUsingPixelRatio(19, 32), - fontSizeOnlyEmojis: 30, - fontSizeOnlyEmojisHeight: 35, fontSizeSmall: getValueUsingPixelRatio(11, 17), fontSizeExtraSmall: 9, fontSizeLabel: getValueUsingPixelRatio(13, 19), @@ -87,8 +85,6 @@ export default { sidebarAvatarSize: 28, iconHeader: 48, iconSection: 68, - emojiSize: 20, - emojiLineHeight: 28, iouAmountTextSize: 40, extraSmallMobileResponsiveWidthBreakpoint: 320, extraSmallMobileResponsiveHeightBreakpoint: 667, @@ -114,6 +110,9 @@ export default { lineHeightSizeh1: getValueUsingPixelRatio(28, 32), lineHeightSizeh2: getValueUsingPixelRatio(24, 28), lineHeightSignInHeroXSmall: getValueUsingPixelRatio(32, 37), + lineHeightComment: 24, + lineHeightDisplayName: 25, + lineHeightMarkdownEnabledInput: 18, inputHeight: getValueUsingPixelRatio(52, 72), inputHeightSmall: 28, formErrorLineHeight: getValueUsingPixelRatio(18, 23), @@ -213,6 +212,21 @@ export default { welcomeVideoDelay: 1000, explanationModalDelay: 2000, + // Emoji related variables + emojiSize: 20, + emojiSizeSmall: 12, + emojiLineHeight: 28, + fontSizeOnlyEmojis: 30, + fontSizeOnlyEmojisHeight: 35, + fontSizeEmojisWithinText: 19, + fontSizeEmojisOnlyComposer: 27, + fontSizeUsernameEmoji: 25, + lineHeightEmojisOnlyComposer: 32, + lineHeightEmojisWithTextComposer: 22, + emojiOnlyMarginTop: 5, + emojiOnlyComposerPaddingBottom: 0, + emojiOnlyComposerPaddingTop: 7, + // The height of the empty list is 14px (2px for borders and 12px for vertical padding) // This is calculated based on the values specified in the 'getGoogleListViewStyle' function of the 'StyleUtils' utility googleEmptyListViewHeight: 14,