From 726c5b9a2d9cb8b2492be13915c166e8d6ad6986 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Fri, 22 May 2026 11:59:12 -0500 Subject: [PATCH] Improve byline linking and interaction states --- src/components/Link.tsx | 12 +- .../StandardSiteEmbed/PublicationMetaRow.tsx | 12 +- .../Post/Embed/StandardSiteEmbed/index.tsx | 205 ++++++++++-------- 3 files changed, 140 insertions(+), 89 deletions(-) diff --git a/src/components/Link.tsx b/src/components/Link.tsx index 5e111891bd..d667823a5d 100644 --- a/src/components/Link.tsx +++ b/src/components/Link.tsx @@ -326,6 +326,8 @@ export type InlineLinkProps = React.PropsWithChildren< disableUnderline?: boolean title?: TextProps['title'] overridePresentation?: boolean + onMouseEnter?: () => void + onMouseLeave?: () => void } > @@ -388,8 +390,14 @@ export function InlineLinkText({ role="link" onPress={download ? undefined : onPress} onLongPress={onLongPress} - onMouseEnter={onHoverIn} - onMouseLeave={onHoverOut} + onMouseEnter={() => { + rest.onMouseEnter?.() + onHoverIn() + }} + onMouseLeave={() => { + rest.onMouseLeave?.() + onHoverOut() + }} accessibilityRole="link" href={href} {...web({ diff --git a/src/components/Post/Embed/StandardSiteEmbed/PublicationMetaRow.tsx b/src/components/Post/Embed/StandardSiteEmbed/PublicationMetaRow.tsx index 754dae436b..bfc4a9c50a 100644 --- a/src/components/Post/Embed/StandardSiteEmbed/PublicationMetaRow.tsx +++ b/src/components/Post/Embed/StandardSiteEmbed/PublicationMetaRow.tsx @@ -13,9 +13,13 @@ import {Text} from '#/components/Typography' export function PublicationMetaRow({ view, author, + onInteractWithin, + onInteractWithout, }: { view: AppBskyEmbedExternal.ViewExternal author: {did: string | null | undefined} + onInteractWithin: () => void + onInteractWithout: () => void }) { const t = useTheme() const {t: l} = useLingui() @@ -63,7 +67,13 @@ export function PublicationMetaRow({ + style={metaTextStyle} + onPress={e => { + // this link is nested, yes it's not ideal + e.stopPropagation() + }} + onMouseEnter={onInteractWithin} + onMouseLeave={onInteractWithout}> @{handle} diff --git a/src/components/Post/Embed/StandardSiteEmbed/index.tsx b/src/components/Post/Embed/StandardSiteEmbed/index.tsx index 6bb7a1b301..64118fc26c 100644 --- a/src/components/Post/Embed/StandardSiteEmbed/index.tsx +++ b/src/components/Post/Embed/StandardSiteEmbed/index.tsx @@ -18,6 +18,7 @@ import {UserAvatar} from '#/view/com/util/UserAvatar' import {atoms as a, useBreakpoints, useTheme, utils} from '#/alf' import {ButtonIcon, ButtonText} from '#/components/Button' import {Divider} from '#/components/Divider' +import {useInteractionState} from '#/components/hooks/useInteractionState' import {Clock_Stroke2_Corner0_Rounded as Clock} from '#/components/icons/Clock' import {Leaflet} from '#/components/icons/community/Leaflet' import {Offprint} from '#/components/icons/community/Offprint' @@ -309,8 +310,10 @@ export const StandardSiteEmbed = ({ {view.source && ( - - + <> + + + - + )} ) @@ -344,6 +347,11 @@ export function PublicationCard({ const t = useTheme() const {t: l} = useLingui() const {gtPhone} = useBreakpoints() + const { + state: interactedWithin, + onIn: onInteractWithin, + onOut: onInteractWithout, + } = useInteractionState() if (!view.source) return null @@ -354,77 +362,85 @@ export function PublicationCard({ label={l`Subscribe`} onPress={onPress} onLongPress={onLongPress}> - {({hovered}) => ( - + {({hovered: maybeHovered}) => { + const hovered = maybeHovered && !interactedWithin + return ( + a.flex_col, + a.rounded_md, + a.overflow_hidden, + a.w_full, + a.border, + a.p_md, + t.atoms.border_contrast_low, + style, + ]}> - <> - + + <> + + + + {view.source?.title} + + + + + + + {!hideSubscribe && ( + - - - {view.source?.title} - - - - + )} - {!hideSubscribe && ( - + {view.description && ( + + + {view.description} + + )} - - {view.description && ( - - - {view.description} - - - )} - - )} + ) + }} ) } @@ -548,6 +564,17 @@ export function PublicationFooter({ const t = useTheme() const {t: l} = useLingui() const {gtPhone} = useBreakpoints() + const { + state: maybeHovered, + onIn: onHoverIn, + onOut: onHoverOut, + } = useInteractionState() + const { + state: interactedWithin, + onIn: onInteractWithin, + onOut: onInteractWithout, + } = useInteractionState() + const hovered = maybeHovered && !interactedWithin if (!view.source) return null @@ -557,11 +584,14 @@ export function PublicationFooter({ a.flex_1, a.align_center, a.justify_between, - a.py_md, + a.p_md, a.gap_md, gtPhone && [a.flex_row, a.gap_sm], ]} - testID="publication-embed-footer"> + testID="publication-embed-footer" + // @ts-ignore it's Fineā„¢ + onMouseEnter={onHoverIn} + onMouseLeave={onHoverOut}> - {({hovered}) => ( - <> - + + + + {view.source?.title} + + - - - {view.source?.title} - - - - - )} + + {!hideSubscribe && (