Skip to content
Closed
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 @@ -88,6 +88,8 @@ public BaseViewManager(@Nullable ReactApplicationContext reactContext) {
view.setTag(R.id.accessibility_actions, null);
view.setTag(R.id.accessibility_value, null);
view.setTag(R.id.accessibility_state_expanded, null);
view.setTag(R.id.accessibility_state_disabled, null);
view.setEnabled(true);
view.setTag(R.id.view_clipped, null);

// This indirectly calls (and resets):
Expand Down Expand Up @@ -364,6 +366,7 @@ public void setAccessibilityCollectionItem(
@ReactProp(name = ViewProps.ACCESSIBILITY_STATE)
public void setViewState(@NonNull T view, @Nullable ReadableMap accessibilityState) {
if (accessibilityState == null) {
resetDisabledFromAccessibilityState(view);
return;
}
if (accessibilityState.hasKey("expanded")) {
Expand All @@ -385,8 +388,12 @@ public void setViewState(@NonNull T view, @Nullable ReadableMap accessibilitySta
view.setSelected(false);
}
view.setTag(R.id.accessibility_state, accessibilityState);
if (accessibilityState.hasKey("disabled")) {
view.setEnabled(!accessibilityState.getBoolean("disabled"));
if (accessibilityState.hasKey("disabled") && !accessibilityState.isNull("disabled")) {
boolean disabled = accessibilityState.getBoolean("disabled");
view.setEnabled(!disabled);
view.setTag(R.id.accessibility_state_disabled, disabled);
} else {
resetDisabledFromAccessibilityState(view);
}

// For states which don't have corresponding methods in
Expand All @@ -413,6 +420,13 @@ public void setViewState(@NonNull T view, @Nullable ReadableMap accessibilitySta
}
}

private static void resetDisabledFromAccessibilityState(@NonNull View view) {
if (Boolean.TRUE.equals(view.getTag(R.id.accessibility_state_disabled))) {
view.setEnabled(true);
}
view.setTag(R.id.accessibility_state_disabled, null);
}

private void updateViewContentDescription(@NonNull T view) {
final String accessibilityLabel = (String) view.getTag(R.id.accessibility_label);
final ReadableMap accessibilityState = (ReadableMap) view.getTag(R.id.accessibility_state);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
<!--tag is used to store accessibilityStateExpanded -->
<item type="id" name="accessibility_state_expanded"/>

<!--tag is used to store whether accessibilityState.disabled disabled the view -->
<item type="id" name="accessibility_state_disabled"/>

<!--tag is used to store accessibilityLabel tag-->
<item type="id" name="accessibility_label"/>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,38 @@ class BaseViewManagerTest {
Assertions.assertThat(view.isSelected).isEqualTo(true)
}

@Test
fun testAccessibilityStateDisabledRemovedReenablesView() {
viewManager.setViewState(view, JavaOnlyMap.of("disabled", true))
Assertions.assertThat(view.isEnabled).isFalse()

viewManager.setViewState(view, JavaOnlyMap())
Assertions.assertThat(view.isEnabled).isTrue()
}

@Test
fun testAccessibilityStateNullReenablesView() {
viewManager.setViewState(view, JavaOnlyMap.of("disabled", true))
viewManager.setViewState(view, null)
Assertions.assertThat(view.isEnabled).isTrue()
}

@Test
fun testAccessibilityStateDisabledNullDoesNotCrash() {
viewManager.setViewState(view, JavaOnlyMap.of("disabled", true))
viewManager.setViewState(view, JavaOnlyMap.of("disabled", null))
Assertions.assertThat(view.isEnabled).isTrue()
}

@Test
fun testAccessibilityStateWithoutDisabledKeepsViewDisabledByOtherProps() {
view.isEnabled = false
viewManager.setViewState(view, JavaOnlyMap())
Assertions.assertThat(view.isEnabled).isFalse()
viewManager.setViewState(view, null)
Assertions.assertThat(view.isEnabled).isFalse()
}

@Test
fun testRoleList() {
viewManager.setRole(view, "list")
Expand Down
53 changes: 53 additions & 0 deletions packages/rn-tester/js/examples/Pressable/PressableExample.js
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,17 @@ function PressableNativeMethods() {
);
}

const DISABLED_OPTIONS: Array<{label: string, value: ?boolean}> = [
{label: 'true', value: true},
{label: 'false', value: false},
{label: 'undefined', value: undefined},
{label: 'null', value: null},
];

function PressableDisabled() {
const [disabled, setDisabled] = useState<?boolean>(true);
const [timesPressed, setTimesPressed] = useState(0);

return (
<>
<Pressable disabled={true} style={[styles.row, styles.block]}>
Expand All @@ -271,6 +281,33 @@ function PressableDisabled() {
]}>
<Text style={styles.button}>Enabled Pressable</Text>
</Pressable>

<View style={[styles.row, styles.block]}>
{DISABLED_OPTIONS.map(option => (
<Pressable
key={option.label}
onPress={() => setDisabled(option.value)}
style={[
styles.disabledOption,
disabled === option.value && styles.disabledOptionSelected,
]}>
<Text>{option.label}</Text>
</Pressable>
))}
</View>
<Pressable
disabled={disabled}
onPress={() => setTimesPressed(current => current + 1)}
style={({pressed}) => [
{opacity: pressed ? 0.5 : 1},
styles.row,
styles.block,
styles.disabledToggleTarget,
]}>
<Text style={disabled === true ? styles.disabledButton : styles.button}>
{`disabled={${String(disabled)}}`} pressed {timesPressed} times
</Text>
</Pressable>
</>
);
}
Expand All @@ -296,6 +333,22 @@ const styles = StyleSheet.create({
color: '#007AFF',
opacity: 0.5,
},
disabledOption: {
paddingHorizontal: 8,
paddingVertical: 4,
marginHorizontal: 4,
borderRadius: 4,
borderWidth: StyleSheet.hairlineWidth,
borderColor: '#007AFF',
},
disabledOptionSelected: {
backgroundColor: '#cce4ff',
},
disabledToggleTarget: {
padding: 20,
borderWidth: StyleSheet.hairlineWidth,
borderColor: '#007AFF',
},
hitSlopButton: {
color: 'white',
},
Expand Down
Loading