Skip to content

Commit 58282d4

Browse files
authored
[0.81] Focus fixes (#15872)
* 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 * Only show focus visuals when using keyboard to move focus (#15864) * Only show focus visuals when using keyboard to move focus * Change files * fix change files * lint fix
1 parent 5ee4808 commit 58282d4

20 files changed

Lines changed: 558 additions & 47 deletions
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "patch",
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: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"type": "none",
2+
"type": "patch",
33
"comment": "Implement button property",
44
"packageName": "react-native-windows",
55
"email": "hmalothu@microsoft.com",
66
"dependentChangeType": "none"
7-
}
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"type": "patch",
3+
"comment": "Only show focus visuals when using keyboard to move focus",
4+
"packageName": "react-native-windows",
5+
"email": "30809111+acoates-ms@users.noreply.github.com",
6+
"dependentChangeType": "patch"
7+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
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 of
19+
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. Clicking
56+
outside the bounds, where the pressable extends but is clipped by its
57+
parent overflow:hidden, should not trigger the pressable.
58+
</Text>
59+
<View
60+
accessible={true}
61+
accessibilityValue={{text: bgColor}}
62+
style={{width: 150, height: 150}}
63+
testID="hidden-overflow-element">
64+
<View
65+
style={{
66+
width: 50,
67+
height: 50,
68+
backgroundColor: 'yellow',
69+
overflow: 'hidden',
70+
}}>
71+
<Pressable
72+
style={{
73+
width: 100,
74+
height: 100,
75+
backgroundColor: bgColor,
76+
}}
77+
onPress={() => {
78+
setBgColor(bgColor === 'red' ? 'green' : 'red');
79+
}}>
80+
<Text>Press me</Text>
81+
</Pressable>
82+
</View>
83+
</View>
84+
</View>
85+
);
86+
}
87+
88+
exports.displayName = 'HitTestExample';
89+
exports.title = 'Hit Testing';
90+
exports.category = 'Basic';
91+
exports.description = 'Test that overflow hidden affect hit testing';
92+
exports.examples = [
93+
{
94+
title: 'overflow visible affects hit testing\n',
95+
render: function () {
96+
return <HitTestWithOverflowVisibile />;
97+
},
98+
},
99+
{
100+
title: 'overflow hidden affects hit testing\n',
101+
render: function () {
102+
return <HitTestWithOverflowHidden />;
103+
},
104+
},
105+
];

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
@@ -213,6 +213,11 @@ const Components: Array<RNTesterModuleInfo> = [
213213
key: 'LegacyTextHitTestTest',
214214
module: require('../examples-win/LegacyTests/TextHitTestPage'),
215215
},
216+
{
217+
key: 'HitTestExample',
218+
category: 'UI',
219+
module: require('../examples-win/HitTest/HitTestExample'),
220+
},
216221
{
217222
key: 'PerformanceComparisonExample',
218223
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)