Skip to content

Commit b8003b8

Browse files
authored
overflow: hidden should prevent hittesting (#15845)
* overflow: hidden should prevent hittesting * Change files * Add tests * snapshots + lint * overflow: hidden should prevent hittesting * Change files * Add tests * snapshots + lint * lint fix
1 parent 7696d3d commit b8003b8

7 files changed

Lines changed: 456 additions & 20 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "prerelease",
3+
"comment": "overflow: hidden should prevent hittesting",
4+
"packageName": "react-native-windows",
5+
"email": "30809111+acoates-ms@users.noreply.github.com",
6+
"dependentChangeType": "patch"
7+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/**
2+
* Copyright (c) Microsoft Corporation.
3+
* Licensed under the MIT License.
4+
* @format
5+
*/
6+
7+
'use strict';
8+
9+
import React from 'react';
10+
import { View, Text, Pressable } from 'react-native';
11+
12+
function HitTestWithOverflowVisibile() {
13+
const [bgColor, setBgColor] = React.useState('red');
14+
15+
return (
16+
<View>
17+
<Text>
18+
Clicking the pressable should work even if it is outside the bounds
19+
of its parent.
20+
</Text>
21+
<View
22+
accessible={true}
23+
accessibilityValue={{ text: bgColor }}
24+
style={{ width: 150, height: 150 }}
25+
testID="visible-overflow-element">
26+
<View
27+
style={{
28+
width: 50,
29+
height: 50,
30+
backgroundColor: 'yellow',
31+
overflow: 'visible',
32+
}}>
33+
<Pressable
34+
style={{
35+
width: 100,
36+
height: 100,
37+
backgroundColor: bgColor,
38+
}}
39+
onPress={() => {
40+
setBgColor(bgColor === 'red' ? 'green' : 'red');
41+
}}>
42+
<Text>Press me</Text>
43+
</Pressable>
44+
</View>
45+
</View>
46+
</View>
47+
);
48+
}
49+
50+
function HitTestWithOverflowHidden() {
51+
const [bgColor, setBgColor] = React.useState('red');
52+
return (
53+
<View>
54+
<Text>
55+
Clicking within the visible view will trigger the pressable.
56+
Clicking outside the bounds, where the pressable extends but is
57+
clipped by its parent overflow:hidden, should not trigger the
58+
pressable.
59+
</Text>
60+
<View
61+
accessible={true}
62+
accessibilityValue={{ text: bgColor }}
63+
style={{ width: 150, height: 150 }}
64+
testID="hidden-overflow-element">
65+
<View
66+
style={{
67+
width: 50,
68+
height: 50,
69+
backgroundColor: 'yellow',
70+
overflow: 'hidden',
71+
}}>
72+
<Pressable
73+
style={{
74+
width: 100,
75+
height: 100,
76+
backgroundColor: bgColor,
77+
}}
78+
onPress={() => {
79+
setBgColor(bgColor === 'red' ? 'green' : 'red');
80+
}}>
81+
<Text>Press me</Text>
82+
</Pressable>
83+
</View>
84+
</View>
85+
</View>
86+
);
87+
}
88+
89+
exports.displayName = 'HitTestExample';
90+
exports.title = 'Hit Testing';
91+
exports.category = 'Basic';
92+
exports.description = 'Test that overflow hidden affect hit testing';
93+
exports.examples = [
94+
{
95+
title: 'overflow visible affects hit testing\n',
96+
render: function () {
97+
return <HitTestWithOverflowVisibile />;
98+
},
99+
},
100+
{
101+
title: 'overflow hidden affects hit testing\n',
102+
render: function () {
103+
return <HitTestWithOverflowHidden />;
104+
},
105+
},
106+
];

packages/@react-native-windows/tester/src/js/utils/RNTesterList.windows.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,11 @@ const Components: Array<RNTesterModuleInfo> = [
212212
key: 'LegacyTextHitTestTest',
213213
module: require('../examples-win/LegacyTests/TextHitTestPage'),
214214
},
215+
{
216+
key: 'HitTestExample',
217+
category: 'UI',
218+
module: require('../examples-win/HitTest/HitTestExample'),
219+
},
215220
{
216221
key: 'PerformanceComparisonExample',
217222
category: 'Basic',
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/**
2+
* Copyright (c) Microsoft Corporation.
3+
* Licensed under the MIT License.
4+
*
5+
* @format
6+
*/
7+
8+
import {app} from '@react-native-windows/automation';
9+
import {dumpVisualTree} from '@react-native-windows/automation-commands';
10+
import {goToComponentExample} from './RNTesterNavigation';
11+
import {verifyNoErrorLogs} from './Helpers';
12+
13+
beforeAll(async () => {
14+
// If window is partially offscreen, tests will fail to click on certain elements
15+
await app.setWindowPosition(0, 0);
16+
await app.setWindowSize(1000, 1250);
17+
await goToComponentExample('Hit Testing');
18+
});
19+
20+
afterEach(async () => {
21+
await verifyNoErrorLogs();
22+
});
23+
24+
async function verifyElementAccessibiltyValue(element: string, value: string) {
25+
const dump = await dumpVisualTree(element);
26+
expect(dump!['Automation Tree']['ValuePattern.Value']).toBe(value);
27+
}
28+
29+
describe('Hit Testing', () => {
30+
test('Hit testing child outside the bounds of parents', async () => {
31+
const target = await app.findElementByTestID('visible-overflow-element');
32+
33+
// View starts in red state
34+
await verifyElementAccessibiltyValue('visible-overflow-element', 'red');
35+
36+
// The webdriverio package computes the offsets from the center point of the target.
37+
// This is within the bounds of the child and the parent, so should hitTest even with overflow:visible
38+
await target.click({x: -50, y: -50});
39+
40+
await verifyElementAccessibiltyValue('visible-overflow-element', 'green');
41+
42+
// The webdriverio package computes the offsets from the center point of the target.
43+
// This is within the bounds of the child, but outside the parents bounds
44+
await target.click({x: 0, y: 0});
45+
46+
// View should still be red, since the click should hit the pressable
47+
await verifyElementAccessibiltyValue('visible-overflow-element', 'red');
48+
});
49+
50+
test('Overflow hidden prevents hittesting child', async () => {
51+
const target = await app.findElementByTestID('hidden-overflow-element');
52+
53+
// View starts in red state
54+
await verifyElementAccessibiltyValue('hidden-overflow-element', 'red');
55+
56+
// This is within the bounds of the child and the parent, so should hitTest even with overflow:hidden
57+
await target.click({x: -50, y: -50});
58+
59+
await verifyElementAccessibiltyValue('hidden-overflow-element', 'green');
60+
61+
// This is within the bounds of the child, but shouldn't hit test, since the parent is overflow:hidden
62+
await target.click({x: 0, y: 0});
63+
64+
// View should still be green, since the click shouldn't hit the pressable
65+
await verifyElementAccessibiltyValue('hidden-overflow-element', 'green');
66+
});
67+
});

0 commit comments

Comments
 (0)