Swap `RichText` (#2934)

* Switch to new RT

* Allow early exit from links

* Build in tracking to text atoms

* Clean up FeedSourceCard

* Clean up leading after new default

* Add deprecated notice
zio/stable
Eric Bailey 2024-02-20 11:03:04 -06:00 committed by GitHub
parent 8a169dc6a1
commit df5a8f1542
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 65 additions and 43 deletions

View File

@ -176,43 +176,59 @@ export const atoms = {
}, },
text_2xs: { text_2xs: {
fontSize: tokens.fontSize._2xs, fontSize: tokens.fontSize._2xs,
letterSpacing: 0.25,
}, },
text_xs: { text_xs: {
fontSize: tokens.fontSize.xs, fontSize: tokens.fontSize.xs,
letterSpacing: 0.25,
}, },
text_sm: { text_sm: {
fontSize: tokens.fontSize.sm, fontSize: tokens.fontSize.sm,
letterSpacing: 0.25,
}, },
text_md: { text_md: {
fontSize: tokens.fontSize.md, fontSize: tokens.fontSize.md,
letterSpacing: 0.25,
}, },
text_lg: { text_lg: {
fontSize: tokens.fontSize.lg, fontSize: tokens.fontSize.lg,
letterSpacing: 0.25,
}, },
text_xl: { text_xl: {
fontSize: tokens.fontSize.xl, fontSize: tokens.fontSize.xl,
letterSpacing: 0.25,
}, },
text_2xl: { text_2xl: {
fontSize: tokens.fontSize._2xl, fontSize: tokens.fontSize._2xl,
letterSpacing: 0.25,
}, },
text_3xl: { text_3xl: {
fontSize: tokens.fontSize._3xl, fontSize: tokens.fontSize._3xl,
letterSpacing: 0.25,
}, },
text_4xl: { text_4xl: {
fontSize: tokens.fontSize._4xl, fontSize: tokens.fontSize._4xl,
letterSpacing: 0.25,
}, },
text_5xl: { text_5xl: {
fontSize: tokens.fontSize._5xl, fontSize: tokens.fontSize._5xl,
letterSpacing: 0.25,
}, },
leading_tight: { leading_tight: {
lineHeight: 1.15, lineHeight: 1.15,
}, },
leading_snug: { leading_snug: {
lineHeight: 1.25, lineHeight: 1.3,
}, },
leading_normal: { leading_normal: {
lineHeight: 1.5, lineHeight: 1.5,
}, },
tracking_normal: {
letterSpacing: 0,
},
tracking_wide: {
letterSpacing: 0.25,
},
font_normal: { font_normal: {
fontWeight: tokens.fontWeight.normal, fontWeight: tokens.fontWeight.normal,
}, },

View File

@ -51,11 +51,12 @@ type BaseLinkProps = Pick<
warnOnMismatchingTextChild?: boolean warnOnMismatchingTextChild?: boolean
/** /**
* Callback for when the link is pressed. * Callback for when the link is pressed. Prevent default and return `false`
* to exit early and prevent navigation.
* *
* DO NOT use this for navigation, that's what the `to` prop is for. * DO NOT use this for navigation, that's what the `to` prop is for.
*/ */
onPress?: (e: GestureResponderEvent) => void onPress?: (e: GestureResponderEvent) => void | false
/** /**
* Web-only attribute. Sets `download` attr on web. * Web-only attribute. Sets `download` attr on web.
@ -82,7 +83,9 @@ export function useLink({
const onPress = React.useCallback( const onPress = React.useCallback(
(e: GestureResponderEvent) => { (e: GestureResponderEvent) => {
outerOnPress?.(e) const exitEarlyIfFalse = outerOnPress?.(e)
if (exitEarlyIfFalse === false) return
const requiresWarning = Boolean( const requiresWarning = Boolean(
warnOnMismatchingTextChild && warnOnMismatchingTextChild &&

View File

@ -1,7 +1,7 @@
import React from 'react' import React from 'react'
import {RichText as RichTextAPI, AppBskyRichtextFacet} from '@atproto/api' import {RichText as RichTextAPI, AppBskyRichtextFacet} from '@atproto/api'
import {atoms as a, TextStyleProp} from '#/alf' import {atoms as a, TextStyleProp, flatten} from '#/alf'
import {InlineLink} from '#/components/Link' import {InlineLink} from '#/components/Link'
import {Text, TextProps} from '#/components/Typography' import {Text, TextProps} from '#/components/Typography'
import {toShortUrl} from 'lib/strings/url-helpers' import {toShortUrl} from 'lib/strings/url-helpers'
@ -29,7 +29,7 @@ export function RichText({
const [richText, setRichText] = React.useState<RichTextAPI>(() => const [richText, setRichText] = React.useState<RichTextAPI>(() =>
value instanceof RichTextAPI ? value : new RichTextAPI({text: value}), value instanceof RichTextAPI ? value : new RichTextAPI({text: value}),
) )
const styles = [a.leading_normal, style] const styles = [a.leading_snug, flatten(style)]
React.useEffect(() => { React.useEffect(() => {
if (!resolveFacets) return if (!resolveFacets) return

View File

@ -2,7 +2,7 @@ import React from 'react'
import {Pressable, StyleProp, StyleSheet, View, ViewStyle} from 'react-native' import {Pressable, StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
import {RichText} from '../util/text/RichText' import {RichText} from '#/components/RichText'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
import {s} from 'lib/styles' import {s} from 'lib/styles'
import {UserAvatar} from '../util/UserAvatar' import {UserAvatar} from '../util/UserAvatar'
@ -25,6 +25,7 @@ import {
} from '#/state/queries/preferences' } from '#/state/queries/preferences'
import {useFeedSourceInfoQuery, FeedSourceInfo} from '#/state/queries/feed' import {useFeedSourceInfoQuery, FeedSourceInfo} from '#/state/queries/feed'
import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder'
import {useTheme} from '#/alf'
export function FeedSourceCard({ export function FeedSourceCard({
feedUri, feedUri,
@ -82,6 +83,7 @@ export function FeedSourceCardLoaded({
pinOnSave?: boolean pinOnSave?: boolean
showMinimalPlaceholder?: boolean showMinimalPlaceholder?: boolean
}) { }) {
const t = useTheme()
const pal = usePalette('default') const pal = usePalette('default')
const {_} = useLingui() const {_} = useLingui()
const navigation = useNavigation<NavigationProp>() const navigation = useNavigation<NavigationProp>()
@ -266,8 +268,8 @@ export function FeedSourceCardLoaded({
{showDescription && feed.description ? ( {showDescription && feed.description ? (
<RichText <RichText
style={[pal.textLight, styles.description]} style={[t.atoms.text_contrast_high, styles.description]}
richText={feed.description} value={feed.description}
numberOfLines={3} numberOfLines={3}
/> />
) : null} ) : null}

View File

@ -3,7 +3,7 @@ import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native'
import {AtUri, AppBskyGraphDefs, RichText} from '@atproto/api' import {AtUri, AppBskyGraphDefs, RichText} from '@atproto/api'
import {Link} from '../util/Link' import {Link} from '../util/Link'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
import {RichText as RichTextCom} from '../util/text/RichText' import {RichText as RichTextCom} from '#/components/RichText'
import {UserAvatar} from '../util/UserAvatar' import {UserAvatar} from '../util/UserAvatar'
import {s} from 'lib/styles' import {s} from 'lib/styles'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
@ -12,6 +12,7 @@ import {sanitizeDisplayName} from 'lib/strings/display-names'
import {sanitizeHandle} from 'lib/strings/handles' import {sanitizeHandle} from 'lib/strings/handles'
import {makeProfileLink} from 'lib/routes/links' import {makeProfileLink} from 'lib/routes/links'
import {Trans} from '@lingui/macro' import {Trans} from '@lingui/macro'
import {atoms as a} from '#/alf'
export const ListCard = ({ export const ListCard = ({
testID, testID,
@ -119,9 +120,9 @@ export const ListCard = ({
{descriptionRichText ? ( {descriptionRichText ? (
<View style={styles.details}> <View style={styles.details}>
<RichTextCom <RichTextCom
style={[pal.text, s.flex1]} style={[a.flex_1]}
numberOfLines={20} numberOfLines={20}
richText={descriptionRichText} value={descriptionRichText}
/> />
</View> </View>
) : undefined} ) : undefined}

View File

@ -11,7 +11,7 @@ import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {PostThreadFollowBtn} from 'view/com/post-thread/PostThreadFollowBtn' import {PostThreadFollowBtn} from 'view/com/post-thread/PostThreadFollowBtn'
import {Link, TextLink} from '../util/Link' import {Link, TextLink} from '../util/Link'
import {RichText} from '../util/text/RichText' import {RichText} from '#/components/RichText'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
import {PreviewableUserAvatar} from '../util/UserAvatar' import {PreviewableUserAvatar} from '../util/UserAvatar'
import {s} from 'lib/styles' import {s} from 'lib/styles'
@ -44,6 +44,7 @@ import {ThreadPost} from '#/state/queries/post-thread'
import {useSession} from 'state/session' import {useSession} from 'state/session'
import {WhoCanReply} from '../threadgate/WhoCanReply' import {WhoCanReply} from '../threadgate/WhoCanReply'
import {LoadingPlaceholder} from '../util/LoadingPlaceholder' import {LoadingPlaceholder} from '../util/LoadingPlaceholder'
import {atoms as a} from '#/alf'
export function PostThreadItem({ export function PostThreadItem({
post, post,
@ -326,10 +327,8 @@ let PostThreadItemLoaded = ({
styles.postTextLargeContainer, styles.postTextLargeContainer,
]}> ]}>
<RichText <RichText
type="post-text-lg" value={richText}
richText={richText} style={[a.flex_1, a.text_xl]}
lineHeight={1.3}
style={s.flex1}
selectable selectable
/> />
</View> </View>
@ -522,10 +521,8 @@ let PostThreadItemLoaded = ({
{richText?.text ? ( {richText?.text ? (
<View style={styles.postTextContainer}> <View style={styles.postTextContainer}>
<RichText <RichText
type="post-text" value={richText}
richText={richText} style={[a.flex_1, a.text_md]}
style={[pal.text, s.flex1]}
lineHeight={1.3}
numberOfLines={limitLines ? MAX_POST_LINES : undefined} numberOfLines={limitLines ? MAX_POST_LINES : undefined}
/> />
</View> </View>

View File

@ -20,7 +20,7 @@ import {PostCtrls} from '../util/post-ctrls/PostCtrls'
import {PostEmbeds} from '../util/post-embeds' import {PostEmbeds} from '../util/post-embeds'
import {ContentHider} from '../util/moderation/ContentHider' import {ContentHider} from '../util/moderation/ContentHider'
import {PostAlerts} from '../util/moderation/PostAlerts' import {PostAlerts} from '../util/moderation/PostAlerts'
import {RichText} from '../util/text/RichText' import {RichText} from '#/components/RichText'
import {PreviewableUserAvatar} from '../util/UserAvatar' import {PreviewableUserAvatar} from '../util/UserAvatar'
import {s} from 'lib/styles' import {s} from 'lib/styles'
import {usePalette} from 'lib/hooks/usePalette' import {usePalette} from 'lib/hooks/usePalette'
@ -36,6 +36,7 @@ import {FeedNameText} from '../util/FeedInfoText'
import {useSession} from '#/state/session' import {useSession} from '#/state/session'
import {Trans, msg} from '@lingui/macro' import {Trans, msg} from '@lingui/macro'
import {useLingui} from '@lingui/react' import {useLingui} from '@lingui/react'
import {atoms as a} from '#/alf'
export function FeedItem({ export function FeedItem({
post, post,
@ -347,11 +348,9 @@ let PostContent = ({
<View style={styles.postTextContainer}> <View style={styles.postTextContainer}>
<RichText <RichText
testID="postText" testID="postText"
type="post-text" value={richText}
richText={richText}
lineHeight={1.3}
numberOfLines={limitLines ? MAX_POST_LINES : undefined} numberOfLines={limitLines ? MAX_POST_LINES : undefined}
style={s.flex1} style={[a.flex_1, a.text_md]}
/> />
</View> </View>
) : undefined} ) : undefined}

View File

@ -23,7 +23,7 @@ import * as Toast from '../util/Toast'
import {LoadingPlaceholder} from '../util/LoadingPlaceholder' import {LoadingPlaceholder} from '../util/LoadingPlaceholder'
import {Text} from '../util/text/Text' import {Text} from '../util/text/Text'
import {ThemedText} from '../util/text/ThemedText' import {ThemedText} from '../util/text/ThemedText'
import {RichText} from '../util/text/RichText' import {RichText} from '#/components/RichText'
import {UserAvatar} from '../util/UserAvatar' import {UserAvatar} from '../util/UserAvatar'
import {UserBanner} from '../util/UserBanner' import {UserBanner} from '../util/UserBanner'
import {ProfileHeaderAlerts} from '../util/moderation/ProfileHeaderAlerts' import {ProfileHeaderAlerts} from '../util/moderation/ProfileHeaderAlerts'
@ -56,6 +56,7 @@ import {Shadow} from '#/state/cache/types'
import {useRequireAuth} from '#/state/session' import {useRequireAuth} from '#/state/session'
import {LabelInfo} from '../util/moderation/LabelInfo' import {LabelInfo} from '../util/moderation/LabelInfo'
import {useProfileShadow} from 'state/cache/profile-shadow' import {useProfileShadow} from 'state/cache/profile-shadow'
import {atoms as a} from '#/alf'
let ProfileHeaderLoading = (_props: {}): React.ReactNode => { let ProfileHeaderLoading = (_props: {}): React.ReactNode => {
const pal = usePalette('default') const pal = usePalette('default')
@ -608,12 +609,12 @@ let ProfileHeader = ({
</Text> </Text>
</View> </View>
{descriptionRT && !moderation.profile.blur ? ( {descriptionRT && !moderation.profile.blur ? (
<View pointerEvents="auto"> <View pointerEvents="auto" style={[styles.description]}>
<RichText <RichText
testID="profileHeaderDescription" testID="profileHeaderDescription"
style={[styles.description, pal.text]} style={[a.text_md]}
numberOfLines={15} numberOfLines={15}
richText={descriptionRT} value={descriptionRT}
/> />
</View> </View>
) : undefined} ) : undefined}

View File

@ -20,7 +20,8 @@ import {PostAlerts} from '../moderation/PostAlerts'
import {makeProfileLink} from 'lib/routes/links' import {makeProfileLink} from 'lib/routes/links'
import {InfoCircleIcon} from 'lib/icons' import {InfoCircleIcon} from 'lib/icons'
import {Trans} from '@lingui/macro' import {Trans} from '@lingui/macro'
import {RichText} from 'view/com/util/text/RichText' import {RichText} from '#/components/RichText'
import {atoms as a} from '#/alf'
export function MaybeQuoteEmbed({ export function MaybeQuoteEmbed({
embed, embed,
@ -127,11 +128,10 @@ export function QuoteEmbed({
) : null} ) : null}
{richText ? ( {richText ? (
<RichText <RichText
richText={richText} value={richText}
type="post-text" style={[a.text_md]}
style={pal.text}
numberOfLines={20} numberOfLines={20}
noLinks disableLinks
/> />
) : null} ) : null}
{embed && <PostEmbeds embed={embed} moderation={{}} />} {embed && <PostEmbeds embed={embed} moderation={{}} />}

View File

@ -10,6 +10,9 @@ import {usePalette} from 'lib/hooks/usePalette'
const WORD_WRAP = {wordWrap: 1} const WORD_WRAP = {wordWrap: 1}
/**
* @deprecated use `#/components/RichText`
*/
export function RichText({ export function RichText({
testID, testID,
type = 'md', type = 'md',

View File

@ -17,7 +17,7 @@ import {TextLink} from 'view/com/util/Link'
import {ListRef} from 'view/com/util/List' import {ListRef} from 'view/com/util/List'
import {Button} from 'view/com/util/forms/Button' import {Button} from 'view/com/util/forms/Button'
import {Text} from 'view/com/util/text/Text' import {Text} from 'view/com/util/text/Text'
import {RichText} from 'view/com/util/text/RichText' import {RichText} from '#/components/RichText'
import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn' import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn'
import {FAB} from 'view/com/util/fab/FAB' import {FAB} from 'view/com/util/fab/FAB'
import {EmptyState} from 'view/com/util/EmptyState' import {EmptyState} from 'view/com/util/EmptyState'
@ -59,6 +59,7 @@ import {useComposerControls} from '#/state/shell/composer'
import {truncateAndInvalidate} from '#/state/queries/util' import {truncateAndInvalidate} from '#/state/queries/util'
import {isNative} from '#/platform/detection' import {isNative} from '#/platform/detection'
import {listenSoftReset} from '#/state/events' import {listenSoftReset} from '#/state/events'
import {atoms as a} from '#/alf'
const SECTION_TITLES = ['Posts', 'About'] const SECTION_TITLES = ['Posts', 'About']
@ -575,9 +576,8 @@ function AboutSection({
{feedInfo.description ? ( {feedInfo.description ? (
<RichText <RichText
testID="listDescription" testID="listDescription"
type="lg" style={[a.text_md]}
style={pal.text} value={feedInfo.description}
richText={feedInfo.description}
/> />
) : ( ) : (
<Text type="lg" style={[{fontStyle: 'italic'}, pal.textLight]}> <Text type="lg" style={[{fontStyle: 'italic'}, pal.textLight]}>

View File

@ -14,7 +14,7 @@ import {NativeDropdown, DropdownItem} from 'view/com/util/forms/NativeDropdown'
import {CenteredView} from 'view/com/util/Views' import {CenteredView} from 'view/com/util/Views'
import {EmptyState} from 'view/com/util/EmptyState' import {EmptyState} from 'view/com/util/EmptyState'
import {LoadingScreen} from 'view/com/util/LoadingScreen' import {LoadingScreen} from 'view/com/util/LoadingScreen'
import {RichText} from 'view/com/util/text/RichText' import {RichText} from '#/components/RichText'
import {Button} from 'view/com/util/forms/Button' import {Button} from 'view/com/util/forms/Button'
import {TextLink} from 'view/com/util/Link' import {TextLink} from 'view/com/util/Link'
import {ListRef} from 'view/com/util/List' import {ListRef} from 'view/com/util/List'
@ -60,6 +60,7 @@ import {
import {logger} from '#/logger' import {logger} from '#/logger'
import {useAnalytics} from '#/lib/analytics/analytics' import {useAnalytics} from '#/lib/analytics/analytics'
import {listenSoftReset} from '#/state/events' import {listenSoftReset} from '#/state/events'
import {atoms as a} from '#/alf'
const SECTION_TITLES_CURATE = ['Posts', 'About'] const SECTION_TITLES_CURATE = ['Posts', 'About']
const SECTION_TITLES_MOD = ['About'] const SECTION_TITLES_MOD = ['About']
@ -742,9 +743,8 @@ const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
{descriptionRT ? ( {descriptionRT ? (
<RichText <RichText
testID="listDescription" testID="listDescription"
type="lg" style={[a.text_md]}
style={pal.text} value={descriptionRT}
richText={descriptionRT}
/> />
) : ( ) : (
<Text <Text