about summary refs log tree commit diff
path: root/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/components')
-rw-r--r--src/components/FeedCard.tsx13
-rw-r--r--src/components/KnownFollowers.tsx14
-rw-r--r--src/components/LabelingServiceCard/index.tsx11
-rw-r--r--src/components/ListCard.tsx24
-rw-r--r--src/components/Pills.tsx1
-rw-r--r--src/components/ProfileCard.tsx12
-rw-r--r--src/components/ReportDialog/SubmitView.tsx1
-rw-r--r--src/components/RichText.tsx9
-rw-r--r--src/components/StarterPack/StarterPackCard.tsx27
-rw-r--r--src/components/StarterPack/Wizard/WizardListCard.tsx11
-rw-r--r--src/components/Typography.tsx108
-rw-r--r--src/components/dms/MessagesListHeader.tsx17
-rw-r--r--src/components/moderation/LabelsOnMeDialog.tsx6
-rw-r--r--src/components/moderation/ModerationDetailsDialog.tsx8
14 files changed, 193 insertions, 69 deletions
diff --git a/src/components/FeedCard.tsx b/src/components/FeedCard.tsx
index e6d664cfd..b28f66f83 100644
--- a/src/components/FeedCard.tsx
+++ b/src/components/FeedCard.tsx
@@ -11,17 +11,17 @@ import {msg, plural, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 import {useQueryClient} from '@tanstack/react-query'
 
+import {sanitizeHandle} from '#/lib/strings/handles'
 import {logger} from '#/logger'
+import {precacheFeedFromGeneratorView} from '#/state/queries/feed'
 import {
   useAddSavedFeedsMutation,
   usePreferencesQuery,
   useRemoveFeedMutation,
 } from '#/state/queries/preferences'
-import {sanitizeHandle} from 'lib/strings/handles'
-import {precacheFeedFromGeneratorView} from 'state/queries/feed'
-import {useSession} from 'state/session'
+import {useSession} from '#/state/session'
+import * as Toast from '#/view/com/util/Toast'
 import {UserAvatar} from '#/view/com/util/UserAvatar'
-import * as Toast from 'view/com/util/Toast'
 import {useTheme} from '#/alf'
 import {atoms as a} from '#/alf'
 import {Button, ButtonIcon} from '#/components/Button'
@@ -121,7 +121,10 @@ export function TitleAndByline({
 
   return (
     <View style={[a.flex_1]}>
-      <Text style={[a.text_md, a.font_bold, a.leading_snug]} numberOfLines={1}>
+      <Text
+        emoji
+        style={[a.text_md, a.font_bold, a.leading_snug]}
+        numberOfLines={1}>
         {title}
       </Text>
       {creator && (
diff --git a/src/components/KnownFollowers.tsx b/src/components/KnownFollowers.tsx
index 4017a7b0b..35a346c3a 100644
--- a/src/components/KnownFollowers.tsx
+++ b/src/components/KnownFollowers.tsx
@@ -5,7 +5,7 @@ import {msg, Plural, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
 import {makeProfileLink} from '#/lib/routes/links'
-import {sanitizeDisplayName} from 'lib/strings/display-names'
+import {sanitizeDisplayName} from '#/lib/strings/display-names'
 import {UserAvatar} from '#/view/com/util/UserAvatar'
 import {atoms as a, useTheme} from '#/alf'
 import {Link, LinkProps} from '#/components/Link'
@@ -185,11 +185,11 @@ function KnownFollowersInner({
               serverCount > 2 ? (
                 <Trans>
                   Followed by{' '}
-                  <Text key={slice[0].profile.did} style={textStyle}>
+                  <Text emoji key={slice[0].profile.did} style={textStyle}>
                     {slice[0].profile.displayName}
                   </Text>
                   ,{' '}
-                  <Text key={slice[1].profile.did} style={textStyle}>
+                  <Text emoji key={slice[1].profile.did} style={textStyle}>
                     {slice[1].profile.displayName}
                   </Text>
                   , and{' '}
@@ -203,11 +203,11 @@ function KnownFollowersInner({
                 // only 2
                 <Trans>
                   Followed by{' '}
-                  <Text key={slice[0].profile.did} style={textStyle}>
+                  <Text emoji key={slice[0].profile.did} style={textStyle}>
                     {slice[0].profile.displayName}
                   </Text>{' '}
                   and{' '}
-                  <Text key={slice[1].profile.did} style={textStyle}>
+                  <Text emoji key={slice[1].profile.did} style={textStyle}>
                     {slice[1].profile.displayName}
                   </Text>
                 </Trans>
@@ -216,7 +216,7 @@ function KnownFollowersInner({
               // 1-n followers, including blocks
               <Trans>
                 Followed by{' '}
-                <Text key={slice[0].profile.did} style={textStyle}>
+                <Text emoji key={slice[0].profile.did} style={textStyle}>
                   {slice[0].profile.displayName}
                 </Text>{' '}
                 and{' '}
@@ -230,7 +230,7 @@ function KnownFollowersInner({
               // only 1
               <Trans>
                 Followed by{' '}
-                <Text key={slice[0].profile.did} style={textStyle}>
+                <Text emoji key={slice[0].profile.did} style={textStyle}>
                   {slice[0].profile.displayName}
                 </Text>
               </Trans>
diff --git a/src/components/LabelingServiceCard/index.tsx b/src/components/LabelingServiceCard/index.tsx
index 851645a48..03b8ece6b 100644
--- a/src/components/LabelingServiceCard/index.tsx
+++ b/src/components/LabelingServiceCard/index.tsx
@@ -44,17 +44,22 @@ export function Avatar({avatar}: {avatar?: string}) {
 }
 
 export function Title({value}: {value: string}) {
-  return <Text style={[a.text_md, a.font_bold, a.leading_tight]}>{value}</Text>
+  return (
+    <Text emoji style={[a.text_md, a.font_bold, a.leading_tight]}>
+      {value}
+    </Text>
+  )
 }
 
 export function Description({value, handle}: {value?: string; handle: string}) {
+  const {_} = useLingui()
   return value ? (
     <Text numberOfLines={2}>
       <RichText value={value} style={[a.leading_snug]} />
     </Text>
   ) : (
-    <Text style={[a.leading_snug]}>
-      <Trans>By {sanitizeHandle(handle, '@')}</Trans>
+    <Text emoji style={[a.leading_snug]}>
+      {_(msg`By ${sanitizeHandle(handle, '@')}`)}
     </Text>
   )
 }
diff --git a/src/components/ListCard.tsx b/src/components/ListCard.tsx
index 829f36d47..ed5838fb0 100644
--- a/src/components/ListCard.tsx
+++ b/src/components/ListCard.tsx
@@ -7,13 +7,14 @@ import {
   moderateUserList,
   ModerationUI,
 } from '@atproto/api'
-import {Trans} from '@lingui/macro'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
 import {useQueryClient} from '@tanstack/react-query'
 
-import {sanitizeHandle} from 'lib/strings/handles'
-import {useModerationOpts} from 'state/preferences/moderation-opts'
-import {precacheList} from 'state/queries/feed'
-import {useSession} from 'state/session'
+import {sanitizeHandle} from '#/lib/strings/handles'
+import {useModerationOpts} from '#/state/preferences/moderation-opts'
+import {precacheList} from '#/state/queries/feed'
+import {useSession} from '#/state/session'
 import {atoms as a, useTheme} from '#/alf'
 import {
   Avatar,
@@ -111,6 +112,7 @@ export function TitleAndByline({
   modUi?: ModerationUI
 }) {
   const t = useTheme()
+  const {_} = useLingui()
   const {currentAccount} = useSession()
 
   return (
@@ -130,6 +132,7 @@ export function TitleAndByline({
         </Hider.Mask>
         <Hider.Content>
           <Text
+            emoji
             style={[a.text_md, a.font_bold, a.leading_snug]}
             numberOfLines={1}>
             {title}
@@ -139,15 +142,12 @@ export function TitleAndByline({
 
       {creator && (
         <Text
+          emoji
           style={[a.leading_snug, t.atoms.text_contrast_medium]}
           numberOfLines={1}>
-          {purpose === MODLIST ? (
-            <Trans>
-              Moderation list by {sanitizeHandle(creator.handle, '@')}
-            </Trans>
-          ) : (
-            <Trans>List by {sanitizeHandle(creator.handle, '@')}</Trans>
-          )}
+          {purpose === MODLIST
+            ? _(msg`Moderation list by ${sanitizeHandle(creator.handle, '@')}`)
+            : _(msg`List by ${sanitizeHandle(creator.handle, '@')}`)}
         </Text>
       )}
     </View>
diff --git a/src/components/Pills.tsx b/src/components/Pills.tsx
index 6c8084743..974d83593 100644
--- a/src/components/Pills.tsx
+++ b/src/components/Pills.tsx
@@ -130,6 +130,7 @@ export function Label({
             )}
 
             <Text
+              emoji
               style={[
                 text,
                 a.font_bold,
diff --git a/src/components/ProfileCard.tsx b/src/components/ProfileCard.tsx
index b208903b4..50b34ba99 100644
--- a/src/components/ProfileCard.tsx
+++ b/src/components/ProfileCard.tsx
@@ -11,13 +11,13 @@ import {useLingui} from '@lingui/react'
 
 import {LogEvents} from '#/lib/statsig/statsig'
 import {sanitizeDisplayName} from '#/lib/strings/display-names'
+import {sanitizeHandle} from '#/lib/strings/handles'
+import {useProfileShadow} from '#/state/cache/profile-shadow'
 import {useProfileFollowMutationQueue} from '#/state/queries/profile'
-import {sanitizeHandle} from 'lib/strings/handles'
-import {useProfileShadow} from 'state/cache/profile-shadow'
-import {useSession} from 'state/session'
+import {useSession} from '#/state/session'
+import {ProfileCardPills} from '#/view/com/profile/ProfileCard'
 import * as Toast from '#/view/com/util/Toast'
-import {ProfileCardPills} from 'view/com/profile/ProfileCard'
-import {UserAvatar} from 'view/com/util/UserAvatar'
+import {UserAvatar} from '#/view/com/util/UserAvatar'
 import {atoms as a, useTheme} from '#/alf'
 import {Button, ButtonIcon, ButtonProps, ButtonText} from '#/components/Button'
 import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
@@ -175,11 +175,13 @@ export function NameAndHandle({
   return (
     <View style={[a.flex_1]}>
       <Text
+        emoji
         style={[a.text_md, a.font_bold, a.leading_snug, a.self_start]}
         numberOfLines={1}>
         {name}
       </Text>
       <Text
+        emoji
         style={[a.leading_snug, t.atoms.text_contrast_medium]}
         numberOfLines={1}>
         {handle}
diff --git a/src/components/ReportDialog/SubmitView.tsx b/src/components/ReportDialog/SubmitView.tsx
index 2def0fa4b..e323d1504 100644
--- a/src/components/ReportDialog/SubmitView.tsx
+++ b/src/components/ReportDialog/SubmitView.tsx
@@ -256,6 +256,7 @@ function LabelerToggle({title}: {title: string}) {
           a.z_10,
         ]}>
         <Text
+          emoji
           style={[
             native({marginTop: 2}),
             t.atoms.text_contrast_medium,
diff --git a/src/components/RichText.tsx b/src/components/RichText.tsx
index 751177597..1c65a87ac 100644
--- a/src/components/RichText.tsx
+++ b/src/components/RichText.tsx
@@ -66,6 +66,7 @@ export function RichText({
         (flattenedStyle.fontSize ?? a.text_sm.fontSize) * emojiMultiplier
       return (
         <Text
+          emoji
           selectable={selectable}
           testID={testID}
           style={[plainStyles, {fontSize}]}
@@ -77,6 +78,7 @@ export function RichText({
     }
     return (
       <Text
+        emoji
         selectable={selectable}
         testID={testID}
         style={plainStyles}
@@ -148,7 +150,11 @@ export function RichText({
         />,
       )
     } else {
-      els.push(segment.text)
+      els.push(
+        <Text key={key} emoji style={plainStyles}>
+          {segment.text}
+        </Text>,
+      )
     }
     key++
   }
@@ -213,6 +219,7 @@ function RichTextTag({
     <React.Fragment>
       <TagMenu control={control} tag={tag} authorHandle={authorHandle}>
         <Text
+          emoji
           selectable={selectable}
           {...native({
             accessibilityLabel: _(msg`Hashtag: #${tag}`),
diff --git a/src/components/StarterPack/StarterPackCard.tsx b/src/components/StarterPack/StarterPackCard.tsx
index 4c4bf246e..ead9c9248 100644
--- a/src/components/StarterPack/StarterPackCard.tsx
+++ b/src/components/StarterPack/StarterPackCard.tsx
@@ -2,15 +2,15 @@ import React from 'react'
 import {View} from 'react-native'
 import {Image} from 'expo-image'
 import {AppBskyGraphDefs, AppBskyGraphStarterpack, AtUri} from '@atproto/api'
-import {msg, Trans} from '@lingui/macro'
+import {msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 import {useQueryClient} from '@tanstack/react-query'
 
-import {sanitizeHandle} from 'lib/strings/handles'
-import {getStarterPackOgCard} from 'lib/strings/starter-pack'
-import {precacheResolvedUri} from 'state/queries/resolve-uri'
-import {precacheStarterPack} from 'state/queries/starter-packs'
-import {useSession} from 'state/session'
+import {sanitizeHandle} from '#/lib/strings/handles'
+import {getStarterPackOgCard} from '#/lib/strings/starter-pack'
+import {precacheResolvedUri} from '#/state/queries/resolve-uri'
+import {precacheStarterPack} from '#/state/queries/starter-packs'
+import {useSession} from '#/state/session'
 import {atoms as a, useTheme} from '#/alf'
 import {StarterPack} from '#/components/icons/StarterPack'
 import {BaseLink} from '#/components/Link'
@@ -66,21 +66,18 @@ export function Card({
       <View style={[a.flex_row, a.gap_sm]}>
         {!noIcon ? <StarterPack width={40} gradient="sky" /> : null}
         <View>
-          <Text style={[a.text_md, a.font_bold, a.leading_snug]}>
+          <Text emoji style={[a.text_md, a.font_bold, a.leading_snug]}>
             {record.name}
           </Text>
-          <Text style={[a.leading_snug, t.atoms.text_contrast_medium]}>
-            <Trans>
-              Starter pack by{' '}
-              {creator?.did === currentAccount?.did
-                ? _(msg`you`)
-                : `@${sanitizeHandle(creator.handle)}`}
-            </Trans>
+          <Text emoji style={[a.leading_snug, t.atoms.text_contrast_medium]}>
+            {creator?.did === currentAccount?.did
+              ? _(msg`Starter pack by you`)
+              : _(msg`Starter pack by ${sanitizeHandle(creator.handle, '@')}`)}
           </Text>
         </View>
       </View>
       {!noDescription && record.description ? (
-        <Text numberOfLines={3} style={[a.leading_snug]}>
+        <Text emoji numberOfLines={3} style={[a.leading_snug]}>
           {record.description}
         </Text>
       ) : null}
diff --git a/src/components/StarterPack/Wizard/WizardListCard.tsx b/src/components/StarterPack/Wizard/WizardListCard.tsx
index ad02cdc30..44f01a154 100644
--- a/src/components/StarterPack/Wizard/WizardListCard.tsx
+++ b/src/components/StarterPack/Wizard/WizardListCard.tsx
@@ -12,11 +12,11 @@ import {GeneratorView} from '@atproto/api/dist/client/types/app/bsky/feed/defs'
 import {msg, Trans} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 
-import {DISCOVER_FEED_URI, STARTER_PACK_MAX_SIZE} from 'lib/constants'
-import {sanitizeDisplayName} from 'lib/strings/display-names'
-import {sanitizeHandle} from 'lib/strings/handles'
-import {useSession} from 'state/session'
-import {UserAvatar} from 'view/com/util/UserAvatar'
+import {DISCOVER_FEED_URI, STARTER_PACK_MAX_SIZE} from '#/lib/constants'
+import {sanitizeDisplayName} from '#/lib/strings/display-names'
+import {sanitizeHandle} from '#/lib/strings/handles'
+import {useSession} from '#/state/session'
+import {UserAvatar} from '#/view/com/util/UserAvatar'
 import {WizardAction, WizardState} from '#/screens/StarterPack/Wizard/State'
 import {atoms as a, useTheme} from '#/alf'
 import {Button, ButtonText} from '#/components/Button'
@@ -78,6 +78,7 @@ function WizardListCard({
       />
       <View style={[a.flex_1, a.gap_2xs]}>
         <Text
+          emoji
           style={[
             a.flex_1,
             a.font_bold,
diff --git a/src/components/Typography.tsx b/src/components/Typography.tsx
index 15f88468a..501e23872 100644
--- a/src/components/Typography.tsx
+++ b/src/components/Typography.tsx
@@ -1,15 +1,85 @@
 import React from 'react'
 import {StyleProp, TextProps as RNTextProps, TextStyle} from 'react-native'
 import {UITextView} from 'react-native-uitextview'
+import createEmojiRegex from 'emoji-regex'
 
-import {isNative} from '#/platform/detection'
+import {logger} from '#/logger'
+import {isIOS, isNative} from '#/platform/detection'
 import {Alf, applyFonts, atoms, flatten, useAlf, useTheme, web} from '#/alf'
+import {IS_DEV} from '#/env'
 
-export type TextProps = RNTextProps & {
+export type StringChild = string | (string | null)[]
+
+export type TextProps = Omit<RNTextProps, 'children'> & {
   /**
    * Lets the user select text, to use the native copy and paste functionality.
    */
   selectable?: boolean
+  /**
+   * Provides `data-*` attributes to the underlying `UITextView` component on
+   * web only.
+   */
+  dataSet?: Record<string, string | number | undefined>
+  /**
+   * Appears as a small tooltip on web hover.
+   */
+  title?: string
+} & (
+    | {
+        emoji: true
+        children: StringChild
+      }
+    | {
+        emoji?: false
+        children: RNTextProps['children']
+      }
+  )
+
+const EMOJI = createEmojiRegex()
+
+export function childHasEmoji(children: React.ReactNode) {
+  return (Array.isArray(children) ? children : [children]).some(
+    child => typeof child === 'string' && createEmojiRegex().test(child),
+  )
+}
+
+export function childIsString(
+  children: React.ReactNode,
+): children is StringChild {
+  return (
+    typeof children === 'string' ||
+    (Array.isArray(children) &&
+      children.every(child => typeof child === 'string' || child === null))
+  )
+}
+
+export function renderChildrenWithEmoji(children: StringChild) {
+  const normalized = Array.isArray(children) ? children : [children]
+
+  return (
+    <UITextView>
+      {normalized.map(child => {
+        if (typeof child !== 'string') return child
+
+        const emojis = child.match(EMOJI)
+
+        if (emojis === null) {
+          return child
+        }
+
+        return child.split(EMOJI).map((stringPart, index) => (
+          <UITextView key={index}>
+            {stringPart}
+            {emojis[index] ? (
+              <UITextView style={{color: 'black', fontFamily: 'System'}}>
+                {emojis[index]}
+              </UITextView>
+            ) : null}
+          </UITextView>
+        ))
+      })}
+    </UITextView>
+  )
 }
 
 /**
@@ -64,7 +134,15 @@ export function normalizeTextStyles(
 /**
  * Our main text component. Use this most of the time.
  */
-export function Text({style, selectable, ...rest}: TextProps) {
+export function Text({
+  children,
+  emoji,
+  style,
+  selectable,
+  title,
+  dataSet,
+  ...rest
+}: TextProps) {
   const {fonts, flags} = useAlf()
   const t = useTheme()
   const s = normalizeTextStyles([atoms.text_sm, t.atoms.text, flatten(style)], {
@@ -73,7 +151,29 @@ export function Text({style, selectable, ...rest}: TextProps) {
     flags,
   })
 
-  return <UITextView selectable={selectable} uiTextView style={s} {...rest} />
+  if (IS_DEV) {
+    if (!emoji && childHasEmoji(children)) {
+      logger.warn(
+        `Text: emoji detected but emoji not enabled: "${children}"\n\nPlease add <Text emoji />'`,
+      )
+    }
+
+    if (emoji && !childIsString(children)) {
+      logger.error('Text: when <Text emoji />, children can only be strings.')
+    }
+  }
+
+  return (
+    <UITextView
+      selectable={selectable}
+      uiTextView
+      style={s}
+      {...rest}
+      // @ts-ignore
+      dataSet={Object.assign({tooltip: title}, dataSet || {})}>
+      {isIOS && emoji ? renderChildrenWithEmoji(children) : children}
+    </UITextView>
+  )
 }
 
 export function createHeadingElement({level}: {level: number}) {
diff --git a/src/components/dms/MessagesListHeader.tsx b/src/components/dms/MessagesListHeader.tsx
index 1a6bbbe60..ab9ec16e4 100644
--- a/src/components/dms/MessagesListHeader.tsx
+++ b/src/components/dms/MessagesListHeader.tsx
@@ -10,14 +10,14 @@ import {msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 import {useNavigation} from '@react-navigation/native'
 
-import {BACK_HITSLOP} from 'lib/constants'
-import {makeProfileLink} from 'lib/routes/links'
-import {NavigationProp} from 'lib/routes/types'
-import {sanitizeDisplayName} from 'lib/strings/display-names'
-import {isWeb} from 'platform/detection'
-import {useProfileShadow} from 'state/cache/profile-shadow'
-import {isConvoActive, useConvo} from 'state/messages/convo'
-import {PreviewableUserAvatar} from 'view/com/util/UserAvatar'
+import {BACK_HITSLOP} from '#/lib/constants'
+import {makeProfileLink} from '#/lib/routes/links'
+import {NavigationProp} from '#/lib/routes/types'
+import {sanitizeDisplayName} from '#/lib/strings/display-names'
+import {isWeb} from '#/platform/detection'
+import {useProfileShadow} from '#/state/cache/profile-shadow'
+import {isConvoActive, useConvo} from '#/state/messages/convo'
+import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar'
 import {atoms as a, useBreakpoints, useTheme, web} from '#/alf'
 import {ConvoMenu} from '#/components/dms/ConvoMenu'
 import {Bell2Off_Filled_Corner0_Rounded as BellStroke} from '#/components/icons/Bell2'
@@ -170,6 +170,7 @@ function HeaderReady({
           </View>
           <View style={a.flex_1}>
             <Text
+              emoji
               style={[
                 a.text_md,
                 a.font_bold,
diff --git a/src/components/moderation/LabelsOnMeDialog.tsx b/src/components/moderation/LabelsOnMeDialog.tsx
index c54a04a78..e63cea93b 100644
--- a/src/components/moderation/LabelsOnMeDialog.tsx
+++ b/src/components/moderation/LabelsOnMeDialog.tsx
@@ -132,8 +132,10 @@ function Label({
       ]}>
       <View style={[a.p_md, a.gap_sm, a.flex_row]}>
         <View style={[a.flex_1, a.gap_xs]}>
-          <Text style={[a.font_bold, a.text_md]}>{strings.name}</Text>
-          <Text style={[t.atoms.text_contrast_medium, a.leading_snug]}>
+          <Text emoji style={[a.font_bold, a.text_md]}>
+            {strings.name}
+          </Text>
+          <Text emoji style={[t.atoms.text_contrast_medium, a.leading_snug]}>
             {strings.description}
           </Text>
         </View>
diff --git a/src/components/moderation/ModerationDetailsDialog.tsx b/src/components/moderation/ModerationDetailsDialog.tsx
index d95717cf4..225917853 100644
--- a/src/components/moderation/ModerationDetailsDialog.tsx
+++ b/src/components/moderation/ModerationDetailsDialog.tsx
@@ -118,7 +118,11 @@ function ModerationDetailsDialogInner({
       : _(msg`The author of this thread has hidden this reply.`)
   } else if (modcause.type === 'label') {
     name = desc.name
-    description = desc.description
+    description = (
+      <Text emoji style={[t.atoms.text, a.text_md, a.leading_snug]}>
+        {desc.description}
+      </Text>
+    )
   } else {
     // should never happen
     name = ''
@@ -127,7 +131,7 @@ function ModerationDetailsDialogInner({
 
   return (
     <Dialog.ScrollableInner label={_(msg`Moderation details`)}>
-      <Text style={[t.atoms.text, a.text_2xl, a.font_bold, a.mb_sm]}>
+      <Text emoji style={[t.atoms.text, a.text_2xl, a.font_bold, a.mb_sm]}>
         {name}
       </Text>
       <Text style={[t.atoms.text, a.text_md, a.leading_snug]}>