Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import {
} from '../utils';
import { getStatesConfig, StateMachineEvent } from './stateDefinitions';
import { PressableStateMachine } from './StateMachine';
import { useIsScreenReaderEnabled } from '../../useIsScreenReaderEnabled';

const DEFAULT_LONG_PRESS_DURATION = 500;
const IS_TEST_ENV = isTestEnv();
Expand Down Expand Up @@ -202,11 +203,16 @@ const LegacyPressable = (props: LegacyPressableProps) => {
);

const stateMachine = useMemo(() => new PressableStateMachine(), []);
const isScreenReaderEnabled = useIsScreenReaderEnabled();

useEffect(() => {
const configuration = getStatesConfig(handlePressIn, handlePressOut);
const configuration = getStatesConfig(
handlePressIn,
handlePressOut,
isScreenReaderEnabled
);
stateMachine.setStates(configuration);
}, [handlePressIn, handlePressOut, stateMachine]);
}, [handlePressIn, handlePressOut, stateMachine, isScreenReaderEnabled]);

const hoverInTimeout = useRef<number | null>(null);
const hoverOutTimeout = useRef<number | null>(null);
Expand Down Expand Up @@ -259,7 +265,7 @@ const LegacyPressable = (props: LegacyPressableProps) => {
);
})
.onTouchesUp(() => {
if (Platform.OS === 'android') {
if (Platform.OS === 'android' && !isScreenReaderEnabled) {
// Prevents potential soft-locks
stateMachine.reset();
handleFinalize();
Expand All @@ -280,7 +286,7 @@ const LegacyPressable = (props: LegacyPressableProps) => {
handleFinalize();
}
}),
[stateMachine, handleFinalize, handlePressOut]
[stateMachine, handleFinalize, handlePressOut, isScreenReaderEnabled]
);

// RNButton is placed inside ButtonGesture to enable Android's ripple and to capture non-propagating events
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,25 @@ function getAndroidStatesConfig(
];
}

function getAndroidAccessibilityStatesConfig(
handlePressIn: (event: PressableEvent) => void,
handlePressOut: (event: PressableEvent) => void
) {
return [
{
eventName: StateMachineEvent.LONG_PRESS_TOUCHES_DOWN,
callback: handlePressIn,
},
{
eventName: StateMachineEvent.NATIVE_BEGIN,
},
{
eventName: StateMachineEvent.FINALIZE,
callback: handlePressOut,
},
];
}

function getIosStatesConfig(
handlePressIn: (event: PressableEvent) => void,
handlePressOut: (event: PressableEvent) => void
Expand Down Expand Up @@ -109,10 +128,13 @@ function getUniversalStatesConfig(

export function getStatesConfig(
handlePressIn: (event: PressableEvent) => void,
handlePressOut: (event: PressableEvent) => void
handlePressOut: (event: PressableEvent) => void,
screenReaderActive: boolean
): StateDefinition[] {
if (Platform.OS === 'android') {
return getAndroidStatesConfig(handlePressIn, handlePressOut);
return screenReaderActive
? getAndroidAccessibilityStatesConfig(handlePressIn, handlePressOut)
: getAndroidStatesConfig(handlePressIn, handlePressOut);
} else if (Platform.OS === 'ios') {
return getIosStatesConfig(handlePressIn, handlePressOut);
} else if (Platform.OS === 'web') {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useEffect, useState } from 'react';
import { AccessibilityInfo } from 'react-native';

export function useIsScreenReaderEnabled() {
const [isEnabled, setIsEnabled] = useState(false);

useEffect(() => {
const checkStatus = async () => {
try {
const res = await AccessibilityInfo.isScreenReaderEnabled();
setIsEnabled(res);
} catch (error) {
console.warn('Could not read accessibility info: defaulting to false');
}
};

checkStatus();

const listener = AccessibilityInfo.addEventListener(
'screenReaderChanged',
(enabled) => {
setIsEnabled(enabled);
}
);

return () => {
listener.remove();
};
}, []);
return isEnabled;
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { PureNativeButton } from './GestureButtons';

import { PressabilityDebugView } from '../../handlers/PressabilityDebugView';
import { INT32_MAX, isTestEnv } from '../../utils';
import { useIsScreenReaderEnabled } from '../../useIsScreenReaderEnabled';

const DEFAULT_LONG_PRESS_DURATION = 500;
const IS_TEST_ENV = isTestEnv();
Expand Down Expand Up @@ -199,11 +200,16 @@ const Pressable = (props: PressableProps) => {
);

const stateMachine = useMemo(() => new PressableStateMachine(), []);
const isScreenReaderEnabled = useIsScreenReaderEnabled();

useEffect(() => {
const configuration = getStatesConfig(handlePressIn, handlePressOut);
const configuration = getStatesConfig(
handlePressIn,
handlePressOut,
isScreenReaderEnabled
);
stateMachine.setStates(configuration);
}, [handlePressIn, handlePressOut, stateMachine]);
}, [handlePressIn, handlePressOut, stateMachine, isScreenReaderEnabled]);

const hoverInTimeout = useRef<number | null>(null);
const hoverOutTimeout = useRef<number | null>(null);
Expand Down Expand Up @@ -257,7 +263,7 @@ const Pressable = (props: PressableProps) => {
);
},
onTouchesUp: () => {
if (Platform.OS === 'android') {
if (Platform.OS === 'android' && !isScreenReaderEnabled) {
// Prevents potential soft-locks
stateMachine.reset();
handleFinalize();
Expand Down
Loading