[Neue] Handle emoji within custom font (#5449)
* Support emoji in text with custom font * Add emoji support to elements that need it * Remove unused file causing lint failure * Fix a few more emoji locations * Couple more * No throw
This commit is contained in:
@@ -19,19 +19,19 @@ import PasteInput, {
|
||||
PasteInputRef,
|
||||
} from '@mattermost/react-native-paste-input'
|
||||
|
||||
import {POST_IMG_MAX} from '#/lib/constants'
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {downloadAndResize} from '#/lib/media/manip'
|
||||
import {isUriImage} from '#/lib/media/util'
|
||||
import {cleanError} from '#/lib/strings/errors'
|
||||
import {getMentionAt, insertMentionAt} from '#/lib/strings/mention-manip'
|
||||
import {useTheme} from '#/lib/ThemeContext'
|
||||
import {isAndroid} from '#/platform/detection'
|
||||
import {POST_IMG_MAX} from 'lib/constants'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {downloadAndResize} from 'lib/media/manip'
|
||||
import {isUriImage} from 'lib/media/util'
|
||||
import {cleanError} from 'lib/strings/errors'
|
||||
import {getMentionAt, insertMentionAt} from 'lib/strings/mention-manip'
|
||||
import {useTheme} from 'lib/ThemeContext'
|
||||
import {
|
||||
LinkFacetMatch,
|
||||
suggestLinkCardUri,
|
||||
} from 'view/com/composer/text-input/text-input-util'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
} from '#/view/com/composer/text-input/text-input-util'
|
||||
import {Text} from '#/view/com/util/text/Text'
|
||||
import {atoms as a, useAlf} from '#/alf'
|
||||
import {normalizeTextStyles} from '#/components/Typography'
|
||||
import {Autocomplete} from './mobile/Autocomplete'
|
||||
@@ -216,6 +216,7 @@ export const TextInput = forwardRef(function TextInputImpl(
|
||||
return Array.from(richtext.segments()).map(segment => {
|
||||
return (
|
||||
<Text
|
||||
emoji
|
||||
key={i++}
|
||||
style={[inputTextStyle, segment.facet ? pal.link : pal.text]}>
|
||||
{segment.text}
|
||||
|
||||
@@ -5,19 +5,20 @@ import React, {
|
||||
useState,
|
||||
} from 'react'
|
||||
import {Pressable, StyleSheet, View} from 'react-native'
|
||||
import {Trans} from '@lingui/macro'
|
||||
import {ReactRenderer} from '@tiptap/react'
|
||||
import tippy, {Instance as TippyInstance} from 'tippy.js'
|
||||
import {
|
||||
SuggestionKeyDownProps,
|
||||
SuggestionOptions,
|
||||
SuggestionProps,
|
||||
SuggestionKeyDownProps,
|
||||
} from '@tiptap/suggestion'
|
||||
import tippy, {Instance as TippyInstance} from 'tippy.js'
|
||||
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {ActorAutocompleteFn} from '#/state/queries/actor-autocomplete'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
import {UserAvatar} from 'view/com/util/UserAvatar'
|
||||
import {Text} from '#/view/com/util/text/Text'
|
||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||
import {useGrapheme} from '../hooks/useGrapheme'
|
||||
import {Trans} from '@lingui/macro'
|
||||
|
||||
interface MentionListRef {
|
||||
onKeyDown: (props: SuggestionKeyDownProps) => boolean
|
||||
@@ -180,7 +181,7 @@ const MentionList = forwardRef<MentionListRef, SuggestionProps>(
|
||||
size={26}
|
||||
type={item.associated?.labeler ? 'labeler' : 'user'}
|
||||
/>
|
||||
<Text style={pal.text} numberOfLines={1}>
|
||||
<Text emoji style={pal.text} numberOfLines={1}>
|
||||
{displayName}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
@@ -12,6 +12,10 @@ import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {msg, Plural, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {useNavigationDeduped} from '#/lib/hooks/useNavigationDeduped'
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {s} from '#/lib/styles'
|
||||
import {logger} from '#/logger'
|
||||
import {shouldClickOpenNewTab} from '#/platform/urls'
|
||||
import {FeedSourceInfo, useFeedSourceInfoQuery} from '#/state/queries/feed'
|
||||
@@ -21,12 +25,8 @@ import {
|
||||
UsePreferencesQueryResponse,
|
||||
useRemoveFeedMutation,
|
||||
} from '#/state/queries/preferences'
|
||||
import {useNavigationDeduped} from 'lib/hooks/useNavigationDeduped'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {sanitizeHandle} from 'lib/strings/handles'
|
||||
import {s} from 'lib/styles'
|
||||
import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder'
|
||||
import * as Toast from 'view/com/util/Toast'
|
||||
import * as Toast from '#/view/com/util/Toast'
|
||||
import {useTheme} from '#/alf'
|
||||
import {atoms as a} from '#/alf'
|
||||
import * as Prompt from '#/components/Prompt'
|
||||
@@ -242,7 +242,7 @@ export function FeedSourceCardLoaded({
|
||||
<UserAvatar type="algo" size={36} avatar={feed.avatar} />
|
||||
</View>
|
||||
<View style={[styles.headerTextContainer]}>
|
||||
<Text style={[pal.text, s.bold]} numberOfLines={1}>
|
||||
<Text emoji style={[pal.text, s.bold]} numberOfLines={1}>
|
||||
{feed.displayName}
|
||||
</Text>
|
||||
<Text style={[pal.textLight]} numberOfLines={1}>
|
||||
|
||||
@@ -65,21 +65,27 @@ export function Component({
|
||||
return [pal.border, {flex: 1, borderTopWidth: StyleSheet.hairlineWidth}]
|
||||
}, [pal.border, screenHeight])
|
||||
|
||||
const headerStyles = [
|
||||
{
|
||||
textAlign: 'center',
|
||||
fontWeight: '600',
|
||||
fontSize: 20,
|
||||
marginBottom: 12,
|
||||
paddingHorizontal: 12,
|
||||
} as const,
|
||||
pal.text,
|
||||
]
|
||||
|
||||
return (
|
||||
<View testID="userAddRemoveListsModal" style={s.hContentRegion}>
|
||||
<Text
|
||||
style={[
|
||||
{
|
||||
textAlign: 'center',
|
||||
fontWeight: '600',
|
||||
fontSize: 20,
|
||||
marginBottom: 12,
|
||||
paddingHorizontal: 12,
|
||||
},
|
||||
pal.text,
|
||||
]}
|
||||
numberOfLines={1}>
|
||||
<Trans>Update {displayName} in Lists</Trans>
|
||||
<Text style={headerStyles} numberOfLines={1}>
|
||||
<Trans>
|
||||
Update{' '}
|
||||
<Text style={headerStyles} numberOfLines={1}>
|
||||
{displayName}
|
||||
</Text>{' '}
|
||||
in Lists
|
||||
</Trans>
|
||||
</Text>
|
||||
<MyLists
|
||||
filter="all"
|
||||
|
||||
@@ -310,7 +310,11 @@ let FeedItem = ({
|
||||
key={authors[0].href}
|
||||
style={[pal.text, s.bold]}
|
||||
href={authors[0].href}
|
||||
text={forceLTR(firstAuthorName)}
|
||||
text={
|
||||
<Text emoji style={[pal.text, s.bold]}>
|
||||
{forceLTR(firstAuthorName)}
|
||||
</Text>
|
||||
}
|
||||
disableMismatchWarning
|
||||
/>
|
||||
{authors.length > 1 ? (
|
||||
@@ -570,12 +574,13 @@ function ExpandedAuthorsList({
|
||||
numberOfLines={1}
|
||||
style={pal.text}
|
||||
lineHeight={1.2}>
|
||||
{sanitizeDisplayName(
|
||||
author.profile.displayName || author.profile.handle,
|
||||
)}
|
||||
|
||||
<Text emoji type="lg-bold" style={pal.text} lineHeight={1.2}>
|
||||
{sanitizeDisplayName(
|
||||
author.profile.displayName || author.profile.handle,
|
||||
)}
|
||||
</Text>{' '}
|
||||
<Text style={[pal.textLight]} lineHeight={1.2}>
|
||||
{sanitizeHandle(author.profile.handle)}
|
||||
{sanitizeHandle(author.profile.handle, '@')}
|
||||
</Text>
|
||||
</Text>
|
||||
</View>
|
||||
@@ -592,7 +597,11 @@ function AdditionalPostText({post}: {post?: AppBskyFeedDefs.PostView}) {
|
||||
|
||||
return (
|
||||
<>
|
||||
{text?.length > 0 && <Text style={pal.textLight}>{text}</Text>}
|
||||
{text?.length > 0 && (
|
||||
<Text emoji style={pal.textLight}>
|
||||
{text}
|
||||
</Text>
|
||||
)}
|
||||
<MediaPreview.Embed
|
||||
embed={post.embed}
|
||||
style={styles.additionalPostImages}
|
||||
|
||||
@@ -138,6 +138,7 @@ export function TabBar({
|
||||
onPress={() => onPressItem(i)}>
|
||||
<View style={[styles.itemInner, selected && indicatorStyle]}>
|
||||
<Text
|
||||
emoji
|
||||
type={isDesktop || isTablet ? 'xl-bold' : 'lg-bold'}
|
||||
testID={testID ? `${testID}-${item}` : undefined}
|
||||
style={[
|
||||
|
||||
@@ -12,24 +12,24 @@ import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {msg, Plural, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {MAX_POST_LINES} from '#/lib/constants'
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {countLines} from '#/lib/strings/helpers'
|
||||
import {niceDate} from '#/lib/strings/time'
|
||||
import {s} from '#/lib/styles'
|
||||
import {isWeb} from '#/platform/detection'
|
||||
import {POST_TOMBSTONE, Shadow, usePostShadow} from '#/state/cache/post-shadow'
|
||||
import {useLanguagePrefs} from '#/state/preferences'
|
||||
import {useOpenLink} from '#/state/preferences/in-app-browser'
|
||||
import {ThreadPost} from '#/state/queries/post-thread'
|
||||
import {useSession} from '#/state/session'
|
||||
import {useComposerControls} from '#/state/shell/composer'
|
||||
import {useMergedThreadgateHiddenReplies} from '#/state/threadgate-hidden-replies'
|
||||
import {MAX_POST_LINES} from 'lib/constants'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {makeProfileLink} from 'lib/routes/links'
|
||||
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||
import {sanitizeHandle} from 'lib/strings/handles'
|
||||
import {countLines} from 'lib/strings/helpers'
|
||||
import {niceDate} from 'lib/strings/time'
|
||||
import {s} from 'lib/styles'
|
||||
import {isWeb} from 'platform/detection'
|
||||
import {useSession} from 'state/session'
|
||||
import {PostThreadFollowBtn} from 'view/com/post-thread/PostThreadFollowBtn'
|
||||
import {PostThreadFollowBtn} from '#/view/com/post-thread/PostThreadFollowBtn'
|
||||
import {atoms as a} from '#/alf'
|
||||
import {AppModerationCause} from '#/components/Pills'
|
||||
import {RichText} from '#/components/RichText'
|
||||
@@ -308,6 +308,7 @@ let PostThreadItemLoaded = ({
|
||||
style={[styles.meta, styles.metaExpandedLine1, {zIndex: 1}]}>
|
||||
<Link style={s.flex1} href={authorHref} title={authorTitle}>
|
||||
<Text
|
||||
emoji
|
||||
type="xl-bold"
|
||||
style={[pal.text, a.self_start]}
|
||||
numberOfLines={1}
|
||||
@@ -322,7 +323,11 @@ let PostThreadItemLoaded = ({
|
||||
</View>
|
||||
<View style={styles.meta}>
|
||||
<Link style={s.flex1} href={authorHref} title={authorTitle}>
|
||||
<Text type="md" style={[pal.textLight]} numberOfLines={1}>
|
||||
<Text
|
||||
emoji
|
||||
type="md"
|
||||
style={[pal.textLight]}
|
||||
numberOfLines={1}>
|
||||
{sanitizeHandle(post.author.handle, '@')}
|
||||
</Text>
|
||||
</Link>
|
||||
|
||||
@@ -316,11 +316,19 @@ let FeedItemInner = ({
|
||||
style={pal.textLight}
|
||||
lineHeight={1.2}
|
||||
numberOfLines={1}
|
||||
text={sanitizeDisplayName(
|
||||
reason.by.displayName ||
|
||||
sanitizeHandle(reason.by.handle),
|
||||
moderation.ui('displayName'),
|
||||
)}
|
||||
text={
|
||||
<Text
|
||||
emoji
|
||||
type="sm-bold"
|
||||
style={pal.textLight}
|
||||
lineHeight={1.2}>
|
||||
{sanitizeDisplayName(
|
||||
reason.by.displayName ||
|
||||
sanitizeHandle(reason.by.handle),
|
||||
moderation.ui('displayName'),
|
||||
)}
|
||||
</Text>
|
||||
}
|
||||
href={makeProfileLink(reason.by)}
|
||||
onBeforePress={onOpenReposter}
|
||||
/>
|
||||
@@ -527,9 +535,11 @@ function ReplyToLabel({
|
||||
numberOfLines={1}
|
||||
href={makeProfileLink(profile)}
|
||||
text={
|
||||
profile.displayName
|
||||
? sanitizeDisplayName(profile.displayName)
|
||||
: sanitizeHandle(profile.handle)
|
||||
<Text emoji type="md" style={pal.textLight} lineHeight={1.2}>
|
||||
{profile.displayName
|
||||
? sanitizeDisplayName(profile.displayName)
|
||||
: sanitizeHandle(profile.handle)}
|
||||
</Text>
|
||||
}
|
||||
/>
|
||||
</ProfileHoverCard>
|
||||
|
||||
@@ -7,17 +7,17 @@ import {
|
||||
} from '@atproto/api'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {getModerationCauseKey, isJustAMute} from '#/lib/moderation'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {s} from '#/lib/styles'
|
||||
import {useProfileShadow} from '#/state/cache/profile-shadow'
|
||||
import {Shadow} from '#/state/cache/types'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {precacheProfile} from '#/state/queries/profile'
|
||||
import {useSession} from '#/state/session'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {getModerationCauseKey, isJustAMute} from 'lib/moderation'
|
||||
import {makeProfileLink} from 'lib/routes/links'
|
||||
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||
import {sanitizeHandle} from 'lib/strings/handles'
|
||||
import {s} from 'lib/styles'
|
||||
import {precacheProfile} from 'state/queries/profile'
|
||||
import {atoms as a} from '#/alf'
|
||||
import {
|
||||
KnownFollowers,
|
||||
@@ -103,6 +103,7 @@ export function ProfileCard({
|
||||
</View>
|
||||
<View style={styles.layoutContent}>
|
||||
<Text
|
||||
emoji
|
||||
type="lg"
|
||||
style={[s.bold, pal.text, a.self_start]}
|
||||
numberOfLines={1}
|
||||
@@ -112,7 +113,7 @@ export function ProfileCard({
|
||||
moderation.ui('displayName'),
|
||||
)}
|
||||
</Text>
|
||||
<Text type="md" style={[pal.textLight]} numberOfLines={1}>
|
||||
<Text emoji type="md" style={[pal.textLight]} numberOfLines={1}>
|
||||
{sanitizeHandle(profile.handle, '@')}
|
||||
</Text>
|
||||
<ProfileCardPills
|
||||
@@ -128,7 +129,7 @@ export function ProfileCard({
|
||||
{profile.description || knownFollowersVisible ? (
|
||||
<View style={styles.details}>
|
||||
{profile.description ? (
|
||||
<Text style={pal.text} numberOfLines={4}>
|
||||
<Text emoji style={pal.text} numberOfLines={4}>
|
||||
{profile.description as string}
|
||||
</Text>
|
||||
) : null}
|
||||
|
||||
@@ -4,16 +4,16 @@ import {AppBskyActorDefs, ModerationDecision, ModerationUI} from '@atproto/api'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {forceLTR} from '#/lib/strings/bidi'
|
||||
import {NON_BREAKING_SPACE} from '#/lib/strings/constants'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {niceDate} from '#/lib/strings/time'
|
||||
import {TypographyVariant} from '#/lib/ThemeContext'
|
||||
import {isAndroid} from '#/platform/detection'
|
||||
import {precacheProfile} from '#/state/queries/profile'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {makeProfileLink} from 'lib/routes/links'
|
||||
import {forceLTR} from 'lib/strings/bidi'
|
||||
import {NON_BREAKING_SPACE} from 'lib/strings/constants'
|
||||
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||
import {sanitizeHandle} from 'lib/strings/handles'
|
||||
import {niceDate} from 'lib/strings/time'
|
||||
import {TypographyVariant} from 'lib/ThemeContext'
|
||||
import {isAndroid} from 'platform/detection'
|
||||
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
|
||||
import {TextLinkOnWebOnly} from './Link'
|
||||
import {Text} from './text/Text'
|
||||
@@ -73,12 +73,20 @@ let PostMeta = (opts: PostMetaOpts): React.ReactNode => {
|
||||
style={[pal.text]}
|
||||
lineHeight={1.2}
|
||||
disableMismatchWarning
|
||||
text={forceLTR(
|
||||
sanitizeDisplayName(
|
||||
displayName,
|
||||
opts.moderation?.ui('displayName'),
|
||||
),
|
||||
)}
|
||||
text={
|
||||
<Text
|
||||
type={opts.displayNameType || 'lg-bold'}
|
||||
emoji
|
||||
style={[pal.text]}
|
||||
lineHeight={1.2}>
|
||||
{forceLTR(
|
||||
sanitizeDisplayName(
|
||||
displayName,
|
||||
opts.moderation?.ui('displayName'),
|
||||
),
|
||||
)}
|
||||
</Text>
|
||||
}
|
||||
href={profileLink}
|
||||
onBeforePress={onBeforePressAuthor}
|
||||
/>
|
||||
@@ -86,7 +94,11 @@ let PostMeta = (opts: PostMetaOpts): React.ReactNode => {
|
||||
type="md"
|
||||
disableMismatchWarning
|
||||
style={[pal.textLight, {flexShrink: 4}]}
|
||||
text={NON_BREAKING_SPACE + sanitizeHandle(handle, '@')}
|
||||
text={
|
||||
<Text emoji style={[pal.textLight, {flexShrink: 4}]}>
|
||||
{NON_BREAKING_SPACE + sanitizeHandle(handle, '@')}
|
||||
</Text>
|
||||
}
|
||||
href={profileLink}
|
||||
onBeforePress={onBeforePressAuthor}
|
||||
anchorNoUnderline
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import React from 'react'
|
||||
import {AppBskyActorGetProfile as GetProfile} from '@atproto/api'
|
||||
import {StyleProp, StyleSheet, TextStyle} from 'react-native'
|
||||
import {TextLinkOnWebOnly} from './Link'
|
||||
import {Text} from './text/Text'
|
||||
import {LoadingPlaceholder} from './LoadingPlaceholder'
|
||||
import {TypographyVariant} from 'lib/ThemeContext'
|
||||
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||
import {sanitizeHandle} from 'lib/strings/handles'
|
||||
import {makeProfileLink} from 'lib/routes/links'
|
||||
import {useProfileQuery} from '#/state/queries/profile'
|
||||
import {AppBskyActorGetProfile as GetProfile} from '@atproto/api'
|
||||
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {TypographyVariant} from '#/lib/ThemeContext'
|
||||
import {STALE} from '#/state/queries'
|
||||
import {useProfileQuery} from '#/state/queries/profile'
|
||||
import {TextLinkOnWebOnly} from './Link'
|
||||
import {LoadingPlaceholder} from './LoadingPlaceholder'
|
||||
import {Text} from './text/Text'
|
||||
|
||||
export function UserInfoText({
|
||||
type = 'md',
|
||||
@@ -50,11 +51,15 @@ export function UserInfoText({
|
||||
lineHeight={1.2}
|
||||
numberOfLines={1}
|
||||
href={makeProfileLink(profile)}
|
||||
text={`${prefix || ''}${sanitizeDisplayName(
|
||||
typeof profile[attr] === 'string' && profile[attr]
|
||||
? (profile[attr] as string)
|
||||
: sanitizeHandle(profile.handle),
|
||||
)}`}
|
||||
text={
|
||||
<Text emoji type={type} style={style} lineHeight={1.2}>
|
||||
{`${prefix || ''}${sanitizeDisplayName(
|
||||
typeof profile[attr] === 'string' && profile[attr]
|
||||
? (profile[attr] as string)
|
||||
: sanitizeHandle(profile.handle),
|
||||
)}`}
|
||||
</Text>
|
||||
}
|
||||
/>
|
||||
)
|
||||
} else {
|
||||
|
||||
@@ -5,21 +5,21 @@ import {AppBskyEmbedExternal} from '@atproto/api'
|
||||
import {msg} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||
import {shareUrl} from 'lib/sharing'
|
||||
import {parseEmbedPlayerFromUrl} from 'lib/strings/embed-player'
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
|
||||
import {shareUrl} from '#/lib/sharing'
|
||||
import {parseEmbedPlayerFromUrl} from '#/lib/strings/embed-player'
|
||||
import {
|
||||
getStarterPackOgCard,
|
||||
parseStarterPackUri,
|
||||
} from 'lib/strings/starter-pack'
|
||||
import {toNiceDomain} from 'lib/strings/url-helpers'
|
||||
import {isNative} from 'platform/detection'
|
||||
import {useExternalEmbedsPrefs} from 'state/preferences'
|
||||
import {Link} from 'view/com/util/Link'
|
||||
import {ExternalGifEmbed} from 'view/com/util/post-embeds/ExternalGifEmbed'
|
||||
import {ExternalPlayer} from 'view/com/util/post-embeds/ExternalPlayerEmbed'
|
||||
import {GifEmbed} from 'view/com/util/post-embeds/GifEmbed'
|
||||
} from '#/lib/strings/starter-pack'
|
||||
import {toNiceDomain} from '#/lib/strings/url-helpers'
|
||||
import {isNative} from '#/platform/detection'
|
||||
import {useExternalEmbedsPrefs} from '#/state/preferences'
|
||||
import {Link} from '#/view/com/util/Link'
|
||||
import {ExternalGifEmbed} from '#/view/com/util/post-embeds/ExternalGifEmbed'
|
||||
import {ExternalPlayer} from '#/view/com/util/post-embeds/ExternalPlayerEmbed'
|
||||
import {GifEmbed} from '#/view/com/util/post-embeds/GifEmbed'
|
||||
import {atoms as a, useTheme} from '#/alf'
|
||||
import {MediaInsetBorder} from '#/components/MediaInsetBorder'
|
||||
import {Text} from '../text/Text'
|
||||
@@ -115,12 +115,13 @@ export const ExternalLinkEmbed = ({
|
||||
</Text>
|
||||
|
||||
{!embedPlayerParams?.isGif && !embedPlayerParams?.dimensions && (
|
||||
<Text type="lg-bold" numberOfLines={3} style={[pal.text]}>
|
||||
<Text emoji type="lg-bold" numberOfLines={3} style={[pal.text]}>
|
||||
{link.title || link.uri}
|
||||
</Text>
|
||||
)}
|
||||
{link.description ? (
|
||||
<Text
|
||||
emoji
|
||||
type="md"
|
||||
numberOfLines={link.thumb ? 2 : 4}
|
||||
style={[pal.text, a.mt_xs]}>
|
||||
|
||||
@@ -2,27 +2,40 @@ import React from 'react'
|
||||
import {StyleSheet, Text as RNText, TextProps} from 'react-native'
|
||||
import {UITextView} from 'react-native-uitextview'
|
||||
|
||||
import {lh, s} from 'lib/styles'
|
||||
import {TypographyVariant, useTheme} from 'lib/ThemeContext'
|
||||
import {isIOS, isWeb} from 'platform/detection'
|
||||
import {lh, s} from '#/lib/styles'
|
||||
import {TypographyVariant, useTheme} from '#/lib/ThemeContext'
|
||||
import {logger} from '#/logger'
|
||||
import {isIOS} from '#/platform/detection'
|
||||
import {applyFonts, useAlf} from '#/alf'
|
||||
import {
|
||||
childHasEmoji,
|
||||
childIsString,
|
||||
renderChildrenWithEmoji,
|
||||
StringChild,
|
||||
} from '#/components/Typography'
|
||||
import {IS_DEV} from '#/env'
|
||||
|
||||
export type CustomTextProps = TextProps & {
|
||||
export type CustomTextProps = Omit<TextProps, 'children'> & {
|
||||
type?: TypographyVariant
|
||||
lineHeight?: number
|
||||
title?: string
|
||||
dataSet?: Record<string, string | number>
|
||||
selectable?: boolean
|
||||
}
|
||||
|
||||
const fontFamilyStyle = {
|
||||
fontFamily:
|
||||
'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Liberation Sans", Helvetica, Arial, sans-serif',
|
||||
}
|
||||
} & (
|
||||
| {
|
||||
emoji: true
|
||||
children: StringChild
|
||||
}
|
||||
| {
|
||||
emoji?: false
|
||||
children: TextProps['children']
|
||||
}
|
||||
)
|
||||
|
||||
export function Text({
|
||||
type = 'md',
|
||||
children,
|
||||
emoji,
|
||||
lineHeight,
|
||||
style,
|
||||
title,
|
||||
@@ -35,6 +48,18 @@ export function Text({
|
||||
const lineHeightStyle = lineHeight ? lh(theme, type, lineHeight) : undefined
|
||||
const {fonts} = useAlf()
|
||||
|
||||
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.')
|
||||
}
|
||||
}
|
||||
|
||||
if (selectable && isIOS) {
|
||||
const flattened = StyleSheet.flatten([
|
||||
s.black,
|
||||
@@ -58,7 +83,7 @@ export function Text({
|
||||
selectable={selectable}
|
||||
uiTextView
|
||||
{...props}>
|
||||
{children}
|
||||
{isIOS && emoji ? renderChildrenWithEmoji(children) : children}
|
||||
</UITextView>
|
||||
)
|
||||
}
|
||||
@@ -66,7 +91,6 @@ export function Text({
|
||||
const flattened = StyleSheet.flatten([
|
||||
s.black,
|
||||
typography,
|
||||
isWeb && fontFamilyStyle,
|
||||
lineHeightStyle,
|
||||
style,
|
||||
])
|
||||
@@ -87,7 +111,7 @@ export function Text({
|
||||
dataSet={Object.assign({tooltip: title}, dataSet || {})}
|
||||
selectable={selectable}
|
||||
{...props}>
|
||||
{children}
|
||||
{isIOS && emoji ? renderChildrenWithEmoji(children) : children}
|
||||
</RNText>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
import React from 'react'
|
||||
import {CustomTextProps, Text} from './Text'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {addStyle} from 'lib/styles'
|
||||
|
||||
export type ThemedTextProps = CustomTextProps & {
|
||||
fg?: 'default' | 'light' | 'error' | 'inverted' | 'inverted-light'
|
||||
bg?: 'default' | 'light' | 'error' | 'inverted' | 'inverted-light'
|
||||
border?: 'default' | 'dark' | 'error' | 'inverted' | 'inverted-dark'
|
||||
lineHeight?: number
|
||||
}
|
||||
|
||||
export function ThemedText({
|
||||
fg,
|
||||
bg,
|
||||
border,
|
||||
style,
|
||||
children,
|
||||
...props
|
||||
}: React.PropsWithChildren<ThemedTextProps>) {
|
||||
const pal = usePalette('default')
|
||||
const palInverted = usePalette('inverted')
|
||||
const palError = usePalette('error')
|
||||
switch (fg) {
|
||||
case 'default':
|
||||
style = addStyle(style, pal.text)
|
||||
break
|
||||
case 'light':
|
||||
style = addStyle(style, pal.textLight)
|
||||
break
|
||||
case 'error':
|
||||
style = addStyle(style, {color: palError.colors.background})
|
||||
break
|
||||
case 'inverted':
|
||||
style = addStyle(style, palInverted.text)
|
||||
break
|
||||
case 'inverted-light':
|
||||
style = addStyle(style, palInverted.textLight)
|
||||
break
|
||||
}
|
||||
switch (bg) {
|
||||
case 'default':
|
||||
style = addStyle(style, pal.view)
|
||||
break
|
||||
case 'light':
|
||||
style = addStyle(style, pal.viewLight)
|
||||
break
|
||||
case 'error':
|
||||
style = addStyle(style, palError.view)
|
||||
break
|
||||
case 'inverted':
|
||||
style = addStyle(style, palInverted.view)
|
||||
break
|
||||
case 'inverted-light':
|
||||
style = addStyle(style, palInverted.viewLight)
|
||||
break
|
||||
}
|
||||
switch (border) {
|
||||
case 'default':
|
||||
style = addStyle(style, pal.border)
|
||||
break
|
||||
case 'dark':
|
||||
style = addStyle(style, pal.borderDark)
|
||||
break
|
||||
case 'error':
|
||||
style = addStyle(style, palError.border)
|
||||
break
|
||||
case 'inverted':
|
||||
style = addStyle(style, palInverted.border)
|
||||
break
|
||||
case 'inverted-dark':
|
||||
style = addStyle(style, palInverted.borderDark)
|
||||
break
|
||||
}
|
||||
return (
|
||||
<Text style={style} {...props}>
|
||||
{children}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
@@ -959,6 +959,7 @@ function SearchHistory({
|
||||
accessibilityIgnoresInvertColors
|
||||
/>
|
||||
<Text
|
||||
emoji
|
||||
style={[pal.text, styles.profileName]}
|
||||
numberOfLines={1}>
|
||||
{profile.displayName || profile.handle}
|
||||
|
||||
@@ -16,19 +16,19 @@ import {useLingui} from '@lingui/react'
|
||||
import {StackActions, useNavigation} from '@react-navigation/native'
|
||||
import {useQueryClient} from '@tanstack/react-query'
|
||||
|
||||
import {usePalette} from '#/lib/hooks/usePalette'
|
||||
import {makeProfileLink} from '#/lib/routes/links'
|
||||
import {NavigationProp} from '#/lib/routes/types'
|
||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||
import {s} from '#/lib/styles'
|
||||
import {useModerationOpts} from '#/state/preferences/moderation-opts'
|
||||
import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {NavigationProp} from 'lib/routes/types'
|
||||
import {precacheProfile} from 'state/queries/profile'
|
||||
import {precacheProfile} from '#/state/queries/profile'
|
||||
import {SearchInput} from '#/view/com/util/forms/SearchInput'
|
||||
import {Link} from '#/view/com/util/Link'
|
||||
import {Text} from '#/view/com/util/text/Text'
|
||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||
import {SearchInput} from 'view/com/util/forms/SearchInput'
|
||||
import {Text} from 'view/com/util/text/Text'
|
||||
import {atoms as a} from '#/alf'
|
||||
|
||||
let SearchLinkCard = ({
|
||||
@@ -126,6 +126,7 @@ let SearchProfileCard = ({
|
||||
/>
|
||||
<View style={{flex: 1}}>
|
||||
<Text
|
||||
emoji
|
||||
type="lg"
|
||||
style={[s.bold, pal.text, a.self_start]}
|
||||
numberOfLines={1}
|
||||
|
||||
Reference in New Issue
Block a user