[fix] Disabled pressables should propagate 'click' events

If a pressable is disabled it should not prevent the propagation of native
'click' events, unless the underlying DOM node has an 'aria-role' of 'button'.
This emulates the native '<button>' behavior.

Fix #1781
This commit is contained in:
Nicolas Gallagher
2020-10-29 14:13:42 -07:00
parent b8fddcf6b1
commit 03897d32be
@@ -119,6 +119,8 @@ const Transitions = Object.freeze({
const isActiveSignal = signal => const isActiveSignal = signal =>
signal === RESPONDER_ACTIVE_PRESS_START || signal === RESPONDER_ACTIVE_LONG_PRESS_START; signal === RESPONDER_ACTIVE_PRESS_START || signal === RESPONDER_ACTIVE_LONG_PRESS_START;
const isButtonRole = element => element.getAttribute('role') === 'button';
const isPressStartSignal = signal => const isPressStartSignal = signal =>
signal === RESPONDER_INACTIVE_PRESS_START || signal === RESPONDER_INACTIVE_PRESS_START ||
signal === RESPONDER_ACTIVE_PRESS_START || signal === RESPONDER_ACTIVE_PRESS_START ||
@@ -306,8 +308,11 @@ export default class PressResponder {
}; };
return { return {
onStartShouldSetResponder: (): boolean => { onStartShouldSetResponder: (event): boolean => {
const { disabled } = this._config; const { disabled } = this._config;
if (disabled && isButtonRole(event.currentTarget)) {
event.stopPropagation();
}
if (disabled == null) { if (disabled == null) {
return true; return true;
} }
@@ -383,23 +388,33 @@ export default class PressResponder {
// If long press dispatched, cancel default click behavior. // If long press dispatched, cancel default click behavior.
// If the responder terminated because text was selected during the gesture, // If the responder terminated because text was selected during the gesture,
// cancel the default click behavior. // cancel the default click behavior.
event.stopPropagation();
if (this._longPressDispatched || this._selectionTerminated) { if (this._longPressDispatched || this._selectionTerminated) {
event.preventDefault(); event.preventDefault();
} else if (onPress != null && event.ctrlKey === false && event.altKey === false) { } else if (onPress != null && event.ctrlKey === false && event.altKey === false) {
onPress(event); onPress(event);
} }
} else {
if (isButtonRole(event.currentTarget)) {
event.stopPropagation();
}
} }
event.stopPropagation();
}, },
// If `onLongPress` is provided and a touch pointer is being used, prevent the // If `onLongPress` is provided and a touch pointer is being used, prevent the
// default context menu from opening. // default context menu from opening.
onContextMenu: (event: any): void => { onContextMenu: (event: any): void => {
const { disabled, onLongPress } = this._config; const { disabled, onLongPress } = this._config;
if (!disabled && onLongPress != null && this._isPointerTouch && !event.defaultPrevented) { if (!disabled) {
event.preventDefault(); if (onLongPress != null && this._isPointerTouch && !event.defaultPrevented) {
event.preventDefault();
event.stopPropagation();
}
} else {
if (isButtonRole(event.currentTarget)) {
event.stopPropagation();
}
} }
event.stopPropagation();
} }
}; };
} }