Skip to content

Commit 99751ee

Browse files
committed
rename inlineTextPress to nestedPress
1 parent 6551848 commit 99751ee

6 files changed

Lines changed: 78 additions & 91 deletions

File tree

app/containers/markdown/components/inline/Link.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import { LISTENER } from '../../../Toast';
99
import { useTheme } from '../../../../theme';
1010
import openLink from '../../../../lib/methods/helpers/openLink';
1111
import EventEmitter from '../../../../lib/methods/helpers/events';
12-
import { claimInlineTextPress, releaseInlineTextPress } from '../../../../lib/methods/helpers/inlineTextPressClaim';
12+
import { beginNestedPress, endNestedPress } from '../../../../lib/methods/helpers/nestedPress';
1313
import { themes } from '../../../../lib/constants/colors';
1414
import MarkdownContext from '../../contexts/MarkdownContext';
1515
import styles from '../../styles';
@@ -53,8 +53,8 @@ const Link = ({ value }: ILinkProps) => {
5353
style={[styles.link, ...(textStyle ? [textStyle] : []), { color: themes[theme].fontInfo }]}
5454
onPress={handlePress}
5555
onLongPress={onLongPress}
56-
onPressIn={claimInlineTextPress}
57-
onPressOut={releaseInlineTextPress}>
56+
onPressIn={beginNestedPress}
57+
onPressOut={endNestedPress}>
5858
{(block => {
5959
const blockArray = Array.isArray(block) ? block : [block];
6060
return blockArray.map(blockInArray => {

app/containers/message/components/Touchable/MessageTouchable.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { A11y } from 'react-native-a11y-order';
22

33
import { useTheme } from '../../../../theme';
4-
import { hasInlineTextPressClaim } from '../../../../lib/methods/helpers/inlineTextPressClaim';
4+
import { isNestedPressActive } from '../../../../lib/methods/helpers/nestedPress';
55
import Touch from '../../../Touch';
66
import Message, { type TMessageProps } from '../Message/Message';
77
import { useLastFocusedMessageRef } from '../../../../lib/a11y/useLastFocusedMessageRef';
@@ -49,10 +49,11 @@ const MessageTouchable = (props: TMessageProps) => {
4949
}
5050

5151
const handleLongPress = () => {
52-
// An inline markdown link already handled this long press. On Android the row is a gesture-handler
53-
// Pressable and the link is a plain <Text onLongPress>, and the two gesture systems cannot arbitrate,
54-
// so without this both fire and the action sheet lands on top of the "copied to clipboard" toast.
55-
if (hasInlineTextPressClaim()) {
52+
// A nested press target — an inline markdown link — already handled this long press. On Android the
53+
// row is a gesture-handler Pressable and the link is a plain <Text onLongPress>, and the two gesture
54+
// systems cannot arbitrate, so without this both fire and the action sheet lands on top of the
55+
// "copied to clipboard" toast.
56+
if (isNestedPressActive()) {
5657
return;
5758
}
5859
markAsLastFocused();

app/lib/methods/helpers/inlineTextPressClaim.test.ts

Lines changed: 0 additions & 51 deletions
This file was deleted.

app/lib/methods/helpers/inlineTextPressClaim.ts

Lines changed: 0 additions & 32 deletions
This file was deleted.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { beginNestedPress, endNestedPress, isNestedPressActive } from './nestedPress';
2+
3+
describe('nestedPress', () => {
4+
beforeEach(() => {
5+
jest.useFakeTimers();
6+
endNestedPress();
7+
});
8+
9+
afterEach(() => {
10+
jest.useRealTimers();
11+
});
12+
13+
it('reports no active press before any press', () => {
14+
expect(isNestedPressActive()).toBe(false);
15+
});
16+
17+
it('reports an active press while a nested target owns the touch', () => {
18+
beginNestedPress();
19+
20+
expect(isNestedPressActive()).toBe(true);
21+
});
22+
23+
it('stays active past the long press delay so the row can still be suppressed', () => {
24+
beginNestedPress();
25+
jest.advanceTimersByTime(500);
26+
27+
expect(isNestedPressActive()).toBe(true);
28+
});
29+
30+
it('goes inactive once the press ends', () => {
31+
beginNestedPress();
32+
endNestedPress();
33+
34+
expect(isNestedPressActive()).toBe(false);
35+
});
36+
37+
it('expires a press that never ended, so a missed release cannot wedge long press', () => {
38+
beginNestedPress();
39+
jest.advanceTimersByTime(1000);
40+
41+
expect(isNestedPressActive()).toBe(false);
42+
});
43+
44+
it('restarts cleanly on a subsequent press', () => {
45+
beginNestedPress();
46+
jest.advanceTimersByTime(1000);
47+
beginNestedPress();
48+
49+
expect(isNestedPressActive()).toBe(true);
50+
});
51+
});
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Lets a nested press target tell an ancestor it owns the current touch: on Android the message row is a
2+
// gesture-handler Pressable while inline markdown links are plain <Text onLongPress>, and the two gesture
3+
// systems cannot arbitrate, so without this a long press on a link fires both handlers.
4+
5+
// Bounds the damage if an end is ever missed, e.g. the text unmounts mid-press.
6+
const MAX_PRESS_DURATION = 1000;
7+
8+
let startedAt: number | null = null;
9+
10+
export const beginNestedPress = () => {
11+
startedAt = Date.now();
12+
};
13+
14+
export const endNestedPress = () => {
15+
startedAt = null;
16+
};
17+
18+
export const isNestedPressActive = () => startedAt !== null && Date.now() - startedAt < MAX_PRESS_DURATION;

0 commit comments

Comments
 (0)