Refine hitslop

This commit is contained in:
Eric Bailey
2025-09-04 15:35:59 -05:00
parent c23bdac0dc
commit 0138e8368a
6 changed files with 47 additions and 12 deletions
@@ -1,4 +1,5 @@
import {memo} from 'react'
import {type Insets} from 'react-native'
import {type AppBskyFeedDefs} from '@atproto/api'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
@@ -18,10 +19,12 @@ export const BookmarkButton = memo(function BookmarkButton({
post,
big,
logContext,
hitSlop,
}: {
post: Shadow<AppBskyFeedDefs.PostView>
big?: boolean
logContext: 'FeedItem' | 'PostThreadItem' | 'Post' | 'ImmersiveVideo'
hitSlop?: Insets
}): React.ReactNode {
const t = useTheme()
const {_} = useLingui()
@@ -122,7 +125,8 @@ export const BookmarkButton = memo(function BookmarkButton({
? _(msg`Remove from saved posts`)
: _(msg`Add to saved posts`)
}
onPress={onHandlePress}>
onPress={onHandlePress}
hitSlop={hitSlop}>
<PostControlButtonIcon
fill={isBookmarked ? t.palette.primary_500 : undefined}
icon={isBookmarked ? BookmarkFilled : Bookmark}
@@ -1,13 +1,14 @@
import {createContext, useContext, useMemo} from 'react'
import {type GestureResponderEvent, type View} from 'react-native'
import {type GestureResponderEvent, type Insets, type View} from 'react-native'
import {POST_CTRL_HITSLOP} from '#/lib/constants'
import {useHaptics} from '#/lib/haptics'
import {atoms as a, useTheme} from '#/alf'
import {Button, type ButtonProps} from '#/components/Button'
import {type Props as SVGIconProps} from '#/components/icons/common'
import {Text, type TextProps} from '#/components/Typography'
export const DEFAULT_HITSLOP = {top: 5, bottom: 10, left: 10, right: 10}
const PostControlContext = createContext<{
big?: boolean
active?: boolean
@@ -25,12 +26,13 @@ export function PostControlButton({
active,
activeColor,
...props
}: ButtonProps & {
}: Omit<ButtonProps, 'hitSlop'> & {
ref?: React.Ref<View>
active?: boolean
big?: boolean
color?: string
activeColor?: string
hitSlop?: Insets
}) {
const t = useTheme()
const playHaptic = useHaptics()
@@ -83,8 +85,11 @@ export function PostControlButton({
shape="round"
variant="ghost"
color="secondary"
hitSlop={POST_CTRL_HITSLOP}
{...props}>
{...props}
hitSlop={{
...DEFAULT_HITSLOP,
...(props.hitSlop || {}),
}}>
{typeof children === 'function' ? (
args => (
<PostControlContext.Provider value={ctx}>
@@ -1,4 +1,5 @@
import {memo, useMemo, useState} from 'react'
import {type Insets} from 'react-native'
import {
type AppBskyFeedDefs,
type AppBskyFeedPost,
@@ -28,6 +29,7 @@ let PostMenuButton = ({
timestamp,
threadgateRecord,
onShowLess,
hitSlop,
}: {
testID: string
post: Shadow<AppBskyFeedDefs.PostView>
@@ -39,6 +41,7 @@ let PostMenuButton = ({
timestamp: string
threadgateRecord?: AppBskyFeedThreadgate.Record
onShowLess?: (interaction: AppBskyFeedDefs.Interaction) => void
hitSlop?: Insets
}): React.ReactNode => {
const {_} = useLingui()
@@ -66,7 +69,8 @@ let PostMenuButton = ({
testID="postDropdownBtn"
big={big}
label={props.accessibilityLabel}
{...props}>
{...props}
hitSlop={hitSlop}>
<PostControlButtonIcon icon={DotsHorizontal} />
</PostControlButton>
)
@@ -1,4 +1,5 @@
import {memo, useMemo, useState} from 'react'
import {type Insets} from 'react-native'
import {
type AppBskyFeedDefs,
type AppBskyFeedPost,
@@ -34,6 +35,7 @@ let ShareMenuButton = ({
timestamp,
threadgateRecord,
onShare,
hitSlop,
}: {
testID: string
post: Shadow<AppBskyFeedDefs.PostView>
@@ -43,6 +45,7 @@ let ShareMenuButton = ({
timestamp: string
threadgateRecord?: AppBskyFeedThreadgate.Record
onShare: () => void
hitSlop?: Insets
}): React.ReactNode => {
const {_} = useLingui()
const gate = useGate()
@@ -92,7 +95,8 @@ let ShareMenuButton = ({
big={big}
label={props.accessibilityLabel}
{...props}
onLongPress={native(onNativeLongPress)}>
onLongPress={native(onNativeLongPress)}
hitSlop={hitSlop}>
<PostControlButtonIcon icon={ShareIcon} />
</PostControlButton>
)
+22 -3
View File
@@ -25,7 +25,7 @@ import {
useProgressGuideControls,
} from '#/state/shell/progress-guide'
import * as Toast from '#/view/com/util/Toast'
import {atoms as a, useBreakpoints} from '#/alf'
import {atoms as a, flatten, useBreakpoints} from '#/alf'
import {Reply as Bubble} from '#/components/icons/Reply'
import {formatPostStatCount} from '#/components/PostControls/util'
import {BookmarkButton} from './BookmarkButton'
@@ -187,6 +187,11 @@ let PostControls = ({
})
}
const secondaryControlSpacingStyles = flatten([
a.gap_xs,
(big || gtPhone) && a.gap_sm,
])
return (
<View
style={[
@@ -289,8 +294,15 @@ let PostControls = ({
{/* Spacer! */}
<View />
</View>
<View style={[a.flex_row, a.justify_end, (big || gtPhone) && a.gap_sm]}>
<BookmarkButton post={post} big={big} logContext={logContext} />
<View style={[a.flex_row, a.justify_end, secondaryControlSpacingStyles]}>
<BookmarkButton
post={post}
big={big}
logContext={logContext}
hitSlop={{
right: secondaryControlSpacingStyles.gap / 2,
}}
/>
<ShareMenuButton
testID="postShareBtn"
post={post}
@@ -300,6 +312,10 @@ let PostControls = ({
timestamp={post.indexedAt}
threadgateRecord={threadgateRecord}
onShare={onShare}
hitSlop={{
left: secondaryControlSpacingStyles.gap / 2,
right: secondaryControlSpacingStyles.gap / 2,
}}
/>
<PostMenuButton
testID="postDropdownBtn"
@@ -312,6 +328,9 @@ let PostControls = ({
timestamp={post.indexedAt}
threadgateRecord={threadgateRecord}
onShowLess={onShowLess}
hitSlop={{
left: secondaryControlSpacingStyles.gap / 2,
}}
/>
</View>
</View>
-1
View File
@@ -124,7 +124,6 @@ export const createHitslop = (size: number): Insets => ({
export const HITSLOP_10 = createHitslop(10)
export const HITSLOP_20 = createHitslop(20)
export const HITSLOP_30 = createHitslop(30)
export const POST_CTRL_HITSLOP = {top: 5, bottom: 10, left: 10, right: 10}
export const LANG_DROPDOWN_HITSLOP = {top: 10, bottom: 10, left: 4, right: 4}
export const BACK_HITSLOP = HITSLOP_30
export const MAX_POST_LINES = 25