Replace pointerEvents props with atoms styles

Migrate all pointerEvents prop usage to use the atoms system (a.pointer_events_none, a.pointer_events_auto, a.pointer_events_box_none) for consistency with the design system.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Samuel Newman
2026-01-12 11:02:26 +02:00
parent fd6b8fcbf1
commit 501f78a3d7
25 changed files with 163 additions and 129 deletions
+1 -1
View File
@@ -44,8 +44,8 @@ export function AccountList({
return (
<View
pointerEvents={pendingDid ? 'none' : 'auto'}
style={[
pendingDid ? a.pointer_events_none : a.pointer_events_auto,
a.rounded_lg,
a.overflow_hidden,
a.border,
+4 -4
View File
@@ -680,20 +680,20 @@ export function ProfileGrid({
<View
ref={containerRef}
style={[
IS_IOS ? a.pointer_events_auto : a.pointer_events_box_none,
!isProfileHeaderContext && a.border_t,
t.atoms.border_contrast_low,
t.atoms.bg_contrast_25,
]}
pointerEvents={IS_IOS ? 'auto' : 'box-none'}>
]}>
<View
style={[
IS_IOS ? a.pointer_events_auto : a.pointer_events_box_none,
a.px_lg,
a.pt_md,
a.flex_row,
a.align_center,
a.justify_between,
]}
pointerEvents={IS_IOS ? 'auto' : 'box-none'}>
]}>
<Text style={[a.text_sm, a.font_semi_bold, t.atoms.text]}>
<Trans>Suggested for you</Trans>
</Text>
@@ -29,7 +29,6 @@ export function TimeIndicator({
return (
<View
pointerEvents="none"
accessibilityLabel={_(
msg`Time remaining: ${plural(Number(time) || 0, {
one: '# second',
@@ -38,6 +37,7 @@ export function TimeIndicator({
)}
accessibilityHint=""
style={[
a.pointer_events_none,
{
backgroundColor: 'rgba(0, 0, 0, 0.5)',
borderRadius: 6,
@@ -413,8 +413,13 @@ export function Controls({
</View>
{(showSpinner || error) && (
<View
pointerEvents="none"
style={[a.absolute, a.inset_0, a.justify_center, a.align_center]}>
style={[
a.pointer_events_none,
a.absolute,
a.inset_0,
a.justify_center,
a.align_center,
]}>
{showSpinner && <Loader fill={t.palette.white} size="lg" />}
{error && (
<Text style={{color: t.palette.white}}>
+1 -1
View File
@@ -307,7 +307,7 @@ export function QuoteEmbed({
onBeforePress={onBeforePress}
onPressIn={onPressIn}
onPressOut={onPressOut}>
<View pointerEvents="none">
<View style={a.pointer_events_none}>
<PostMeta
author={quote.author}
moderation={moderation}
@@ -13,6 +13,7 @@ import Animated, {
withTiming,
} from 'react-native-reanimated'
import {atoms as a} from '#/alf'
import {IS_IOS, IS_WEB} from '#/env'
type AccordionAnimationProps = React.PropsWithChildren<{
@@ -63,10 +64,12 @@ function MobileAccordion({
return (
<Animated.View
style={style}
style={[
IS_IOS ? a.pointer_events_auto : a.pointer_events_box_none,
style,
]}
entering={FadeInUp.duration(duration)}
exiting={FadeOutUp.duration(duration / 2)}
pointerEvents={IS_IOS ? 'auto' : 'box-none'}>
exiting={FadeOutUp.duration(duration / 2)}>
{children}
</Animated.View>
)
+28 -24
View File
@@ -6,7 +6,7 @@ import Animated, {
} from 'react-native-reanimated'
import {s} from '#/lib/styles'
import {useTheme} from '#/alf'
import {atoms as a, useTheme} from '#/alf'
import {
Heart2_Filled_Stroke2_Corner0_Rounded as HeartIconFilled,
Heart2_Stroke2_Corner0_Rounded as HeartIconOutline,
@@ -90,7 +90,7 @@ export function AnimatedLikeIcon({
</Animated.View>
) : (
<HeartIconOutline
style={[{color: t.palette.contrast_500}, {pointerEvents: 'none'}]}
style={[{color: t.palette.contrast_500}, a.pointer_events_none]}
width={size}
/>
)}
@@ -98,31 +98,35 @@ export function AnimatedLikeIcon({
<>
<Animated.View
entering={circle1Keyframe.duration(300)}
style={{
position: 'absolute',
backgroundColor: s.likeColor.color,
top: 0,
left: 0,
width: size,
height: size,
zIndex: -1,
pointerEvents: 'none',
borderRadius: size / 2,
}}
style={[
a.pointer_events_none,
{
position: 'absolute',
backgroundColor: s.likeColor.color,
top: 0,
left: 0,
width: size,
height: size,
zIndex: -1,
borderRadius: size / 2,
},
]}
/>
<Animated.View
entering={circle2Keyframe.duration(300)}
style={{
position: 'absolute',
backgroundColor: t.atoms.bg.backgroundColor,
top: 0,
left: 0,
width: size,
height: size,
zIndex: -1,
pointerEvents: 'none',
borderRadius: size / 2,
}}
style={[
a.pointer_events_none,
{
position: 'absolute',
backgroundColor: t.atoms.bg.backgroundColor,
top: 0,
left: 0,
width: size,
height: size,
zIndex: -1,
borderRadius: size / 2,
},
]}
/>
</>
) : null}
+30 -26
View File
@@ -3,7 +3,7 @@ import {View} from 'react-native'
import {useReducedMotion} from 'react-native-reanimated'
import {s} from '#/lib/styles'
import {useTheme} from '#/alf'
import {atoms as a, useTheme} from '#/alf'
import {
Heart2_Filled_Stroke2_Corner0_Rounded as HeartIconFilled,
Heart2_Stroke2_Corner0_Rounded as HeartIconOutline,
@@ -78,41 +78,45 @@ export function AnimatedLikeIcon({
</View>
) : (
<HeartIconOutline
style={[{color: t.palette.contrast_500}, {pointerEvents: 'none'}]}
style={[{color: t.palette.contrast_500}, a.pointer_events_none]}
width={size}
/>
)}
<View
// @ts-expect-error is div
ref={circle1Ref}
style={{
position: 'absolute',
backgroundColor: s.likeColor.color,
top: 0,
left: 0,
width: size,
height: size,
zIndex: -1,
pointerEvents: 'none',
borderRadius: size / 2,
opacity: 0,
}}
style={[
a.pointer_events_none,
{
position: 'absolute',
backgroundColor: s.likeColor.color,
top: 0,
left: 0,
width: size,
height: size,
zIndex: -1,
borderRadius: size / 2,
opacity: 0,
},
]}
/>
<View
// @ts-expect-error is div
ref={circle2Ref}
style={{
position: 'absolute',
backgroundColor: t.atoms.bg.backgroundColor,
top: 0,
left: 0,
width: size,
height: size,
zIndex: -1,
pointerEvents: 'none',
borderRadius: size / 2,
opacity: 0,
}}
style={[
a.pointer_events_none,
{
position: 'absolute',
backgroundColor: t.atoms.bg.backgroundColor,
top: 0,
left: 0,
width: size,
height: size,
zIndex: -1,
borderRadius: size / 2,
opacity: 0,
},
]}
/>
</View>
)
@@ -167,6 +167,7 @@ export function MessageInputEmbed({
content = (
<View
style={[
a.pointer_events_none,
a.flex_1,
t.atoms.bg,
t.atoms.border_contrast_low,
@@ -174,8 +175,7 @@ export function MessageInputEmbed({
a.border,
a.p_sm,
a.mb_sm,
]}
pointerEvents="none">
]}>
<PostMeta
showAvatar
author={post.author}
+1 -1
View File
@@ -18,7 +18,7 @@ export function ProfileHeaderDisplayName({
const {gtMobile} = useBreakpoints()
return (
<View pointerEvents="none">
<View style={a.pointer_events_none}>
<Text
emoji
testID="profileHeaderDisplayName"
@@ -153,15 +153,14 @@ function GrowableBannerInner({
</Animated.View>
</Pressable>
<AnimatedBlurView
pointerEvents="none"
style={[a.absolute, a.inset_0]}
style={[a.pointer_events_none, a.absolute, a.inset_0]}
tint="dark"
animatedProps={animatedBlurViewProps}
/>
</Animated.View>
<View
pointerEvents="none"
style={[
a.pointer_events_none,
a.absolute,
a.inset_0,
{top: topInset - (IS_IOS ? 15 : 0)},
+11 -2
View File
@@ -23,8 +23,17 @@ export function ProfileHeaderHandle({
const blockHide = profile.viewer?.blocking || profile.viewer?.blockedBy
return (
<View
style={[a.flex_row, a.gap_sm, a.align_center, {maxWidth: '100%'}]}
pointerEvents={disableTaps ? 'none' : IS_IOS ? 'auto' : 'box-none'}>
style={[
a.flex_row,
a.gap_sm,
a.align_center,
{maxWidth: '100%'},
disableTaps
? a.pointer_events_none
: IS_IOS
? a.pointer_events_auto
: a.pointer_events_box_none,
]}>
<NewskieDialog profile={profile} disabled={disableTaps} />
{profile.viewer?.followedBy && !blockHide ? (
<View style={[t.atoms.bg_contrast_50, a.rounded_xs, a.px_sm, a.py_xs]}>
+1 -2
View File
@@ -30,8 +30,7 @@ export function ProfileHeaderMetrics({
return (
<View
style={[a.flex_row, a.gap_sm, a.align_center]}
pointerEvents="box-none">
style={[a.flex_row, a.gap_sm, a.align_center, a.pointer_events_box_none]}>
<InlineLinkText
testID="profileHeaderFollowersButton"
style={[a.flex_row, t.atoms.text]}
@@ -111,11 +111,21 @@ let ProfileHeaderLabeler = ({
hideBackButton={hideBackButton}
isPlaceholderProfile={isPlaceholderProfile}>
<View
style={[a.px_lg, a.pt_md, a.pb_sm]}
pointerEvents={IS_IOS ? 'auto' : 'box-none'}>
style={[
a.px_lg,
a.pt_md,
a.pb_sm,
IS_IOS ? a.pointer_events_auto : a.pointer_events_box_none,
]}>
<View
style={[a.flex_row, a.justify_end, a.align_center, a.gap_xs, a.pb_lg]}
pointerEvents={IS_IOS ? 'auto' : 'box-none'}>
style={[
a.flex_row,
a.justify_end,
a.align_center,
a.gap_xs,
a.pb_lg,
IS_IOS ? a.pointer_events_auto : a.pointer_events_box_none,
]}>
<HeaderLabelerButtons profile={profile} />
</View>
<View style={[a.flex_col, a.gap_2xs, a.pt_2xs, a.pb_md]}>
@@ -126,7 +136,7 @@ let ProfileHeaderLabeler = ({
<>
{isSelf && <ProfileHeaderMetrics profile={profile} />}
{descriptionRT && !moderation.ui('profileView').blur ? (
<View pointerEvents="auto">
<View style={a.pointer_events_auto}>
<RichText
testID="profileHeaderDescription"
style={[a.text_md]}
@@ -102,8 +102,13 @@ let ProfileHeaderStandard = ({
hideBackButton={hideBackButton}
isPlaceholderProfile={isPlaceholderProfile}>
<View
style={[a.px_lg, a.pt_md, a.pb_sm, a.overflow_hidden]}
pointerEvents={IS_IOS ? 'auto' : 'box-none'}>
style={[
a.px_lg,
a.pt_md,
a.pb_sm,
a.overflow_hidden,
IS_IOS ? a.pointer_events_auto : a.pointer_events_box_none,
]}>
<View
style={[
{paddingLeft: 90},
@@ -113,8 +118,8 @@ let ProfileHeaderStandard = ({
a.gap_xs,
a.pb_sm,
a.flex_wrap,
]}
pointerEvents={IS_IOS ? 'auto' : 'box-none'}>
IS_IOS ? a.pointer_events_auto : a.pointer_events_box_none,
]}>
<HeaderStandardButtons
profile={profile}
moderation={moderation}
@@ -151,7 +156,7 @@ let ProfileHeaderStandard = ({
<View style={a.gap_md}>
<ProfileHeaderMetrics profile={profile} />
{descriptionRT && !moderation.ui('profileView').blur ? (
<View pointerEvents="auto">
<View style={a.pointer_events_auto}>
<RichText
testID="profileHeaderDescription"
style={[a.text_md]}
+12 -5
View File
@@ -161,10 +161,17 @@ let ProfileHeaderShell = ({
}, [profile.banner, moderation, _openLightbox, bannerRef])
return (
<View style={t.atoms.bg} pointerEvents={IS_IOS ? 'auto' : 'box-none'}>
<View
style={[
t.atoms.bg,
IS_IOS ? a.pointer_events_auto : a.pointer_events_box_none,
]}>
<View
pointerEvents={IS_IOS ? 'auto' : 'box-none'}
style={[a.relative, {height: 150}]}>
style={[
a.relative,
{height: 150},
IS_IOS ? a.pointer_events_auto : a.pointer_events_box_none,
]}>
<StatusBarShadow />
<GrowableBanner
onPress={isPlaceholderProfile ? undefined : onPressBanner}
@@ -238,7 +245,7 @@ let ProfileHeaderShell = ({
a.px_lg,
a.pt_xs,
a.pb_sm,
IS_IOS ? a.pointer_events_auto : {pointerEvents: 'box-none'},
IS_IOS ? a.pointer_events_auto : a.pointer_events_box_none,
]}
/>
) : (
@@ -248,7 +255,7 @@ let ProfileHeaderShell = ({
a.px_lg,
a.pt_xs,
a.pb_sm,
IS_IOS ? a.pointer_events_auto : {pointerEvents: 'box-none'},
IS_IOS ? a.pointer_events_auto : a.pointer_events_box_none,
]}
/>
))}
+9 -9
View File
@@ -160,15 +160,8 @@ const MinimalHeader = memo(function MinimalHeader({
return (
<Animated.View
pointerEvents={visible ? 'auto' : 'none'}
aria-hidden={!visible}
accessibilityElementsHidden={!visible}
importantForAccessibility={visible ? 'auto' : 'no-hide-descendants'}
onLayout={evt => {
setMinimalHeaderHeight(evt.nativeEvent.layout.height)
onLayout(evt)
}}
style={[
visible ? a.pointer_events_auto : a.pointer_events_none,
a.absolute,
a.z_50,
t.atoms.bg,
@@ -179,7 +172,14 @@ const MinimalHeader = memo(function MinimalHeader({
paddingTop: insets.top,
},
animatedStyle,
]}>
]}
aria-hidden={!visible}
accessibilityElementsHidden={!visible}
importantForAccessibility={visible ? 'auto' : 'no-hide-descendants'}
onLayout={evt => {
setMinimalHeaderHeight(evt.nativeEvent.layout.height)
onLayout(evt)
}}>
<Header.Outer noBottomBorder>
{hideBackButton ? <Header.MenuButton /> : <Header.BackButton />}
<Header.Content align="left">
@@ -48,14 +48,14 @@ export function CopyButton({
entering={ZoomIn.duration(100)}
exiting={FadeOutUp.duration(2000)}
style={[
a.pointer_events_none,
a.absolute,
{bottom: '100%', right: 0},
a.justify_center,
a.gap_sm,
a.z_10,
a.pb_sm,
]}
pointerEvents="none">
]}>
<Text
style={[
a.font_medium,
@@ -262,11 +262,11 @@ function LandingScreenLoaded({
<View
key={item.subject.did}
style={[
a.pointer_events_none,
a.py_lg,
a.px_md,
(!isTabletOrDesktop || i !== 0) && a.border_t,
t.atoms.border_contrast_low,
{pointerEvents: 'none'},
]}>
<ProfileCard
profile={item.subject}
@@ -285,7 +285,7 @@ function LandingScreenLoaded({
<View
style={[
{pointerEvents: 'none'},
a.pointer_events_none,
isTabletOrDesktop && [
a.border,
a.rounded_md,
@@ -171,6 +171,7 @@ export function Scrubber({
)}
<Animated.View
style={[
a.pointer_events_none,
a.absolute,
{
left: 0,
@@ -178,8 +179,7 @@ export function Scrubber({
bottom: insets.bottom + 80,
},
timeStyle,
]}
pointerEvents="none">
]}>
<Text style={[a.text_center, a.font_semi_bold]}>
<Text style={[a.text_5xl, {fontVariant: ['tabular-nums']}]}>
{formatTime(currentSeekTime)}
+2 -2
View File
@@ -917,13 +917,13 @@ function Overlay({
{IS_ANDROID && status === 'loading' && (
<View
style={[
a.pointer_events_none,
a.absolute,
a.inset_0,
a.align_center,
a.justify_center,
a.z_10,
]}
pointerEvents="none">
]}>
<Loader size="2xl" />
</View>
)}
+1 -1
View File
@@ -1245,7 +1245,7 @@ function ComposerEmbeds({
<View
style={[a.pb_sm, video ? [a.pt_md] : [a.pt_xl], IS_WEB && [a.pb_md]]}>
<View style={[a.relative]}>
<View style={{pointerEvents: 'none'}}>
<View style={a.pointer_events_none}>
<LazyQuoteEmbed uri={embed.quote.uri} />
</View>
{canRemoveQuote && (
+2 -2
View File
@@ -44,7 +44,7 @@ export const ExternalEmbedGif = ({
return (
<View style={[a.overflow_hidden, t.atoms.border_contrast_medium]}>
{linkInfo ? (
<View style={{pointerEvents: 'auto'}}>
<View style={a.pointer_events_auto}>
<ExternalEmbed link={linkInfo} hideAlt />
</View>
) : error ? (
@@ -129,7 +129,7 @@ export const ExternalEmbedLink = ({
return (
<View style={[a.mb_xl, a.overflow_hidden, t.atoms.border_contrast_medium]}>
{linkComponent ? (
<View style={{pointerEvents: 'none'}}>{linkComponent}</View>
<View style={a.pointer_events_none}>{linkComponent}</View>
) : error ? (
<Container style={[a.align_start, a.p_md, a.gap_xs]}>
<Text numberOfLines={1} style={t.atoms.text_contrast_high}>
+8 -4
View File
@@ -23,7 +23,7 @@ import {
type PagerRef,
type RenderTabBarFnProps,
} from '#/view/com/pager/Pager'
import {useTheme} from '#/alf'
import {atoms as a, useTheme} from '#/alf'
import {IS_IOS} from '#/env'
import {type ListMethods} from '../util/List'
import {PagerHeaderProvider} from './PagerHeaderContext'
@@ -273,11 +273,15 @@ let PagerTabBar = ({
const headerRef = useRef(null)
return (
<Animated.View
pointerEvents={IS_IOS ? 'auto' : 'box-none'}
style={[styles.tabBarMobile, headerTransform, t.atoms.bg]}>
style={[
IS_IOS ? a.pointer_events_auto : a.pointer_events_box_none,
styles.tabBarMobile,
headerTransform,
t.atoms.bg,
]}>
<View
ref={headerRef}
pointerEvents={IS_IOS ? 'auto' : 'box-none'}
style={IS_IOS ? a.pointer_events_auto : a.pointer_events_box_none}
collapsable={false}>
{renderHeader?.({setMinimumHeight: setMinimumHeaderHeight})}
{
+3 -18
View File
@@ -69,12 +69,7 @@ export function PostLoadingPlaceholder({
<View style={[styles.postCtrl, {marginLeft: -6}]}>
<View style={styles.postBtn}>
<Bubble
style={[
{
color: t.palette.contrast_500,
},
{pointerEvents: 'none'},
]}
style={[{color: t.palette.contrast_500}, a.pointer_events_none]}
width={18}
/>
</View>
@@ -82,12 +77,7 @@ export function PostLoadingPlaceholder({
<View style={styles.postCtrl}>
<View style={styles.postBtn}>
<Repost
style={[
{
color: t.palette.contrast_500,
},
{pointerEvents: 'none'},
]}
style={[{color: t.palette.contrast_500}, a.pointer_events_none]}
width={18}
/>
</View>
@@ -95,12 +85,7 @@ export function PostLoadingPlaceholder({
<View style={styles.postCtrl}>
<View style={styles.postBtn}>
<HeartIconOutline
style={[
{
color: t.palette.contrast_500,
},
{pointerEvents: 'none'},
]}
style={[{color: t.palette.contrast_500}, a.pointer_events_none]}
width={18}
/>
</View>