@@ -1280,6 +1280,264 @@ describe('FocusScope', function () {
12801280 } ) ;
12811281 } ) ;
12821282
1283+ it ( 'skips radio buttons that are in the same group and are not the selectable one forwards' , async function ( ) {
1284+ function Test ( ) {
1285+ return (
1286+ < FocusScope contain >
1287+ < button data-testid = "button1" > button</ button >
1288+ < form >
1289+ < fieldset >
1290+ < legend > Select a maintenance drone:</ legend >
1291+
1292+ < div >
1293+ < input type = "radio" id = "huey" name = "drone" value = "huey" defaultChecked />
1294+ < label htmlFor = "huey" > Huey</ label >
1295+ </ div >
1296+
1297+ < div >
1298+ < input type = "radio" id = "dewey" name = "drone" value = "dewey" />
1299+ < label htmlFor = "dewey" > Dewey</ label >
1300+ </ div >
1301+ < button data-testid = "button2" > button</ button >
1302+ < div >
1303+ < input type = "radio" id = "louie" name = "drone" value = "louie" />
1304+ < label htmlFor = "louie" > Louie</ label >
1305+ </ div >
1306+ </ fieldset >
1307+ < fieldset >
1308+ < legend > Select a ship:</ legend >
1309+
1310+ < div >
1311+ < input type = "radio" id = "larry" name = "ship" value = "larry" />
1312+ < label htmlFor = "larry" > Larry</ label >
1313+ </ div >
1314+
1315+ < div >
1316+ < input type = "radio" id = "moe" name = "ship" value = "moe" />
1317+ < label htmlFor = "moe" > Moe</ label >
1318+ </ div >
1319+ < button data-testid = "button3" > button</ button >
1320+ < div >
1321+ < input type = "radio" id = "curly" name = "ship" value = "curly" />
1322+ < label htmlFor = "curly" > Curly</ label >
1323+ </ div >
1324+ </ fieldset >
1325+ </ form >
1326+ < button data-testid = "button4" > button</ button >
1327+ </ FocusScope >
1328+ ) ;
1329+ }
1330+
1331+ let { getByTestId, getAllByRole} = render ( < Test /> ) ;
1332+ let radios = getAllByRole ( 'radio' ) ;
1333+ await user . tab ( ) ;
1334+ expect ( document . activeElement ) . toBe ( getByTestId ( 'button1' ) ) ;
1335+ await user . tab ( ) ;
1336+ expect ( document . activeElement ) . toBe ( radios [ 0 ] ) ;
1337+ await user . tab ( ) ;
1338+ expect ( document . activeElement ) . toBe ( getByTestId ( 'button2' ) ) ;
1339+ await user . tab ( ) ;
1340+ expect ( document . activeElement ) . toBe ( radios [ 3 ] ) ;
1341+ await user . tab ( ) ;
1342+ expect ( document . activeElement ) . toBe ( getByTestId ( 'button3' ) ) ;
1343+ await user . tab ( ) ;
1344+ expect ( document . activeElement ) . toBe ( radios [ 5 ] ) ;
1345+ await user . tab ( ) ;
1346+ expect ( document . activeElement ) . toBe ( getByTestId ( 'button4' ) ) ;
1347+ } ) ;
1348+
1349+ it ( 'skips radio buttons that are in the same group and are not the selectable one forwards outside of a form' , async function ( ) {
1350+ function Test ( ) {
1351+ return (
1352+ < FocusScope contain >
1353+ < button data-testid = "button1" > button</ button >
1354+ < fieldset >
1355+ < legend > Select a maintenance drone:</ legend >
1356+
1357+ < div >
1358+ < input type = "radio" id = "huey" name = "drone" value = "huey" defaultChecked />
1359+ < label htmlFor = "huey" > Huey</ label >
1360+ </ div >
1361+
1362+ < div >
1363+ < input type = "radio" id = "dewey" name = "drone" value = "dewey" />
1364+ < label htmlFor = "dewey" > Dewey</ label >
1365+ </ div >
1366+ < button data-testid = "button2" > button</ button >
1367+ < div >
1368+ < input type = "radio" id = "louie" name = "drone" value = "louie" />
1369+ < label htmlFor = "louie" > Louie</ label >
1370+ </ div >
1371+ </ fieldset >
1372+ < fieldset >
1373+ < legend > Select a ship:</ legend >
1374+
1375+ < div >
1376+ < input type = "radio" id = "larry" name = "ship" value = "larry" />
1377+ < label htmlFor = "larry" > Larry</ label >
1378+ </ div >
1379+
1380+ < div >
1381+ < input type = "radio" id = "moe" name = "ship" value = "moe" />
1382+ < label htmlFor = "moe" > Moe</ label >
1383+ </ div >
1384+ < button data-testid = "button3" > button</ button >
1385+ < div >
1386+ < input type = "radio" id = "curly" name = "ship" value = "curly" />
1387+ < label htmlFor = "curly" > Curly</ label >
1388+ </ div >
1389+ </ fieldset >
1390+ < button data-testid = "button4" > button</ button >
1391+ </ FocusScope >
1392+ ) ;
1393+ }
1394+
1395+ let { getByTestId, getAllByRole} = render ( < Test /> ) ;
1396+ let radios = getAllByRole ( 'radio' ) ;
1397+ await user . tab ( ) ;
1398+ expect ( document . activeElement ) . toBe ( getByTestId ( 'button1' ) ) ;
1399+ await user . tab ( ) ;
1400+ expect ( document . activeElement ) . toBe ( radios [ 0 ] ) ;
1401+ await user . tab ( ) ;
1402+ expect ( document . activeElement ) . toBe ( getByTestId ( 'button2' ) ) ;
1403+ await user . tab ( ) ;
1404+ expect ( document . activeElement ) . toBe ( radios [ 3 ] ) ;
1405+ await user . tab ( ) ;
1406+ expect ( document . activeElement ) . toBe ( getByTestId ( 'button3' ) ) ;
1407+ await user . tab ( ) ;
1408+ expect ( document . activeElement ) . toBe ( radios [ 5 ] ) ;
1409+ await user . tab ( ) ;
1410+ expect ( document . activeElement ) . toBe ( getByTestId ( 'button4' ) ) ;
1411+ } ) ;
1412+
1413+ it ( 'skips radio buttons that are in the same group and are not the selectable one backwards' , async function ( ) {
1414+ function Test ( ) {
1415+ return (
1416+ < FocusScope contain >
1417+ < button data-testid = "button1" > button</ button >
1418+ < form >
1419+ < fieldset >
1420+ < legend > Select a maintenance drone:</ legend >
1421+
1422+ < div >
1423+ < input type = "radio" id = "huey" name = "drone" value = "huey" defaultChecked />
1424+ < label htmlFor = "huey" > Huey</ label >
1425+ </ div >
1426+
1427+ < div >
1428+ < input type = "radio" id = "dewey" name = "drone" value = "dewey" />
1429+ < label htmlFor = "dewey" > Dewey</ label >
1430+ </ div >
1431+ < button data-testid = "button2" > button</ button >
1432+ < div >
1433+ < input type = "radio" id = "louie" name = "drone" value = "louie" />
1434+ < label htmlFor = "louie" > Louie</ label >
1435+ </ div >
1436+ </ fieldset >
1437+ < fieldset >
1438+ < legend > Select a ship:</ legend >
1439+
1440+ < div >
1441+ < input type = "radio" id = "larry" name = "ship" value = "larry" />
1442+ < label htmlFor = "larry" > Larry</ label >
1443+ </ div >
1444+
1445+ < div >
1446+ < input type = "radio" id = "moe" name = "ship" value = "moe" />
1447+ < label htmlFor = "moe" > Moe</ label >
1448+ </ div >
1449+ < button data-testid = "button3" > button</ button >
1450+ < div >
1451+ < input type = "radio" id = "curly" name = "ship" value = "curly" />
1452+ < label htmlFor = "curly" > Curly</ label >
1453+ </ div >
1454+ </ fieldset >
1455+ </ form >
1456+ < button data-testid = "button4" > button</ button >
1457+ </ FocusScope >
1458+ ) ;
1459+ }
1460+
1461+ let { getByTestId, getAllByRole} = render ( < Test /> ) ;
1462+ let radios = getAllByRole ( 'radio' ) ;
1463+ await user . click ( getByTestId ( 'button4' ) ) ;
1464+ await user . tab ( { shift : true } ) ;
1465+ expect ( document . activeElement ) . toBe ( radios [ 5 ] ) ;
1466+ await user . tab ( { shift : true } ) ;
1467+ expect ( document . activeElement ) . toBe ( getByTestId ( 'button3' ) ) ;
1468+ await user . tab ( { shift : true } ) ;
1469+ expect ( document . activeElement ) . toBe ( radios [ 4 ] ) ;
1470+ await user . tab ( { shift : true } ) ;
1471+ expect ( document . activeElement ) . toBe ( getByTestId ( 'button2' ) ) ;
1472+ await user . tab ( { shift : true } ) ;
1473+ expect ( document . activeElement ) . toBe ( radios [ 0 ] ) ;
1474+ await user . tab ( { shift : true } ) ;
1475+ expect ( document . activeElement ) . toBe ( getByTestId ( 'button1' ) ) ;
1476+ } ) ;
1477+
1478+ it ( 'skips radio buttons that are in the same group and are not the selectable one backwards outside of a form' , async function ( ) {
1479+ function Test ( ) {
1480+ return (
1481+ < FocusScope contain >
1482+ < button data-testid = "button1" > button</ button >
1483+ < fieldset >
1484+ < legend > Select a maintenance drone:</ legend >
1485+
1486+ < div >
1487+ < input type = "radio" id = "huey" name = "drone" value = "huey" defaultChecked />
1488+ < label htmlFor = "huey" > Huey</ label >
1489+ </ div >
1490+
1491+ < div >
1492+ < input type = "radio" id = "dewey" name = "drone" value = "dewey" />
1493+ < label htmlFor = "dewey" > Dewey</ label >
1494+ </ div >
1495+ < button data-testid = "button2" > button</ button >
1496+ < div >
1497+ < input type = "radio" id = "louie" name = "drone" value = "louie" />
1498+ < label htmlFor = "louie" > Louie</ label >
1499+ </ div >
1500+ </ fieldset >
1501+ < fieldset >
1502+ < legend > Select a ship:</ legend >
1503+
1504+ < div >
1505+ < input type = "radio" id = "larry" name = "ship" value = "larry" />
1506+ < label htmlFor = "larry" > Larry</ label >
1507+ </ div >
1508+
1509+ < div >
1510+ < input type = "radio" id = "moe" name = "ship" value = "moe" />
1511+ < label htmlFor = "moe" > Moe</ label >
1512+ </ div >
1513+ < button data-testid = "button3" > button</ button >
1514+ < div >
1515+ < input type = "radio" id = "curly" name = "ship" value = "curly" />
1516+ < label htmlFor = "curly" > Curly</ label >
1517+ </ div >
1518+ </ fieldset >
1519+ < button data-testid = "button4" > button</ button >
1520+ </ FocusScope >
1521+ ) ;
1522+ }
1523+
1524+ let { getByTestId, getAllByRole} = render ( < Test /> ) ;
1525+ let radios = getAllByRole ( 'radio' ) ;
1526+ await user . click ( getByTestId ( 'button4' ) ) ;
1527+ await user . tab ( { shift : true } ) ;
1528+ expect ( document . activeElement ) . toBe ( radios [ 5 ] ) ;
1529+ await user . tab ( { shift : true } ) ;
1530+ expect ( document . activeElement ) . toBe ( getByTestId ( 'button3' ) ) ;
1531+ await user . tab ( { shift : true } ) ;
1532+ expect ( document . activeElement ) . toBe ( radios [ 4 ] ) ;
1533+ await user . tab ( { shift : true } ) ;
1534+ expect ( document . activeElement ) . toBe ( getByTestId ( 'button2' ) ) ;
1535+ await user . tab ( { shift : true } ) ;
1536+ expect ( document . activeElement ) . toBe ( radios [ 0 ] ) ;
1537+ await user . tab ( { shift : true } ) ;
1538+ expect ( document . activeElement ) . toBe ( getByTestId ( 'button1' ) ) ;
1539+ } ) ;
1540+
12831541 describe ( 'nested focus scopes' , function ( ) {
12841542 it ( 'should make child FocusScopes the active scope regardless of DOM structure' , function ( ) {
12851543 function ChildComponent ( props ) {
0 commit comments