@@ -109,6 +109,7 @@ import {
109109 readStoredAccessibilitySource ,
110110 readStoredFlag ,
111111 sanitizeAccessibilitySources ,
112+ shouldRetainAccessibilityTreeDuringRefresh ,
112113 TOUCH_OVERLAY_VISIBLE_STORAGE_KEY ,
113114 viewportStateForUDID ,
114115 writePersistedUiState ,
@@ -568,6 +569,7 @@ export function AppShell({
568569 > ( ( ) => { } ) ;
569570 const accessibilityRequestIdRef = useRef ( 0 ) ;
570571 const accessibilityLoadingRef = useRef ( false ) ;
572+ const accessibilityRootsRef = useRef < AccessibilityNode [ ] > ( [ ] ) ;
571573 const streamConfigRequestIdRef = useRef ( 0 ) ;
572574 const streamConfigUserChangeAtRef = useRef ( 0 ) ;
573575 const streamConfigUserTouchedRef = useRef ( false ) ;
@@ -588,6 +590,11 @@ export function AppShell({
588590 const zoomDockSize = useElementSize ( zoomDockElement ) ;
589591 refreshRef . current = refresh ;
590592
593+ const updateAccessibilityRoots = useCallback ( ( roots : AccessibilityNode [ ] ) => {
594+ accessibilityRootsRef . current = roots ;
595+ setAccessibilityRoots ( roots ) ;
596+ } , [ ] ) ;
597+
591598 const handleOuterCanvasRef = useCallback ( ( node : HTMLDivElement | null ) => {
592599 outerCanvasRef . current = node ;
593600 setOuterCanvasElement ( node ) ;
@@ -1160,7 +1167,7 @@ export function AppShell({
11601167 setChromeProfile ( null ) ;
11611168 setChromeProfileReady ( false ) ;
11621169 setLocalError ( "" ) ;
1163- setAccessibilityRoots ( [ ] ) ;
1170+ updateAccessibilityRoots ( [ ] ) ;
11641171 setAccessibilitySelectedId ( "" ) ;
11651172 setAccessibilityHoveredId ( null ) ;
11661173 setAccessibilityPickerActive ( false ) ;
@@ -1210,7 +1217,7 @@ export function AppShell({
12101217 : nextViewportState . rotationQuarterTurns ,
12111218 ) ;
12121219 setLocalError ( "" ) ;
1213- setAccessibilityRoots ( [ ] ) ;
1220+ updateAccessibilityRoots ( [ ] ) ;
12141221 setAccessibilitySelectedId (
12151222 persistedState . accessibilitySelectedByUDID ?. [ selectedSimulator . udid ] ??
12161223 "" ,
@@ -1231,7 +1238,7 @@ export function AppShell({
12311238 }
12321239
12331240 if ( providerDisconnected ) {
1234- setAccessibilityRoots ( [ ] ) ;
1241+ updateAccessibilityRoots ( [ ] ) ;
12351242 setAccessibilitySelectedId ( "" ) ;
12361243 setAccessibilityHoveredId ( null ) ;
12371244 setAccessibilityAvailableSources ( [ ] ) ;
@@ -1242,7 +1249,7 @@ export function AppShell({
12421249 }
12431250
12441251 if ( ! selectedSimulator ?. isBooted ) {
1245- setAccessibilityRoots ( [ ] ) ;
1252+ updateAccessibilityRoots ( [ ] ) ;
12461253 setAccessibilitySelectedId ( "" ) ;
12471254 setAccessibilityAvailableSources ( [ ] ) ;
12481255 setAccessibilitySource ( "" ) ;
@@ -1281,48 +1288,90 @@ export function AppShell({
12811288 sanitizeAccessibilitySources ( snapshot . availableSources ) ,
12821289 snapshot . source ,
12831290 ) ;
1284- setAccessibilityRoots ( roots ) ;
1285- setAccessibilityAvailableSources ( availableSources ) ;
1286- setAccessibilitySource ( snapshot . source ) ;
1287- setAccessibilityError (
1288- roots . length === 0
1289- ? userFacingAccessibilityError ( snapshot . fallbackReason ?? "" )
1290- : "" ,
1291- ) ;
1292- const nextPreferredSource = nextAccessibilitySourcePreference (
1291+ const retainCurrentTree = shouldRetainAccessibilityTreeDuringRefresh (
12931292 accessibilityPreferredSource ,
1293+ accessibilitySource ,
12941294 snapshot . source ,
1295- availableSources ,
1295+ roots . length ,
1296+ accessibilityRootsRef . current . length ,
12961297 ) ;
1297- if ( nextPreferredSource ) {
1298- setAccessibilityPreferredSource ( nextPreferredSource ) ;
1299- }
1300- if ( roots . length === 0 ) {
1301- setAccessibilitySelectedId ( "" ) ;
1298+ if ( retainCurrentTree ) {
1299+ setAccessibilityAvailableSources (
1300+ mergeAccessibilitySources (
1301+ availableSources ,
1302+ accessibilitySource ,
1303+ accessibilityPreferredSource ,
1304+ ) ,
1305+ ) ;
1306+ setAccessibilityError ( "" ) ;
1307+ } else {
1308+ updateAccessibilityRoots ( roots ) ;
1309+ setAccessibilityAvailableSources ( availableSources ) ;
1310+ setAccessibilitySource ( snapshot . source ) ;
1311+ setAccessibilityError (
1312+ roots . length === 0
1313+ ? userFacingAccessibilityError ( snapshot . fallbackReason ?? "" )
1314+ : "" ,
1315+ ) ;
1316+ const nextPreferredSource = nextAccessibilitySourcePreference (
1317+ accessibilityPreferredSource ,
1318+ snapshot . source ,
1319+ availableSources ,
1320+ ) ;
1321+ if ( nextPreferredSource ) {
1322+ setAccessibilityPreferredSource ( nextPreferredSource ) ;
1323+ }
1324+ if ( roots . length === 0 ) {
1325+ setAccessibilitySelectedId ( "" ) ;
1326+ }
13021327 }
13031328 } catch ( snapshotError ) {
13041329 if ( accessibilityRequestIdRef . current !== requestId ) {
13051330 return ;
13061331 }
1307- setAccessibilityError (
1308- snapshotError instanceof Error
1309- ? userFacingAccessibilityError ( snapshotError . message )
1310- : "Failed to load accessibility hierarchy." ,
1332+ const retainCurrentTree = shouldRetainAccessibilityTreeDuringRefresh (
1333+ accessibilityPreferredSource ,
1334+ accessibilitySource ,
1335+ "native-ax" ,
1336+ 0 ,
1337+ accessibilityRootsRef . current . length ,
13111338 ) ;
1312- setAccessibilityRoots ( [ ] ) ;
1313- setAccessibilitySelectedId ( "" ) ;
1314- setAccessibilityHoveredId ( null ) ;
1315- setAccessibilitySource ( "" ) ;
1316- if ( accessibilityPreferredSource !== "auto" ) {
1317- setAccessibilityPreferredSource ( "auto" ) ;
1339+ if ( retainCurrentTree ) {
1340+ setAccessibilityAvailableSources ( ( current ) =>
1341+ mergeAccessibilitySources (
1342+ current ,
1343+ accessibilitySource ,
1344+ accessibilityPreferredSource ,
1345+ ) ,
1346+ ) ;
1347+ setAccessibilityError ( "" ) ;
1348+ } else {
1349+ setAccessibilityError (
1350+ snapshotError instanceof Error
1351+ ? userFacingAccessibilityError ( snapshotError . message )
1352+ : "Failed to load accessibility hierarchy." ,
1353+ ) ;
1354+ updateAccessibilityRoots ( [ ] ) ;
1355+ setAccessibilitySelectedId ( "" ) ;
1356+ setAccessibilityHoveredId ( null ) ;
1357+ setAccessibilitySource ( "" ) ;
1358+ if ( accessibilityPreferredSource !== "auto" ) {
1359+ setAccessibilityPreferredSource ( "auto" ) ;
1360+ }
13181361 }
13191362 } finally {
13201363 if ( accessibilityRequestIdRef . current === requestId ) {
13211364 accessibilityLoadingRef . current = false ;
13221365 setAccessibilityLoading ( false ) ;
13231366 }
13241367 }
1325- } , [ accessibilityPreferredSource , providerDisconnected , selectedSimulator ] ) ;
1368+ } , [
1369+ accessibilityPreferredSource ,
1370+ accessibilitySource ,
1371+ providerDisconnected ,
1372+ selectedSimulator ,
1373+ updateAccessibilityRoots ,
1374+ ] ) ;
13261375
13271376 const changeAccessibilitySource = useCallback (
13281377 ( source : AccessibilitySource ) => {
@@ -1332,14 +1381,14 @@ export function AppShell({
13321381 accessibilityRequestIdRef . current += 1 ;
13331382 accessibilityLoadingRef . current = false ;
13341383 setAccessibilityPreferredSource ( source ) ;
1335- setAccessibilityRoots ( [ ] ) ;
1384+ updateAccessibilityRoots ( [ ] ) ;
13361385 setAccessibilitySelectedId ( "" ) ;
13371386 setAccessibilityHoveredId ( null ) ;
13381387 setAccessibilityError ( "" ) ;
13391388 setAccessibilitySource ( "" ) ;
13401389 setAccessibilityLoading ( false ) ;
13411390 } ,
1342- [ accessibilityPreferredSource ] ,
1391+ [ accessibilityPreferredSource , updateAccessibilityRoots ] ,
13431392 ) ;
13441393
13451394 useEffect ( ( ) => {
0 commit comments