Skip to main content

tessera_ui/
focus.rs

1//! Focus ownership, traversal, and restoration for interactive UI.
2//!
3//! ## Usage
4//!
5//! Register focus targets, scopes, and traversal rules for keyboard and IME
6//! input.
7
8use std::{cell::Cell, collections::BTreeMap, ptr::NonNull};
9
10use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet};
11
12use crate::{
13    NodeId, PxPosition, PxRect,
14    component_tree::{
15        ComponentNodeMetaDatas, ComponentNodeTree, NodeRole, nearest_replay_boundary_instance_key,
16        sibling_index,
17    },
18    execution_context::{with_execution_context, with_execution_context_mut},
19    prop::CallbackWith,
20    px::PxSize,
21    runtime::{
22        TesseraRuntime, focus_read_subscribers, focus_requester_read_subscribers,
23        has_persistent_focus_handle, record_replay_boundary_invalidation_for_instance_key,
24        schedule_runtime_redraw, track_focus_read_dependency,
25        track_focus_requester_read_dependency,
26    },
27};
28
29const ROOT_SCOPE_ID: FocusHandleId = 0;
30
31const FOCUS_CHANGE_DIRECTION: crate::session::SessionLocal<Cell<Option<FocusDirection>>> =
32    crate::session::SessionLocal::new();
33
34struct FocusChangeDirectionGuard(Option<FocusDirection>);
35
36impl Drop for FocusChangeDirectionGuard {
37    fn drop(&mut self) {
38        FOCUS_CHANGE_DIRECTION.set(self.0);
39    }
40}
41
42pub(crate) type FocusHandleId = u128;
43pub(crate) type FocusRequesterId = u128;
44
45fn next_focus_handle_id() -> FocusHandleId {
46    uuid::Uuid::new_v4().as_u128()
47}
48
49fn next_focus_requester_id() -> FocusRequesterId {
50    uuid::Uuid::new_v4().as_u128()
51}
52
53fn with_bound_focus_owner<R>(f: impl FnOnce(&FocusOwner) -> R) -> Option<R> {
54    let ptr = with_execution_context(|context| context.current_focus_owner_stack.last().copied())?;
55    // SAFETY: The binding guard only pushes a pointer that remains valid for
56    // the duration of the handler dispatch on the current thread.
57    Some(unsafe { f(ptr.as_ref()) })
58}
59
60fn with_bound_focus_owner_mut<R>(f: impl FnOnce(&mut FocusOwner) -> R) -> Option<R> {
61    let ptr = with_execution_context(|context| context.current_focus_owner_stack.last().copied())?;
62    // SAFETY: The binding guard only pushes a pointer that remains valid for
63    // the duration of the handler dispatch on the current thread.
64    Some(unsafe { f(&mut *ptr.as_ptr()) })
65}
66
67fn with_focus_owner<R>(f: impl FnOnce(&FocusOwner) -> R) -> R {
68    let mut f = Some(f);
69    if let Some(result) = with_bound_focus_owner(|owner| {
70        f.take().expect("focus owner callback should run once")(owner)
71    }) {
72        return result;
73    }
74    TesseraRuntime::with(|runtime| {
75        f.take().expect("focus owner callback should run once")(
76            runtime.component_tree.focus_owner(),
77        )
78    })
79}
80
81fn with_focus_owner_mut<R>(f: impl FnOnce(&mut FocusOwner) -> R) -> R {
82    let mut f = Some(f);
83    if let Some(result) = with_bound_focus_owner_mut(|owner| {
84        f.take().expect("focus owner callback should run once")(owner)
85    }) {
86        return result;
87    }
88    let result = TesseraRuntime::with_mut(|runtime| {
89        f.take().expect("focus owner callback should run once")(
90            runtime.component_tree.focus_owner_mut(),
91        )
92    });
93    flush_pending_focus_callbacks();
94    result
95}
96
97pub(crate) struct FocusOwnerBindingGuard {
98    active: bool,
99}
100
101impl Drop for FocusOwnerBindingGuard {
102    fn drop(&mut self) {
103        if !self.active {
104            return;
105        }
106        with_execution_context_mut(|context| {
107            let popped = context.current_focus_owner_stack.pop();
108            debug_assert!(popped.is_some(), "focus owner binding stack underflow");
109        });
110        self.active = false;
111    }
112}
113
114pub(crate) fn bind_focus_owner(owner: &mut FocusOwner) -> FocusOwnerBindingGuard {
115    with_execution_context_mut(|context| {
116        context.current_focus_owner_stack.push(NonNull::from(owner));
117    });
118    FocusOwnerBindingGuard { active: true }
119}
120
121/// Focus state for a registered focus node.
122///
123/// Use this to render focus-dependent UI and distinguish between the primary
124/// focused target and its focused ancestors.
125#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
126pub enum FocusState {
127    /// The node is not participating in the active focus path.
128    #[default]
129    Inactive,
130    /// A descendant of this node currently holds focus.
131    ActiveParent,
132    /// This node currently holds focus.
133    Active,
134    /// This node currently holds captured focus.
135    Captured,
136}
137
138impl FocusState {
139    /// Returns `true` when this node is in the active focus path.
140    pub fn has_focus(self) -> bool {
141        !matches!(self, Self::Inactive)
142    }
143
144    /// Returns `true` when this node is the primary focused node.
145    pub fn is_focused(self) -> bool {
146        matches!(self, Self::Active | Self::Captured)
147    }
148
149    /// Returns `true` when this node has captured focus.
150    pub fn is_captured(self) -> bool {
151        matches!(self, Self::Captured)
152    }
153}
154
155/// Focus traversal direction for owner-level movement.
156///
157/// These directions are used by [`FocusManager`], [`FocusScopeNode`], and
158/// [`FocusGroupNode`] when keyboard or programmatic traversal moves focus.
159#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
160pub enum FocusDirection {
161    /// Move to the next focusable target in traversal order.
162    Next,
163    /// Move to the previous focusable target in traversal order.
164    Previous,
165    /// Move focus upward.
166    Up,
167    /// Move focus downward.
168    Down,
169    /// Move focus leftward.
170    Left,
171    /// Move focus rightward.
172    Right,
173    /// Enter a nested focus group or scope.
174    Enter,
175    /// Exit the current focus group or scope.
176    Exit,
177}
178
179/// Strategy used by a focus traversal policy.
180#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
181pub enum FocusTraversalStrategy {
182    /// Traverse in declaration order using previous/next semantics.
183    Linear,
184    /// Traverse horizontally using left/right arrows.
185    Horizontal,
186    /// Traverse vertically using up/down arrows.
187    Vertical,
188    /// Traverse spatially using candidate rectangles.
189    Spatial,
190}
191
192/// Policy applied by a focus scope or group when traversal starts inside it.
193///
194/// Use policies to describe how a container handles directional keys and
195/// whether `Tab` navigation should stay inside the container.
196#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
197pub struct FocusTraversalPolicy {
198    /// Traversal strategy used for arrow-key navigation.
199    pub strategy: FocusTraversalStrategy,
200    /// Whether traversal wraps when it reaches either end of the group.
201    pub wrap: bool,
202    /// Whether `Tab` and `Shift+Tab` should be handled by this policy.
203    pub tab_navigation: bool,
204    /// Whether the group contributes one stop to global Tab navigation.
205    /// The preferred enabled descendant is used on entry; arrows still visit
206    /// every traversable descendant.
207    pub single_tab_stop: bool,
208}
209
210impl FocusTraversalPolicy {
211    /// Creates a new traversal policy for the given strategy.
212    pub const fn new(strategy: FocusTraversalStrategy) -> Self {
213        Self {
214            strategy,
215            wrap: false,
216            tab_navigation: false,
217            single_tab_stop: false,
218        }
219    }
220
221    /// Creates a linear traversal policy.
222    pub const fn linear() -> Self {
223        Self::new(FocusTraversalStrategy::Linear)
224    }
225
226    /// Creates a horizontal traversal policy.
227    pub const fn horizontal() -> Self {
228        Self::new(FocusTraversalStrategy::Horizontal)
229    }
230
231    /// Creates a vertical traversal policy.
232    pub const fn vertical() -> Self {
233        Self::new(FocusTraversalStrategy::Vertical)
234    }
235
236    /// Creates a spatial traversal policy.
237    pub const fn spatial() -> Self {
238        Self::new(FocusTraversalStrategy::Spatial)
239    }
240
241    /// Sets whether traversal wraps when it reaches either end.
242    pub const fn wrap(mut self, wrap: bool) -> Self {
243        self.wrap = wrap;
244        self
245    }
246
247    /// Sets whether `Tab` and `Shift+Tab` should be handled inside this
248    /// policy owner.
249    pub const fn tab_navigation(mut self, tab_navigation: bool) -> Self {
250        self.tab_navigation = tab_navigation;
251        self
252    }
253
254    /// Makes this group a single Tab stop, preferring a descendant marked with
255    /// [`FocusProperties::preferred_tab_stop`] and otherwise its first enabled
256    /// descendant. Tab leaves the group from any focused descendant.
257    pub const fn single_tab_stop(mut self, single_tab_stop: bool) -> Self {
258        self.single_tab_stop = single_tab_stop;
259        self
260    }
261
262    fn scoped_direction(self, direction: FocusDirection) -> Option<FocusDirection> {
263        if self.tab_navigation && !self.single_tab_stop {
264            match direction {
265                FocusDirection::Next | FocusDirection::Previous => return Some(direction),
266                _ => {}
267            }
268        }
269
270        match self.strategy {
271            FocusTraversalStrategy::Linear => match direction {
272                FocusDirection::Left | FocusDirection::Up => Some(FocusDirection::Previous),
273                FocusDirection::Right | FocusDirection::Down => Some(FocusDirection::Next),
274                _ => None,
275            },
276            FocusTraversalStrategy::Horizontal => match direction {
277                FocusDirection::Left => Some(FocusDirection::Previous),
278                FocusDirection::Right => Some(FocusDirection::Next),
279                _ => None,
280            },
281            FocusTraversalStrategy::Vertical => match direction {
282                FocusDirection::Up => Some(FocusDirection::Previous),
283                FocusDirection::Down => Some(FocusDirection::Next),
284                _ => None,
285            },
286            FocusTraversalStrategy::Spatial => match direction {
287                FocusDirection::Left
288                | FocusDirection::Right
289                | FocusDirection::Up
290                | FocusDirection::Down => Some(direction),
291                _ => None,
292            },
293        }
294    }
295}
296
297/// A request for scroll containers to reveal a focused rectangle.
298#[derive(Clone, Copy, Debug, PartialEq)]
299pub struct FocusRevealRequest {
300    target_bounds: crate::FloatRect,
301    viewport_bounds: crate::FloatRect,
302    local_to_window: crate::LocalToWindow,
303    /// The absolute rectangle of the focused target.
304    pub target_rect: PxRect,
305    /// The absolute visible viewport of the current reveal container.
306    pub viewport_rect: PxRect,
307}
308
309impl FocusRevealRequest {
310    pub(crate) fn with_geometry(
311        target_bounds: crate::FloatRect,
312        viewport_bounds: crate::FloatRect,
313        local_to_window: crate::LocalToWindow,
314    ) -> Self {
315        Self {
316            target_rect: target_bounds.outward(),
317            viewport_rect: viewport_bounds.outward(),
318            target_bounds,
319            viewport_bounds,
320            local_to_window,
321        }
322    }
323
324    /// Returns the focused rectangle in the reveal container's local units.
325    pub fn local_target_bounds(self) -> crate::FloatRect {
326        self.local_to_window.inverse_rect(self.target_bounds)
327    }
328
329    /// Returns the visible viewport in the reveal container's local units.
330    pub fn local_viewport_bounds(self) -> crate::FloatRect {
331        self.local_to_window.inverse_rect(self.viewport_bounds)
332    }
333}
334
335/// Focus properties used when registering a focus node on the current
336/// component.
337///
338/// Use properties to enable or disable focus participation and to declare
339/// explicit traversal neighbors for complex layouts.
340/// Controls hidden by layout cannot receive focus. Placed controls outside a
341/// scroll viewport remain eligible so navigation can reveal them.
342#[derive(Clone, Copy, Debug, PartialEq, Eq)]
343pub struct FocusProperties {
344    /// Whether this node may receive focus.
345    pub can_focus: bool,
346    /// Whether this node may be the target of focus requests.
347    pub can_request_focus: bool,
348    /// Whether traversal should skip this node.
349    /// A directly focused skipped target still anchors subsequent traversal.
350    pub skip_traversal: bool,
351    /// Whether this target is preferred when Tab enters a single-stop group.
352    pub preferred_tab_stop: bool,
353    /// Explicit target for `Next` traversal.
354    pub next: Option<FocusRequester>,
355    /// Explicit target for `Previous` traversal.
356    pub previous: Option<FocusRequester>,
357    /// Explicit target for `Up` traversal.
358    pub up: Option<FocusRequester>,
359    /// Explicit target for `Down` traversal.
360    pub down: Option<FocusRequester>,
361    /// Explicit target for `Left` traversal.
362    pub left: Option<FocusRequester>,
363    /// Explicit target for `Right` traversal.
364    pub right: Option<FocusRequester>,
365    /// Explicit target when entering a nested focus region.
366    pub enter: Option<FocusRequester>,
367    /// Explicit target when exiting a focus region.
368    pub exit: Option<FocusRequester>,
369}
370
371impl FocusProperties {
372    /// Creates the default focus properties for focus targets.
373    pub fn new() -> Self {
374        Self::default()
375    }
376
377    /// Sets whether this node may receive focus.
378    pub fn can_focus(mut self, can_focus: bool) -> Self {
379        self.can_focus = can_focus;
380        self
381    }
382
383    /// Sets whether this node may be the target of focus requests.
384    pub fn can_request_focus(mut self, can_request_focus: bool) -> Self {
385        self.can_request_focus = can_request_focus;
386        self
387    }
388
389    /// Sets whether traversal should skip this node.
390    pub fn skip_traversal(mut self, skip_traversal: bool) -> Self {
391        self.skip_traversal = skip_traversal;
392        self
393    }
394
395    /// Prefers this target when entering a group whose traversal policy uses a
396    /// single Tab stop. Disabled or skipped targets are never chosen on entry.
397    pub fn preferred_tab_stop(mut self, preferred: bool) -> Self {
398        self.preferred_tab_stop = preferred;
399        self
400    }
401
402    /// Sets the explicit requester for `Next` traversal.
403    pub fn next(mut self, requester: FocusRequester) -> Self {
404        self.next = Some(requester);
405        self
406    }
407
408    /// Sets the explicit requester for `Previous` traversal.
409    pub fn previous(mut self, requester: FocusRequester) -> Self {
410        self.previous = Some(requester);
411        self
412    }
413
414    /// Sets the explicit requester for `Up` traversal.
415    pub fn up(mut self, requester: FocusRequester) -> Self {
416        self.up = Some(requester);
417        self
418    }
419
420    /// Sets the explicit requester for `Down` traversal.
421    pub fn down(mut self, requester: FocusRequester) -> Self {
422        self.down = Some(requester);
423        self
424    }
425
426    /// Sets the explicit requester for `Left` traversal.
427    pub fn left(mut self, requester: FocusRequester) -> Self {
428        self.left = Some(requester);
429        self
430    }
431
432    /// Sets the explicit requester for `Right` traversal.
433    pub fn right(mut self, requester: FocusRequester) -> Self {
434        self.right = Some(requester);
435        self
436    }
437
438    /// Sets the explicit requester used when moving focus into a group.
439    pub fn enter(mut self, requester: FocusRequester) -> Self {
440        self.enter = Some(requester);
441        self
442    }
443
444    /// Sets the explicit requester used when moving focus out of a group.
445    pub fn exit(mut self, requester: FocusRequester) -> Self {
446        self.exit = Some(requester);
447        self
448    }
449}
450
451impl Default for FocusProperties {
452    fn default() -> Self {
453        Self {
454            can_focus: true,
455            can_request_focus: true,
456            skip_traversal: false,
457            preferred_tab_stop: false,
458            next: None,
459            previous: None,
460            up: None,
461            down: None,
462            left: None,
463            right: None,
464            enter: None,
465            exit: None,
466        }
467    }
468}
469
470#[derive(Clone, Copy, Debug, PartialEq, Eq)]
471pub(crate) enum FocusRegistrationKind {
472    Target,
473    Scope,
474    Group,
475}
476
477#[derive(Clone, Copy, Debug, PartialEq, Eq)]
478pub(crate) struct FocusRegistration {
479    pub(crate) id: FocusHandleId,
480    pub(crate) kind: FocusRegistrationKind,
481    pub(crate) properties: FocusProperties,
482}
483
484impl FocusRegistration {
485    pub(crate) fn target(node: FocusNode) -> Self {
486        Self {
487            id: node.id,
488            kind: FocusRegistrationKind::Target,
489            properties: FocusProperties::default(),
490        }
491    }
492
493    pub(crate) fn scope(scope: FocusScopeNode) -> Self {
494        Self {
495            id: scope.id,
496            kind: FocusRegistrationKind::Scope,
497            properties: FocusProperties::default().can_focus(false),
498        }
499    }
500
501    pub(crate) fn group(group: FocusGroupNode) -> Self {
502        Self {
503            id: group.id,
504            kind: FocusRegistrationKind::Group,
505            properties: FocusProperties::default()
506                .can_focus(false)
507                .can_request_focus(false),
508        }
509    }
510}
511
512/// Imperative handle used to request focus for a registered target.
513///
514/// Requesters are stable handles that can be stored in component state and
515/// passed across component boundaries without exposing the underlying focus
516/// tree.
517#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
518pub struct FocusRequester {
519    id: FocusRequesterId,
520}
521
522impl FocusRequester {
523    /// Creates a new focus requester.
524    pub fn new() -> Self {
525        Self {
526            id: next_focus_requester_id(),
527        }
528    }
529
530    /// Requests focus for the bound target.
531    ///
532    /// An attached target hidden by layout rejects the request. Navigation can
533    /// still reveal a placed target outside its scroll viewport.
534    pub fn request_focus(&self) {
535        with_focus_owner_mut(|owner| owner.request_focus_by_requester(self.id));
536    }
537
538    /// Clears focus from the bound target if it currently holds it.
539    pub fn clear_focus(&self) {
540        with_focus_owner_mut(|owner| owner.clear_focus_by_requester(self.id));
541    }
542
543    /// Alias for [`Self::clear_focus`].
544    pub fn unfocus(&self) {
545        self.clear_focus();
546    }
547
548    /// Captures focus on this node, preventing focus from moving elsewhere
549    /// until released, force-cleared, hidden by layout, or removed.
550    pub fn capture_focus(&self) {
551        with_focus_owner_mut(|owner| owner.capture_focus_by_requester(self.id));
552    }
553
554    /// Releases captured focus from this node.
555    pub fn free_focus(&self) {
556        with_focus_owner_mut(|owner| owner.free_focus_by_requester(self.id));
557    }
558
559    /// Returns the current focus state for the bound target.
560    pub fn state(&self) -> FocusState {
561        track_focus_requester_read_dependency(self.id);
562        with_focus_owner(|owner| owner.state_of_requester(self.id))
563    }
564
565    /// Returns `true` when this node is in the active focus path.
566    pub fn has_focus(&self) -> bool {
567        self.state().has_focus()
568    }
569
570    /// Returns `true` when this node is the primary focused node.
571    pub fn is_focused(&self) -> bool {
572        self.state().is_focused()
573    }
574
575    /// Returns whether the focused target should display a keyboard focus
576    /// indicator.
577    ///
578    /// Pointer presses hide the indicator without releasing focus. Keyboard
579    /// input and accessibility focus actions show it; programmatic focus
580    /// inherits the most recent input mode. Read this during component
581    /// composition.
582    pub fn is_focus_visible(&self) -> bool {
583        track_focus_requester_read_dependency(self.id);
584        with_focus_owner(|owner| owner.is_requester_focus_visible(self.id))
585    }
586
587    /// Returns `true` when this node has captured focus.
588    pub fn is_captured(&self) -> bool {
589        self.state().is_captured()
590    }
591
592    pub(crate) fn requester_id(self) -> FocusRequesterId {
593        self.id
594    }
595}
596
597impl Default for FocusRequester {
598    fn default() -> Self {
599        Self::new()
600    }
601}
602
603/// Persistent focus target handle.
604///
605/// This is the low-level target identity used by focus modifiers. Most code
606/// should prefer [`FocusRequester`] and [`crate::modifier::FocusModifierExt`].
607#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
608pub(crate) struct FocusNode {
609    id: FocusHandleId,
610}
611
612impl FocusNode {
613    pub(crate) fn new() -> Self {
614        Self {
615            id: next_focus_handle_id(),
616        }
617    }
618
619    pub(crate) fn handle_id(self) -> FocusHandleId {
620        self.id
621    }
622
623    pub(crate) fn from_handle_id(id: FocusHandleId) -> Self {
624        Self { id }
625    }
626}
627
628impl Default for FocusNode {
629    fn default() -> Self {
630        Self::new()
631    }
632}
633
634/// Persistent focus scope handle.
635///
636/// Scopes own restore behavior and provide imperative traversal within a
637/// subtree.
638#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
639pub struct FocusScopeNode {
640    id: FocusHandleId,
641}
642
643impl FocusScopeNode {
644    /// Creates a new persistent focus scope handle.
645    pub fn new() -> Self {
646        Self {
647            id: next_focus_handle_id(),
648        }
649    }
650
651    pub(crate) fn handle_id(self) -> FocusHandleId {
652        self.id
653    }
654
655    pub(crate) fn from_handle_id(id: FocusHandleId) -> Self {
656        Self { id }
657    }
658
659    /// Requests focus within this scope, restoring the last focused descendant
660    /// when possible.
661    pub fn request_focus(&self) {
662        with_focus_owner_mut(|owner| owner.request_focus(self.id));
663    }
664
665    /// Clears focus from this scope.
666    pub fn clear_focus(&self) {
667        with_focus_owner_mut(|owner| owner.clear_focus(self.id));
668    }
669
670    /// Restores focus to the last focused descendant of this scope.
671    pub fn restore_focus(&self) {
672        with_focus_owner_mut(|owner| owner.restore_focus(self.id));
673    }
674
675    /// Moves focus to another focusable descendant inside this scope.
676    pub fn move_focus(&self, direction: FocusDirection) -> bool {
677        with_focus_owner_mut(|owner| owner.move_focus_in_scope(self.id, direction, false))
678    }
679
680    /// Cycles focus inside this scope, wrapping when traversal reaches an end.
681    pub fn cycle_focus(&self, direction: FocusDirection) -> bool {
682        with_focus_owner_mut(|owner| owner.move_focus_in_scope(self.id, direction, true))
683    }
684
685    /// Returns the current focus state for this scope.
686    pub fn state(&self) -> FocusState {
687        track_focus_read_dependency(self.id);
688        with_focus_owner(|owner| owner.state_of(self.id))
689    }
690
691    /// Returns `true` when this scope participates in the active focus path.
692    pub fn has_focus(&self) -> bool {
693        self.state().has_focus()
694    }
695
696    /// Returns `true` when this scope itself is the primary focused node.
697    pub fn is_focused(&self) -> bool {
698        self.state().is_focused()
699    }
700}
701
702impl Default for FocusScopeNode {
703    fn default() -> Self {
704        Self::new()
705    }
706}
707
708/// Persistent traversal-only focus group handle.
709///
710/// Groups define traversal boundaries without taking on scope restore
711/// semantics.
712#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
713pub struct FocusGroupNode {
714    id: FocusHandleId,
715}
716
717impl FocusGroupNode {
718    /// Creates a new persistent focus group handle.
719    pub fn new() -> Self {
720        Self {
721            id: next_focus_handle_id(),
722        }
723    }
724
725    pub(crate) fn handle_id(self) -> FocusHandleId {
726        self.id
727    }
728
729    pub(crate) fn from_handle_id(id: FocusHandleId) -> Self {
730        Self { id }
731    }
732
733    /// Moves focus to another focusable descendant inside this group.
734    pub fn move_focus(&self, direction: FocusDirection) -> bool {
735        with_focus_owner_mut(|owner| owner.move_focus_in_scope(self.id, direction, false))
736    }
737
738    /// Cycles focus inside this group, wrapping when traversal reaches an end.
739    pub fn cycle_focus(&self, direction: FocusDirection) -> bool {
740        with_focus_owner_mut(|owner| owner.move_focus_in_scope(self.id, direction, true))
741    }
742
743    /// Returns the current focus state for this group.
744    pub fn state(&self) -> FocusState {
745        track_focus_read_dependency(self.id);
746        with_focus_owner(|owner| owner.state_of(self.id))
747    }
748
749    /// Returns `true` when this group participates in the active focus path.
750    pub fn has_focus(&self) -> bool {
751        self.state().has_focus()
752    }
753
754    /// Returns `true` when this group itself is the primary focused node.
755    pub fn is_focused(&self) -> bool {
756        self.state().is_focused()
757    }
758}
759
760impl Default for FocusGroupNode {
761    fn default() -> Self {
762        Self::new()
763    }
764}
765
766/// A saved focus target that can be restored while it remains available.
767///
768/// Use [`FocusManager::save_focus`] before showing temporary interactive
769/// content. Restoration does not wait for a removed or disabled target to
770/// become available.
771#[derive(Clone, Copy, Debug, PartialEq, Eq)]
772pub struct FocusRestorationTarget {
773    id: FocusHandleId,
774}
775
776impl FocusRestorationTarget {
777    /// Restores focus if the target is attached, enabled and available.
778    ///
779    /// Returns `false` when the window is unfocused or another target has
780    /// captured focus. Check availability after layout when target
781    /// properties have changed.
782    pub fn restore(self) -> bool {
783        with_focus_owner_mut(|owner| {
784            if !owner.owner_focused
785                || !owner.can_request_focus(self.id)
786                || owner.captured.is_some_and(|captured| captured != self.id)
787            {
788                return false;
789            }
790            owner.request_focus(self.id);
791            true
792        })
793    }
794}
795
796/// Owner-scoped focus manager for traversal and forced clear operations.
797///
798/// Use the focus manager to trigger application-level traversal without
799/// storing a specific scope or requester.
800#[derive(Clone, Copy, Debug, Default)]
801pub struct FocusManager;
802
803impl FocusManager {
804    /// Returns the focus manager for the current component tree.
805    pub fn current() -> Self {
806        Self
807    }
808
809    /// Saves the current target for restoring focus after temporary UI closes.
810    ///
811    /// Saving does not move focus or keep the target alive. Restore only while
812    /// the temporary UI still owns focus, so later user navigation is
813    /// preserved.
814    pub fn save_focus(self) -> Option<FocusRestorationTarget> {
815        with_focus_owner(|owner| owner.active.map(|id| FocusRestorationTarget { id }))
816    }
817
818    /// Returns the traversal direction responsible for the focus callback
819    /// currently running. Explicit focus requests, restoration, and calls
820    /// outside a focus callback return `None`.
821    pub fn focus_change_direction(self) -> Option<FocusDirection> {
822        FOCUS_CHANGE_DIRECTION.get()
823    }
824
825    /// Defers queued keys until the next layout and its focus updates finish.
826    ///
827    /// Use when opening or closing focusable content so subsequent keys reach
828    /// the resulting focus target.
829    pub fn defer_keyboard_until_layout(self) {
830        with_focus_owner_mut(|owner| owner.keyboard_barrier = KeyboardLayoutBarrier::Requested);
831    }
832
833    /// Clears the current focus. Set `force` to `true` to break captured focus.
834    pub fn clear_focus(self, force: bool) {
835        with_focus_owner_mut(|owner| {
836            owner.clear_focus_global(force);
837        });
838    }
839
840    /// Moves focus in the requested direction.
841    pub fn move_focus(self, direction: FocusDirection) -> bool {
842        with_focus_owner_mut(|owner| {
843            owner.pending_navigation = None;
844            owner.move_focus(direction)
845        })
846    }
847
848    /// Queues traversal after the next layout, revealing lazy content as
849    /// needed.
850    ///
851    /// Later requests replace an earlier queued direction. Returns `false` when
852    /// the window is unfocused or focus is captured. Following keyboard input
853    /// waits for the requested traversal and its layout updates.
854    /// Explicit focus requests, focus capture, and window blur cancel it.
855    pub fn request_move_focus(self, direction: FocusDirection) -> bool {
856        let accepted = with_focus_owner_mut(|owner| {
857            if !owner.owner_focused || owner.captured.is_some() {
858                return false;
859            }
860            owner.pending_navigation = Some(direction);
861            owner.keyboard_barrier = KeyboardLayoutBarrier::Requested;
862            true
863        });
864        if accepted {
865            schedule_runtime_redraw();
866        }
867        accepted
868    }
869}
870
871#[derive(Clone, Copy, Debug)]
872struct FocusAttachment {
873    host_replay_boundary_key: u64,
874    live_node_id: Option<NodeId>,
875    focus_rect: Option<PxRect>,
876    traversal_order: Option<u64>,
877    parent: FocusHandleId,
878    scope_parent: FocusHandleId,
879}
880
881impl FocusAttachment {
882    fn permits_focus(self) -> bool {
883        // Requests before layout remain valid. Clipped but placed targets keep
884        // a rectangle so keyboard navigation can reveal them.
885        self.traversal_order.is_none() || self.focus_rect.is_some()
886    }
887
888    fn root_scope() -> Self {
889        Self {
890            host_replay_boundary_key: 0,
891            live_node_id: None,
892            focus_rect: None,
893            traversal_order: None,
894            parent: ROOT_SCOPE_ID,
895            scope_parent: ROOT_SCOPE_ID,
896        }
897    }
898}
899
900#[derive(Clone, Copy, Debug)]
901struct FocusTreeNode {
902    kind: FocusRegistrationKind,
903    attachment: Option<FocusAttachment>,
904    last_parent: FocusHandleId,
905    last_scope_parent: FocusHandleId,
906    props: FocusProperties,
907    traversal_policy: Option<FocusTraversalPolicy>,
908    state: FocusState,
909    last_focused_descendant: Option<FocusHandleId>,
910    restorer_fallback: Option<FocusRequesterId>,
911}
912
913impl FocusTreeNode {
914    fn new_root_scope() -> Self {
915        Self {
916            kind: FocusRegistrationKind::Scope,
917            attachment: Some(FocusAttachment::root_scope()),
918            last_parent: ROOT_SCOPE_ID,
919            last_scope_parent: ROOT_SCOPE_ID,
920            props: FocusProperties::default()
921                .can_focus(false)
922                .can_request_focus(false)
923                .skip_traversal(true),
924            traversal_policy: None,
925            state: FocusState::Inactive,
926            last_focused_descendant: None,
927            restorer_fallback: None,
928        }
929    }
930
931    fn new(kind: FocusRegistrationKind) -> Self {
932        Self {
933            kind,
934            attachment: None,
935            last_parent: ROOT_SCOPE_ID,
936            last_scope_parent: ROOT_SCOPE_ID,
937            props: FocusProperties::default(),
938            traversal_policy: None,
939            state: FocusState::Inactive,
940            last_focused_descendant: None,
941            restorer_fallback: None,
942        }
943    }
944
945    fn is_attached(&self) -> bool {
946        self.attachment.is_some()
947    }
948}
949
950#[derive(Clone)]
951pub(crate) struct PendingFocusCallbackInvocation {
952    callback: CallbackWith<FocusState>,
953    state: FocusState,
954    direction: Option<FocusDirection>,
955}
956
957impl PendingFocusCallbackInvocation {
958    pub(crate) fn new(
959        callback: CallbackWith<FocusState>,
960        state: FocusState,
961        direction: Option<FocusDirection>,
962    ) -> Self {
963        Self {
964            callback,
965            state,
966            direction,
967        }
968    }
969
970    pub(crate) fn invoke(self) {
971        let _direction = FocusChangeDirectionGuard(FOCUS_CHANGE_DIRECTION.replace(self.direction));
972        self.callback.call(self.state);
973    }
974}
975
976#[derive(Clone, Copy, Debug)]
977pub(crate) struct FocusNotification {
978    pub handle_id: FocusHandleId,
979    pub state: FocusState,
980    pub changed: bool,
981    pub direction: Option<FocusDirection>,
982}
983
984#[derive(Clone, Copy, Debug)]
985enum FocusCommand {
986    Request(FocusHandleId),
987    Clear(FocusHandleId),
988    Capture(FocusHandleId),
989    Free(FocusHandleId),
990    Restore(FocusHandleId),
991}
992
993#[derive(Clone, Copy)]
994struct DeferredFocusCommand {
995    command: FocusCommand,
996    reveal: bool,
997}
998
999#[derive(Clone, Copy, Default, PartialEq, Eq)]
1000enum KeyboardLayoutBarrier {
1001    #[default]
1002    None,
1003    Requested,
1004    Layout,
1005}
1006
1007type FocusOrderPath = Vec<(u64, usize)>;
1008type FocusChildren = BTreeMap<(FocusOrderPath, FocusHandleId), FocusHandleId>;
1009
1010/// Per-component-tree focus owner.
1011#[derive(Default)]
1012pub(crate) struct FocusOwner {
1013    nodes: HashMap<FocusHandleId, FocusTreeNode>,
1014    children_by_parent: HashMap<FocusHandleId, FocusChildren>,
1015    requester_bindings: HashMap<FocusRequesterId, FocusHandleId>,
1016    requesters_by_handle: HashMap<FocusHandleId, Vec<FocusRequesterId>>,
1017    active: Option<FocusHandleId>,
1018    stateful_handles: HashSet<FocusHandleId>,
1019    handles_by_component: HashMap<NodeId, FocusHandleId>,
1020    order_paths: HashMap<FocusHandleId, FocusOrderPath>,
1021    captured: Option<FocusHandleId>,
1022    suspended: Option<FocusHandleId>,
1023    owner_focused: bool,
1024    focus_visible: bool,
1025    latest_focus_input: Option<crate::time::Instant>,
1026    pending: Vec<DeferredFocusCommand>,
1027    pending_notifications: Vec<FocusNotification>,
1028    pending_reveal: Option<FocusHandleId>,
1029    pending_navigation: Option<FocusDirection>,
1030    keyboard_barrier: KeyboardLayoutBarrier,
1031}
1032
1033impl FocusOwner {
1034    pub(crate) fn new() -> Self {
1035        let mut nodes = HashMap::default();
1036        nodes.insert(ROOT_SCOPE_ID, FocusTreeNode::new_root_scope());
1037        Self {
1038            nodes,
1039            children_by_parent: HashMap::default(),
1040            requester_bindings: HashMap::default(),
1041            requesters_by_handle: HashMap::default(),
1042            active: None,
1043            stateful_handles: HashSet::default(),
1044            handles_by_component: HashMap::default(),
1045            order_paths: HashMap::default(),
1046            captured: None,
1047            suspended: None,
1048            owner_focused: true,
1049            focus_visible: false,
1050            latest_focus_input: None,
1051            pending: Vec::new(),
1052            pending_notifications: Vec::new(),
1053            pending_reveal: None,
1054            pending_navigation: None,
1055            keyboard_barrier: KeyboardLayoutBarrier::None,
1056        }
1057    }
1058
1059    pub(crate) fn reset(&mut self) {
1060        *self = Self::new();
1061    }
1062
1063    pub(crate) fn begin_layout(&mut self) {
1064        if self.keyboard_barrier == KeyboardLayoutBarrier::Requested {
1065            self.keyboard_barrier = KeyboardLayoutBarrier::Layout;
1066        }
1067    }
1068
1069    pub(crate) fn finish_layout(&mut self) {
1070        if self.keyboard_barrier == KeyboardLayoutBarrier::Layout {
1071            self.keyboard_barrier = KeyboardLayoutBarrier::None;
1072        }
1073    }
1074
1075    pub(crate) fn keyboard_is_deferred(&self) -> bool {
1076        self.keyboard_barrier != KeyboardLayoutBarrier::None
1077    }
1078
1079    pub(crate) fn take_pending_navigation(&mut self) -> Option<FocusDirection> {
1080        self.pending_navigation
1081            .take()
1082            .filter(|_| self.owner_focused && self.captured.is_none())
1083    }
1084
1085    pub(crate) fn retain_navigation_retry(&mut self, direction: Option<FocusDirection>) {
1086        if self.pending_navigation.is_none() {
1087            self.pending_navigation = direction;
1088        }
1089    }
1090
1091    pub(crate) fn has_pending_navigation(&self) -> bool {
1092        self.pending_navigation.is_some()
1093    }
1094
1095    pub(crate) fn allows_navigation(&self) -> bool {
1096        self.owner_focused && self.captured.is_none()
1097    }
1098
1099    pub(crate) fn state_of(&self, id: FocusHandleId) -> FocusState {
1100        self.nodes
1101            .get(&id)
1102            .filter(|node| node.is_attached())
1103            .map(|node| node.state)
1104            .unwrap_or(FocusState::Inactive)
1105    }
1106
1107    pub(crate) fn active_component_node_id(&self) -> Option<NodeId> {
1108        let active = self.active?;
1109        self.nodes
1110            .get(&active)
1111            .and_then(|node| node.attachment)
1112            .and_then(|attachment| attachment.live_node_id)
1113    }
1114
1115    pub(crate) fn component_node_id_of(&self, id: FocusHandleId) -> Option<NodeId> {
1116        self.nodes
1117            .get(&id)
1118            .and_then(|node| node.attachment)
1119            .and_then(|attachment| attachment.live_node_id)
1120    }
1121
1122    pub(crate) fn active_handle_id(&self) -> Option<FocusHandleId> {
1123        self.active
1124    }
1125
1126    pub(crate) fn has_pending_reveal(&self) -> bool {
1127        self.pending_reveal.is_some()
1128    }
1129
1130    pub(crate) fn take_pending_reveal(&mut self) -> Option<FocusHandleId> {
1131        self.pending_reveal.take()
1132    }
1133
1134    pub(crate) fn retain_reveal_retry(&mut self) {
1135        if self.pending_reveal.is_none() {
1136            self.pending_reveal = self.active;
1137        }
1138    }
1139
1140    pub(crate) fn cancel_pending_reveal_for_scroll(&mut self) {
1141        self.pending_reveal = None;
1142        for pending in &mut self.pending {
1143            if matches!(
1144                pending.command,
1145                FocusCommand::Request(_) | FocusCommand::Restore(_)
1146            ) {
1147                pending.reveal = false;
1148            }
1149        }
1150    }
1151
1152    pub(crate) fn record_keyboard_input(
1153        &mut self,
1154        state: winit::event::ElementState,
1155        timestamp: crate::time::Instant,
1156    ) {
1157        if state == winit::event::ElementState::Pressed {
1158            self.record_focus_input(true, timestamp);
1159        }
1160    }
1161
1162    pub(crate) fn record_pointer_press(&mut self, timestamp: crate::time::Instant) {
1163        self.record_focus_input(false, timestamp);
1164    }
1165
1166    pub(crate) fn observe_pointer_press(&mut self, timestamp: crate::time::Instant) {
1167        if self
1168            .latest_focus_input
1169            .is_none_or(|latest| timestamp > latest)
1170        {
1171            self.record_pointer_press(timestamp);
1172        }
1173    }
1174
1175    pub(crate) fn record_accessibility_focus(&mut self, timestamp: crate::time::Instant) {
1176        self.record_focus_input(true, timestamp);
1177    }
1178
1179    fn record_focus_input(&mut self, visible: bool, timestamp: crate::time::Instant) {
1180        if self
1181            .latest_focus_input
1182            .is_some_and(|latest| timestamp < latest)
1183        {
1184            return;
1185        }
1186        self.latest_focus_input = Some(timestamp);
1187        if self.focus_visible == visible {
1188            return;
1189        }
1190        self.focus_visible = visible;
1191        let Some(active) = self.active else {
1192            return;
1193        };
1194        if let Some(node) = self.nodes.get(&active)
1195            && let Some(attachment) = node.attachment
1196            && attachment.host_replay_boundary_key != 0
1197        {
1198            record_replay_boundary_invalidation_for_instance_key(
1199                attachment.host_replay_boundary_key,
1200            );
1201        }
1202        if let Some(requesters) = self.requesters_by_handle.get(&active) {
1203            for requester in requesters {
1204                for reader in focus_requester_read_subscribers(*requester) {
1205                    record_replay_boundary_invalidation_for_instance_key(reader);
1206                }
1207            }
1208        }
1209    }
1210
1211    pub(crate) fn is_requester_focus_visible(&self, id: FocusRequesterId) -> bool {
1212        self.owner_focused && self.focus_visible && self.state_of_requester(id).is_focused()
1213    }
1214
1215    pub(crate) fn state_of_requester(&self, id: FocusRequesterId) -> FocusState {
1216        self.requester_bindings
1217            .get(&id)
1218            .copied()
1219            .map(|handle_id| self.state_of(handle_id))
1220            .unwrap_or(FocusState::Inactive)
1221    }
1222
1223    pub(crate) fn request_focus_by_requester(&mut self, id: FocusRequesterId) {
1224        if let Some(handle_id) = self.requester_bindings.get(&id).copied() {
1225            self.request_focus(handle_id);
1226        }
1227    }
1228
1229    pub(crate) fn clear_focus_by_requester(&mut self, id: FocusRequesterId) {
1230        if let Some(handle_id) = self.requester_bindings.get(&id).copied() {
1231            self.clear_focus(handle_id);
1232        }
1233    }
1234
1235    pub(crate) fn capture_focus_by_requester(&mut self, id: FocusRequesterId) {
1236        if let Some(handle_id) = self.requester_bindings.get(&id).copied() {
1237            self.capture_focus(handle_id);
1238        }
1239    }
1240
1241    pub(crate) fn free_focus_by_requester(&mut self, id: FocusRequesterId) {
1242        if let Some(handle_id) = self.requester_bindings.get(&id).copied() {
1243            self.free_focus(handle_id);
1244        }
1245    }
1246
1247    pub(crate) fn request_focus(&mut self, id: FocusHandleId) {
1248        self.execute_or_defer(FocusCommand::Request(id));
1249    }
1250
1251    pub(crate) fn clear_focus(&mut self, id: FocusHandleId) {
1252        self.execute_or_defer(FocusCommand::Clear(id));
1253    }
1254
1255    pub(crate) fn capture_focus(&mut self, id: FocusHandleId) {
1256        self.execute_or_defer(FocusCommand::Capture(id));
1257    }
1258
1259    pub(crate) fn free_focus(&mut self, id: FocusHandleId) {
1260        self.execute_or_defer(FocusCommand::Free(id));
1261    }
1262
1263    pub(crate) fn restore_focus(&mut self, id: FocusHandleId) {
1264        self.execute_or_defer(FocusCommand::Restore(id));
1265    }
1266
1267    pub(crate) fn set_owner_focused(&mut self, focused: bool) {
1268        if self.owner_focused == focused {
1269            return;
1270        }
1271
1272        let previous_states = self.snapshot_live_states();
1273        self.owner_focused = focused;
1274        if !focused {
1275            self.pending_navigation = None;
1276        }
1277        if focused {
1278            if let Some(suspended) = self.suspended.take() {
1279                if let Some(target) = self.resolve_request_target(suspended) {
1280                    self.active = Some(target);
1281                    self.pending_reveal = Some(target);
1282                } else {
1283                    self.suspended = Some(suspended);
1284                }
1285            }
1286        } else {
1287            self.suspended = self.active;
1288            self.active = None;
1289            self.captured = None;
1290            self.pending_reveal = None;
1291        }
1292        self.recompute_states();
1293        self.notify_state_changes(previous_states);
1294    }
1295
1296    pub(crate) fn sync_changes(
1297        &mut self,
1298        tree: &ComponentNodeTree,
1299        changed: &HashSet<NodeId>,
1300        removed: &HashSet<NodeId>,
1301    ) {
1302        if changed.is_empty() && removed.is_empty() {
1303            return;
1304        }
1305        let previous_states = self.snapshot_live_states();
1306        let mut requesters = HashMap::default();
1307        for &node_id in removed.iter().chain(changed.iter()) {
1308            let Some(handle) = self.handles_by_component.remove(&node_id) else {
1309                continue;
1310            };
1311            if let Some(node) = self.nodes.get_mut(&handle) {
1312                if let Some(attachment) = node.attachment.take() {
1313                    if let Some(children) = self.children_by_parent.get_mut(&attachment.parent) {
1314                        if let Some(order) = self.order_paths.get(&handle) {
1315                            children.remove(&(order.clone(), handle));
1316                        }
1317                    }
1318                }
1319            }
1320            if let Some(bindings) = self.requesters_by_handle.remove(&handle) {
1321                for requester in bindings {
1322                    let previous = self.requester_bindings.remove(&requester);
1323                    requesters.entry(requester).or_insert(previous);
1324                }
1325            }
1326        }
1327        for &node_id in changed {
1328            let Some(node_ref) = tree.get(node_id).filter(|node| !node.is_removed()) else {
1329                continue;
1330            };
1331            let node = node_ref.get();
1332            let interaction = node.interaction();
1333            let Some(registration) = interaction.focus_registration else {
1334                continue;
1335            };
1336            let mut parent = ROOT_SCOPE_ID;
1337            let mut scope = ROOT_SCOPE_ID;
1338            for ancestor in node_id.ancestors(tree).skip(1) {
1339                if let Some(registration) = tree[ancestor].get().interaction().focus_registration {
1340                    if parent == ROOT_SCOPE_ID {
1341                        parent = registration.id;
1342                    }
1343                    if registration.kind == FocusRegistrationKind::Scope {
1344                        scope = registration.id;
1345                        break;
1346                    }
1347                }
1348            }
1349            let entry = self
1350                .nodes
1351                .entry(registration.id)
1352                .or_insert_with(|| FocusTreeNode::new(registration.kind));
1353            entry.kind = registration.kind;
1354            entry.last_parent = parent;
1355            entry.last_scope_parent = scope;
1356            entry.props = registration.properties;
1357            entry.traversal_policy = interaction.focus_traversal_policy;
1358            entry.restorer_fallback = (registration.kind == FocusRegistrationKind::Scope)
1359                .then(|| {
1360                    interaction
1361                        .focus_restorer_fallback
1362                        .map(|fallback| fallback.requester_id())
1363                })
1364                .flatten();
1365            entry.attachment = Some(FocusAttachment {
1366                host_replay_boundary_key: nearest_replay_boundary_instance_key(node_id, tree),
1367                live_node_id: Some(node_id),
1368                focus_rect: None,
1369                traversal_order: None,
1370                parent,
1371                scope_parent: scope,
1372            });
1373            self.handles_by_component.insert(node_id, registration.id);
1374            let order: Vec<_> = node_id
1375                .ancestors(tree)
1376                .filter(|id| tree[*id].parent().is_some())
1377                .map(|id| (u64::MAX, sibling_index(id, tree)))
1378                .collect::<Vec<_>>()
1379                .into_iter()
1380                .rev()
1381                .collect();
1382            self.order_paths.insert(registration.id, order.clone());
1383            self.children_by_parent
1384                .entry(parent)
1385                .or_default()
1386                .insert((order, registration.id), registration.id);
1387            self.children_by_parent.entry(registration.id).or_default();
1388            if let Some(requester) = interaction.focus_requester_binding {
1389                let requester = requester.requester_id();
1390                let previous = self.requester_bindings.insert(requester, registration.id);
1391                requesters.entry(requester).or_insert(previous);
1392                self.requesters_by_handle
1393                    .entry(registration.id)
1394                    .or_default()
1395                    .push(requester);
1396            }
1397        }
1398        self.repair_after_sync();
1399        self.recompute_states();
1400        self.notify_state_changes(previous_states);
1401        for (requester, previous) in requesters {
1402            if self.requester_bindings.get(&requester).copied() == previous {
1403                continue;
1404            }
1405            for reader in focus_requester_read_subscribers(requester) {
1406                record_replay_boundary_invalidation_for_instance_key(reader);
1407            }
1408        }
1409    }
1410
1411    pub(crate) fn sync_geometry_changes(
1412        &mut self,
1413        tree: &ComponentNodeTree,
1414        metadatas: &ComponentNodeMetaDatas,
1415        geometry_changed: &HashSet<NodeId>,
1416        structure_changed: &HashSet<NodeId>,
1417    ) {
1418        if (geometry_changed.is_empty() && structure_changed.is_empty())
1419            || (self.handles_by_component.is_empty() && self.active.is_none())
1420        {
1421            return;
1422        }
1423        for node_id in geometry_changed.union(structure_changed) {
1424            let Some(&handle) = self.handles_by_component.get(node_id) else {
1425                continue;
1426            };
1427            let rect = metadatas.get(node_id).and_then(|metadata| {
1428                let position = metadata.abs_position?;
1429                let size = metadata.computed_data?;
1430                let transform = metadata
1431                    .local_to_window
1432                    .unwrap_or_else(|| crate::LocalToWindow::new(1.0, position).unwrap());
1433                let rect = transform
1434                    .map_rect(crate::FloatRect::from_position_size(
1435                        PxPosition::ZERO,
1436                        PxSize::new(size.width, size.height),
1437                    ))
1438                    .outward();
1439                Some(metadata.event_clip_rect().map_or(rect, |clip| {
1440                    clip.intersection(&rect).unwrap_or(PxRect::ZERO)
1441                }))
1442            });
1443            if let Some(attachment) = self
1444                .nodes
1445                .get_mut(&handle)
1446                .and_then(|node| node.attachment.as_mut())
1447            {
1448                attachment.focus_rect = rect;
1449                if attachment.traversal_order.is_some()
1450                    && !metadatas.placement_order_changed.contains(node_id)
1451                {
1452                    continue;
1453                }
1454            }
1455            let mut order = node_id
1456                .ancestors(tree)
1457                .filter_map(|id| {
1458                    let node = tree.get(id)?;
1459                    node.parent()?;
1460                    if node.get().role != NodeRole::Layout
1461                        && node.get().interaction().focus_registration.is_none()
1462                    {
1463                        return None;
1464                    }
1465                    Some((
1466                        metadatas
1467                            .get(&id)
1468                            .and_then(|metadata| metadata.placement_order)
1469                            .unwrap_or(u64::MAX),
1470                        sibling_index(id, tree),
1471                    ))
1472                })
1473                .collect::<Vec<_>>();
1474            order.reverse();
1475            let order_changed = self.order_paths.get(&handle) != Some(&order);
1476            if let Some(attachment) = self
1477                .nodes
1478                .get_mut(&handle)
1479                .and_then(|node| node.attachment.as_mut())
1480            {
1481                attachment.focus_rect = rect;
1482                attachment.traversal_order = Some(0);
1483                if !order_changed {
1484                    continue;
1485                }
1486                let previous_order = self.order_paths.insert(handle, order.clone());
1487                let children = self
1488                    .children_by_parent
1489                    .entry(attachment.parent)
1490                    .or_default();
1491                if let Some(previous) = previous_order {
1492                    children.remove(&(previous, handle));
1493                }
1494                children.insert((order, handle), handle);
1495            }
1496        }
1497        if self.active.is_some_and(|id| {
1498            self.nodes.get(&id).is_some_and(|node| node.is_attached())
1499                && !self.can_request_focus(id)
1500        }) {
1501            let previous_states = self.snapshot_live_states();
1502            self.active = self
1503                .active
1504                .and_then(|id| self.restore_single_tab_stop_group(id));
1505            self.captured = None;
1506            self.pending_reveal = self.active;
1507            if let Some(active) = self.active {
1508                self.update_scope_restore_chain(active);
1509            }
1510            self.recompute_states();
1511            self.notify_state_changes(previous_states);
1512        }
1513    }
1514
1515    #[cfg(test)]
1516    pub(crate) fn sync_from_component_tree(&mut self, root_node: NodeId, tree: &ComponentNodeTree) {
1517        let changed = root_node.descendants(tree).collect::<HashSet<_>>();
1518        let removed = self
1519            .handles_by_component
1520            .keys()
1521            .copied()
1522            .filter(|node| !changed.contains(node))
1523            .collect();
1524        self.sync_changes(tree, &changed, &removed);
1525    }
1526
1527    #[cfg(test)]
1528    pub(crate) fn sync_layout_from_component_tree(
1529        &mut self,
1530        tree: &ComponentNodeTree,
1531        metadatas: &ComponentNodeMetaDatas,
1532    ) {
1533        let changed = self.handles_by_component.keys().copied().collect();
1534        self.sync_geometry_changes(tree, metadatas, &changed, &HashSet::default());
1535    }
1536
1537    pub(crate) fn commit_pending(&mut self) {
1538        if self.pending.is_empty() {
1539            return;
1540        }
1541
1542        let previous_states = self.snapshot_live_states();
1543        let commands = std::mem::take(&mut self.pending);
1544        for pending in commands {
1545            let reveal = self.pending_reveal;
1546            let applied = self.apply_command_inner(pending.command);
1547            if !pending.reveal {
1548                self.pending_reveal = reveal;
1549            }
1550            if !applied && self.should_defer_command(pending.command) {
1551                self.pending.push(pending);
1552            }
1553        }
1554        self.recompute_states();
1555        self.notify_state_changes(previous_states);
1556    }
1557
1558    pub(crate) fn take_pending_notifications(&mut self) -> Vec<FocusNotification> {
1559        std::mem::take(&mut self.pending_notifications)
1560    }
1561
1562    pub(crate) fn clear_focus_global(&mut self, force: bool) -> bool {
1563        if force || self.captured.is_none() {
1564            self.pending_navigation = None;
1565        }
1566        let previous_states = self.snapshot_live_states();
1567        let cleared = if self.active.is_some() && (force || self.captured.is_none()) {
1568            self.active = None;
1569            self.captured = None;
1570            self.pending_reveal = None;
1571            true
1572        } else {
1573            false
1574        };
1575        self.recompute_states();
1576        self.notify_state_changes(previous_states);
1577        cleared
1578    }
1579
1580    pub(crate) fn move_focus(&mut self, direction: FocusDirection) -> bool {
1581        if !self.owner_focused {
1582            return false;
1583        }
1584        let previous_states = self.snapshot_live_states();
1585        let target = match self.resolve_policy_move_target(direction) {
1586            Some(target) => target,
1587            None => self.resolve_move_target(direction),
1588        };
1589        let moved = target.is_some_and(|target| self.set_active(target));
1590        self.recompute_states();
1591        self.notify_state_changes_from(previous_states, Some(direction));
1592        moved
1593    }
1594
1595    pub(crate) fn move_focus_in_scope(
1596        &mut self,
1597        scope_id: FocusHandleId,
1598        direction: FocusDirection,
1599        wrap: bool,
1600    ) -> bool {
1601        if !self.owner_focused {
1602            return false;
1603        }
1604        let previous_states = self.snapshot_live_states();
1605        let moved = self
1606            .resolve_move_target_in_scope(scope_id, direction, wrap)
1607            .is_some_and(|target| self.set_active(target));
1608        self.recompute_states();
1609        self.notify_state_changes_from(previous_states, Some(direction));
1610        moved
1611    }
1612
1613    fn resolve_policy_move_target(
1614        &self,
1615        direction: FocusDirection,
1616    ) -> Option<Option<FocusHandleId>> {
1617        let active = self
1618            .active
1619            .filter(|current| self.can_request_focus(*current))?;
1620        let (owner_id, policy) = self.nearest_traversal_policy_owner(active)?;
1621        let scoped_direction = policy.scoped_direction(direction)?;
1622        let target = self.resolve_move_target_in_scope(owner_id, scoped_direction, policy.wrap);
1623        // Empty wrapping scopes still own traversal; an absent candidate must
1624        // not be interpreted as permission to navigate behind a modal.
1625        (target.is_some() || policy.wrap).then_some(target)
1626    }
1627
1628    fn nearest_traversal_policy_owner(
1629        &self,
1630        start: FocusHandleId,
1631    ) -> Option<(FocusHandleId, FocusTraversalPolicy)> {
1632        let mut current = Some(start);
1633        while let Some(id) = current {
1634            let node = self.nodes.get(&id)?;
1635            if matches!(
1636                node.kind,
1637                FocusRegistrationKind::Scope | FocusRegistrationKind::Group
1638            ) && let Some(policy) = node.traversal_policy
1639            {
1640                return Some((id, policy));
1641            }
1642            current = (id != ROOT_SCOPE_ID).then_some(node.last_parent);
1643        }
1644        None
1645    }
1646
1647    fn repair_after_sync(&mut self) {
1648        if self
1649            .active
1650            .is_some_and(|id| !self.nodes.get(&id).is_some_and(|node| node.is_attached()))
1651        {
1652            let previous_active = self.active;
1653            if previous_active
1654                .and_then(|id| self.restore_single_tab_stop_group(id))
1655                .is_some()
1656                || !previous_active.is_some_and(|id| self.should_wait_for_reattach(id))
1657            {
1658                let previous_active = self.active.take();
1659                self.active = previous_active.and_then(|id| self.restore_from_detached(id));
1660                self.captured = None;
1661                if let Some(active) = self.active {
1662                    self.update_scope_restore_chain(active);
1663                    self.pending_reveal = Some(active);
1664                }
1665            }
1666        }
1667
1668        if self
1669            .captured
1670            .is_some_and(|id| !self.nodes.get(&id).is_some_and(|node| node.is_attached()))
1671        {
1672            self.captured = None;
1673        }
1674
1675        if self.owner_focused
1676            && self.active.is_none()
1677            && let Some(suspended) = self.suspended
1678            && let Some(target) = self.resolve_request_target(suspended)
1679        {
1680            self.active = Some(target);
1681            self.suspended = None;
1682            self.pending_reveal = Some(target);
1683        }
1684
1685        if self.active.is_some_and(|id| {
1686            self.nodes.get(&id).is_some_and(|node| {
1687                node.is_attached() && (!self.can_focus(id) || !self.can_request_focus(id))
1688            })
1689        }) {
1690            self.active = self
1691                .active
1692                .and_then(|id| self.restore_single_tab_stop_group(id));
1693            self.captured = None;
1694            self.pending_reveal = self.active;
1695            if let Some(active) = self.active {
1696                self.update_scope_restore_chain(active);
1697            }
1698        }
1699    }
1700
1701    fn should_wait_for_reattach(&self, id: FocusHandleId) -> bool {
1702        let Some(node) = self.nodes.get(&id) else {
1703            return false;
1704        };
1705        if node.is_attached() {
1706            return false;
1707        }
1708        if has_persistent_focus_handle(id) {
1709            return true;
1710        }
1711        let waiting_scope_id = node.last_scope_parent;
1712        waiting_scope_id != ROOT_SCOPE_ID
1713            && self
1714                .nodes
1715                .get(&waiting_scope_id)
1716                .is_some_and(|scope| !scope.is_attached())
1717    }
1718
1719    pub(crate) fn remove_handles(
1720        &mut self,
1721        removed_handles: &HashSet<FocusHandleId>,
1722        removed_requesters: &HashSet<FocusRequesterId>,
1723    ) {
1724        if removed_handles.is_empty() && removed_requesters.is_empty() {
1725            return;
1726        }
1727
1728        let previous_states = self.snapshot_live_states();
1729        let mut previous_requester_bindings = HashMap::default();
1730        for requester_id in removed_requesters {
1731            if let Some(handle) = self.requester_bindings.remove(requester_id) {
1732                previous_requester_bindings.insert(*requester_id, handle);
1733                if let Some(requesters) = self.requesters_by_handle.get_mut(&handle) {
1734                    requesters.retain(|id| id != requester_id);
1735                }
1736            }
1737        }
1738        // Restore against survivors while retaining scope ancestry until
1739        // cleanup finishes.
1740        for handle_id in removed_handles {
1741            if let Some(node) = self.nodes.get_mut(handle_id) {
1742                node.attachment = None;
1743            }
1744        }
1745
1746        let active_was_removed = self.active.filter(|id| removed_handles.contains(id));
1747        if active_was_removed.is_some() {
1748            self.active = active_was_removed.and_then(|id| self.restore_from_detached(id));
1749            self.captured = None;
1750            if let Some(active) = self.active {
1751                self.update_scope_restore_chain(active);
1752                self.pending_reveal = Some(active);
1753            } else {
1754                self.pending_reveal = None;
1755            }
1756        }
1757
1758        if self
1759            .captured
1760            .is_some_and(|id| removed_handles.contains(&id))
1761        {
1762            self.captured = None;
1763        }
1764        if self
1765            .suspended
1766            .is_some_and(|id| removed_handles.contains(&id))
1767        {
1768            self.suspended = None;
1769        }
1770
1771        for handle_id in removed_handles {
1772            if let Some(node) = self.nodes.remove(handle_id) {
1773                if let Some(children) = self.children_by_parent.get_mut(&node.last_parent) {
1774                    if let Some(order) = self.order_paths.get(handle_id) {
1775                        children.remove(&(order.clone(), *handle_id));
1776                    }
1777                }
1778            }
1779            self.children_by_parent.remove(handle_id);
1780            self.stateful_handles.remove(handle_id);
1781            self.order_paths.remove(handle_id);
1782            if let Some(requesters) = self.requesters_by_handle.remove(handle_id) {
1783                for requester in requesters {
1784                    if let Some(handle) = self.requester_bindings.remove(&requester) {
1785                        previous_requester_bindings.insert(requester, handle);
1786                    }
1787                }
1788            }
1789        }
1790
1791        self.recompute_states();
1792        self.notify_state_changes(previous_states);
1793        self.notify_requester_binding_changes(previous_requester_bindings);
1794    }
1795
1796    fn execute_or_defer(&mut self, command: FocusCommand) {
1797        self.pending_navigation = None;
1798        if matches!(command, FocusCommand::Request(_) | FocusCommand::Restore(_)) {
1799            self.discard_pending_focus_requests();
1800        }
1801        if !self.apply_command(command) && self.should_defer_command(command) {
1802            self.pending.push(DeferredFocusCommand {
1803                command,
1804                reveal: true,
1805            });
1806        }
1807    }
1808
1809    fn discard_pending_focus_requests(&mut self) {
1810        self.pending.retain(|pending| {
1811            !matches!(
1812                pending.command,
1813                FocusCommand::Request(_) | FocusCommand::Restore(_)
1814            )
1815        });
1816    }
1817
1818    fn should_defer_command(&self, command: FocusCommand) -> bool {
1819        let id = match command {
1820            FocusCommand::Request(id)
1821            | FocusCommand::Clear(id)
1822            | FocusCommand::Capture(id)
1823            | FocusCommand::Free(id)
1824            | FocusCommand::Restore(id) => id,
1825        };
1826        // Attached targets treat commands as immediate intents. Replaying a
1827        // no-op or rejected command after another event can steal or clear
1828        // focus.
1829        !self.nodes.get(&id).is_some_and(|node| node.is_attached())
1830    }
1831
1832    fn apply_command(&mut self, command: FocusCommand) -> bool {
1833        let previous_states = self.snapshot_live_states();
1834        let applied = self.apply_command_inner(command);
1835        self.recompute_states();
1836        self.notify_state_changes(previous_states);
1837        applied
1838    }
1839
1840    fn apply_command_inner(&mut self, command: FocusCommand) -> bool {
1841        match command {
1842            FocusCommand::Request(id) => {
1843                if !self.owner_focused {
1844                    self.suspended = Some(id);
1845                    return true;
1846                }
1847                let Some(target) = self.resolve_request_target(id) else {
1848                    return false;
1849                };
1850                self.set_active(target)
1851            }
1852            FocusCommand::Clear(id) => self.clear_active_for(id),
1853            FocusCommand::Capture(id) => {
1854                if self.active == Some(id)
1855                    && self.nodes.get(&id).is_some_and(|node| node.is_attached())
1856                {
1857                    self.captured = Some(id);
1858                    true
1859                } else {
1860                    false
1861                }
1862            }
1863            FocusCommand::Free(id) => {
1864                if self.captured == Some(id) {
1865                    self.captured = None;
1866                    true
1867                } else {
1868                    false
1869                }
1870            }
1871            FocusCommand::Restore(id) => {
1872                let Some(target) = self.resolve_restore_candidate(id) else {
1873                    return false;
1874                };
1875                self.set_active(target)
1876            }
1877        }
1878    }
1879
1880    fn set_active(&mut self, target: FocusHandleId) -> bool {
1881        if self.captured.is_some() && self.captured != Some(target) {
1882            return false;
1883        }
1884        self.discard_pending_focus_requests();
1885        let changed = self.active != Some(target) || self.captured.is_some_and(|id| id != target);
1886        self.active = Some(target);
1887        if self.captured.is_some_and(|id| id != target) {
1888            self.captured = None;
1889        }
1890        self.update_scope_restore_chain(target);
1891        if changed {
1892            self.pending_reveal = Some(target);
1893        }
1894        changed
1895    }
1896
1897    fn clear_active_for(&mut self, id: FocusHandleId) -> bool {
1898        let Some(active) = self.active else {
1899            return false;
1900        };
1901        let affects_active = active == id || self.is_ancestor(id, active);
1902        if !affects_active {
1903            return false;
1904        }
1905        if self.captured.is_some() {
1906            return false;
1907        }
1908
1909        self.active = None;
1910        self.captured = None;
1911        self.pending_reveal = None;
1912        true
1913    }
1914
1915    fn resolve_move_target(&self, direction: FocusDirection) -> Option<FocusHandleId> {
1916        if let Some(active) = self.active
1917            && let Some(explicit) = self.resolve_explicit_direction_target(active, direction)
1918        {
1919            return Some(explicit);
1920        }
1921
1922        if matches!(
1923            direction,
1924            FocusDirection::Left
1925                | FocusDirection::Right
1926                | FocusDirection::Up
1927                | FocusDirection::Down
1928        ) && let Some(target) = self.resolve_geometric_move_target(direction)
1929        {
1930            return Some(target);
1931        }
1932
1933        let candidates = if matches!(direction, FocusDirection::Next | FocusDirection::Previous) {
1934            let mut candidates = Vec::new();
1935            self.collect_tab_focus_handles(ROOT_SCOPE_ID, &mut candidates);
1936            candidates
1937        } else {
1938            self.traversable_focus_handles()
1939        };
1940        if candidates.is_empty() {
1941            return None;
1942        }
1943
1944        let forward = matches!(
1945            direction,
1946            FocusDirection::Next
1947                | FocusDirection::Down
1948                | FocusDirection::Right
1949                | FocusDirection::Enter
1950        );
1951
1952        let Some(active) = self
1953            .active
1954            .filter(|current| self.can_request_focus(*current))
1955        else {
1956            return if forward {
1957                candidates.first().copied()
1958            } else {
1959                candidates.last().copied()
1960            };
1961        };
1962
1963        let Some(index) = candidates.iter().position(|candidate| *candidate == active) else {
1964            return if forward {
1965                candidates.first().copied()
1966            } else {
1967                candidates.last().copied()
1968            };
1969        };
1970
1971        if forward {
1972            candidates.get(index + 1).copied()
1973        } else if index > 0 {
1974            candidates.get(index - 1).copied()
1975        } else {
1976            None
1977        }
1978    }
1979
1980    fn resolve_move_target_in_scope(
1981        &self,
1982        scope_id: FocusHandleId,
1983        direction: FocusDirection,
1984        wrap: bool,
1985    ) -> Option<FocusHandleId> {
1986        let candidates = self.traversable_focus_handles_in_scope(scope_id);
1987        if candidates.is_empty() {
1988            return None;
1989        }
1990
1991        let active = self
1992            .active
1993            .filter(|current| self.can_request_focus(*current))
1994            .filter(|current| self.is_ancestor(scope_id, *current));
1995
1996        if let Some(active) = active
1997            && let Some(explicit) = self.resolve_explicit_direction_target(active, direction)
1998            && self.is_ancestor(scope_id, explicit)
1999        {
2000            return Some(explicit);
2001        }
2002
2003        if matches!(
2004            direction,
2005            FocusDirection::Left
2006                | FocusDirection::Right
2007                | FocusDirection::Up
2008                | FocusDirection::Down
2009        ) && let Some(target) =
2010            self.resolve_geometric_move_target_in_candidates(direction, &candidates, active)
2011        {
2012            return Some(target);
2013        }
2014
2015        let forward = matches!(
2016            direction,
2017            FocusDirection::Next
2018                | FocusDirection::Down
2019                | FocusDirection::Right
2020                | FocusDirection::Enter
2021        );
2022
2023        let Some(active) = active else {
2024            return if forward {
2025                candidates.first().copied()
2026            } else {
2027                candidates.last().copied()
2028            };
2029        };
2030
2031        let Some(index) = candidates.iter().position(|candidate| *candidate == active) else {
2032            return if forward {
2033                candidates.first().copied()
2034            } else {
2035                candidates.last().copied()
2036            };
2037        };
2038
2039        if forward {
2040            candidates.get(index + 1).copied().or_else(|| {
2041                wrap.then_some(candidates.first().copied())
2042                    .flatten()
2043                    .filter(|candidate| self.is_traversable_focus_handle(*candidate))
2044            })
2045        } else if index > 0 {
2046            candidates.get(index - 1).copied()
2047        } else if wrap {
2048            candidates
2049                .last()
2050                .copied()
2051                .filter(|candidate| self.is_traversable_focus_handle(*candidate))
2052        } else {
2053            None
2054        }
2055    }
2056
2057    fn resolve_geometric_move_target(&self, direction: FocusDirection) -> Option<FocusHandleId> {
2058        let active = self.active.and_then(|id| self.resolve_request_target(id))?;
2059        let focused_rect = self.nodes.get(&active)?.attachment?.focus_rect?;
2060        let mut best_candidate = initial_best_candidate_rect(focused_rect, direction);
2061        let mut best_handle = None;
2062
2063        for handle_id in self.traversable_focus_handles() {
2064            if handle_id == active {
2065                continue;
2066            }
2067            let Some(candidate_rect) = self
2068                .nodes
2069                .get(&handle_id)
2070                .and_then(|node| node.attachment)
2071                .and_then(|attachment| attachment.focus_rect)
2072            else {
2073                continue;
2074            };
2075            if !is_eligible_focus_rect(candidate_rect) {
2076                continue;
2077            }
2078            if is_better_focus_candidate(candidate_rect, best_candidate, focused_rect, direction) {
2079                best_candidate = candidate_rect;
2080                best_handle = Some(handle_id);
2081            }
2082        }
2083
2084        best_handle
2085    }
2086
2087    fn resolve_geometric_move_target_in_candidates(
2088        &self,
2089        direction: FocusDirection,
2090        candidates: &[FocusHandleId],
2091        active: Option<FocusHandleId>,
2092    ) -> Option<FocusHandleId> {
2093        let active = active?;
2094        let focused_rect = self.nodes.get(&active)?.attachment?.focus_rect?;
2095        let mut best_candidate = initial_best_candidate_rect(focused_rect, direction);
2096        let mut best_handle = None;
2097
2098        for &handle_id in candidates {
2099            if handle_id == active {
2100                continue;
2101            }
2102            let Some(candidate_rect) = self
2103                .nodes
2104                .get(&handle_id)
2105                .and_then(|node| node.attachment)
2106                .and_then(|attachment| attachment.focus_rect)
2107            else {
2108                continue;
2109            };
2110            if !is_eligible_focus_rect(candidate_rect) {
2111                continue;
2112            }
2113            if is_better_focus_candidate(candidate_rect, best_candidate, focused_rect, direction) {
2114                best_candidate = candidate_rect;
2115                best_handle = Some(handle_id);
2116            }
2117        }
2118
2119        best_handle
2120    }
2121
2122    fn resolve_request_target(&self, id: FocusHandleId) -> Option<FocusHandleId> {
2123        let node = self.nodes.get(&id)?;
2124        if !node.is_attached() {
2125            return None;
2126        }
2127        match node.kind {
2128            FocusRegistrationKind::Target => self.can_request_focus(id).then_some(id),
2129            FocusRegistrationKind::Scope => self
2130                .resolve_restore_candidate(id)
2131                .or_else(|| self.first_focusable_descendant(id))
2132                .or_else(|| self.can_request_focus(id).then_some(id)),
2133            FocusRegistrationKind::Group => self
2134                .first_focusable_descendant(id)
2135                .or_else(|| self.can_request_focus(id).then_some(id)),
2136        }
2137    }
2138
2139    fn resolve_requester_target(&self, requester_id: FocusRequesterId) -> Option<FocusHandleId> {
2140        self.requester_bindings.get(&requester_id).copied()
2141    }
2142
2143    fn resolve_explicit_direction_target(
2144        &self,
2145        id: FocusHandleId,
2146        direction: FocusDirection,
2147    ) -> Option<FocusHandleId> {
2148        let requester = self.nodes.get(&id).and_then(|node| match direction {
2149            FocusDirection::Next => node.props.next,
2150            FocusDirection::Previous => node.props.previous,
2151            FocusDirection::Up => node.props.up,
2152            FocusDirection::Down => node.props.down,
2153            FocusDirection::Left => node.props.left,
2154            FocusDirection::Right => node.props.right,
2155            FocusDirection::Enter => node.props.enter,
2156            FocusDirection::Exit => node.props.exit,
2157        })?;
2158        let handle_id = self.resolve_requester_target(requester.requester_id())?;
2159        self.resolve_request_target(handle_id)
2160    }
2161
2162    fn resolve_restore_candidate(&self, id: FocusHandleId) -> Option<FocusHandleId> {
2163        let scope = self.nodes.get(&id)?;
2164        if !scope.is_attached() || scope.kind != FocusRegistrationKind::Scope {
2165            return None;
2166        }
2167        scope
2168            .last_focused_descendant
2169            .filter(|candidate| *candidate != id && self.can_request_focus(*candidate))
2170            .or_else(|| {
2171                scope
2172                    .restorer_fallback
2173                    .and_then(|requester_id| self.resolve_requester_target(requester_id))
2174                    .and_then(|candidate| self.resolve_request_target(candidate))
2175            })
2176            .or_else(|| self.first_focusable_descendant(id))
2177    }
2178
2179    fn traversable_focus_handles(&self) -> Vec<FocusHandleId> {
2180        let mut ordered = Vec::new();
2181        self.collect_traversable_focus_handles(ROOT_SCOPE_ID, &mut ordered);
2182        ordered
2183    }
2184
2185    fn collect_tab_focus_handles(&self, parent: FocusHandleId, ordered: &mut Vec<FocusHandleId>) {
2186        let Some(children) = self.children_by_parent.get(&parent) else {
2187            return;
2188        };
2189        for &child in children.values() {
2190            if self.is_single_tab_stop_group(child) {
2191                let target = self
2192                    .active
2193                    .filter(|active| {
2194                        self.is_ancestor(child, *active) && self.can_request_focus(*active)
2195                    })
2196                    .or_else(|| self.tab_entry_target(child));
2197                if let Some(target) = target {
2198                    ordered.push(target);
2199                }
2200                continue;
2201            }
2202            if self.is_traversable_focus_handle(child)
2203                || (self.active == Some(child) && self.can_request_focus(child))
2204            {
2205                ordered.push(child);
2206            }
2207            self.collect_tab_focus_handles(child, ordered);
2208        }
2209    }
2210
2211    fn is_single_tab_stop_group(&self, id: FocusHandleId) -> bool {
2212        self.nodes.get(&id).is_some_and(|node| {
2213            node.is_attached()
2214                && matches!(
2215                    node.kind,
2216                    FocusRegistrationKind::Group | FocusRegistrationKind::Scope
2217                )
2218                && node
2219                    .traversal_policy
2220                    .is_some_and(|policy| policy.single_tab_stop)
2221        })
2222    }
2223
2224    fn tab_entry_target(&self, group: FocusHandleId) -> Option<FocusHandleId> {
2225        let mut candidates = Vec::new();
2226        self.collect_tab_focus_handles(group, &mut candidates);
2227        candidates
2228            .iter()
2229            .copied()
2230            .find(|id| {
2231                self.is_traversable_focus_handle(*id)
2232                    && self
2233                        .nodes
2234                        .get(id)
2235                        .is_some_and(|node| node.props.preferred_tab_stop)
2236            })
2237            .or_else(|| {
2238                candidates
2239                    .into_iter()
2240                    .find(|id| self.is_traversable_focus_handle(*id))
2241            })
2242    }
2243
2244    fn restore_single_tab_stop_group(&self, id: FocusHandleId) -> Option<FocusHandleId> {
2245        let mut current = self.nodes.get(&id).map(|node| node.last_parent);
2246        while let Some(parent) = current {
2247            if self.is_single_tab_stop_group(parent) {
2248                return self.tab_entry_target(parent);
2249            }
2250            current = self
2251                .nodes
2252                .get(&parent)
2253                .and_then(|node| (parent != ROOT_SCOPE_ID).then_some(node.last_parent));
2254        }
2255        None
2256    }
2257
2258    fn traversable_focus_handles_in_scope(&self, scope_id: FocusHandleId) -> Vec<FocusHandleId> {
2259        let mut ordered = Vec::new();
2260        self.collect_traversable_focus_handles(scope_id, &mut ordered);
2261        ordered
2262    }
2263
2264    fn collect_traversable_focus_handles(
2265        &self,
2266        parent: FocusHandleId,
2267        ordered: &mut Vec<FocusHandleId>,
2268    ) {
2269        let Some(children) = self.children_by_parent.get(&parent) else {
2270            return;
2271        };
2272        for &child in children.values() {
2273            // A skipped target can hold focus and must retain its position as a
2274            // traversal anchor.
2275            if self.is_traversable_focus_handle(child)
2276                || (self.active == Some(child) && self.can_request_focus(child))
2277            {
2278                ordered.push(child);
2279            }
2280            self.collect_traversable_focus_handles(child, ordered);
2281        }
2282    }
2283
2284    fn is_traversable_focus_handle(&self, id: FocusHandleId) -> bool {
2285        self.can_request_focus(id)
2286            && self
2287                .nodes
2288                .get(&id)
2289                .is_some_and(|node| !node.props.skip_traversal)
2290    }
2291
2292    fn first_focusable_descendant(&self, parent: FocusHandleId) -> Option<FocusHandleId> {
2293        let mut stack: Vec<_> = self
2294            .children_by_parent
2295            .get(&parent)
2296            .into_iter()
2297            .flat_map(|children| children.values().rev())
2298            .copied()
2299            .collect();
2300        while let Some(id) = stack.pop() {
2301            if self.can_request_focus(id) {
2302                return Some(id);
2303            }
2304            if let Some(children) = self.children_by_parent.get(&id) {
2305                stack.extend(children.values().rev().copied());
2306            }
2307        }
2308        None
2309    }
2310
2311    fn restore_from_detached(&self, id: FocusHandleId) -> Option<FocusHandleId> {
2312        if let Some(target) = self.restore_single_tab_stop_group(id) {
2313            return Some(target);
2314        }
2315        let mut current_scope = self.nodes.get(&id).map(|node| node.last_scope_parent)?;
2316        loop {
2317            if current_scope == ROOT_SCOPE_ID {
2318                break;
2319            }
2320            if let Some(candidate) = self.resolve_restore_candidate(current_scope) {
2321                return Some(candidate);
2322            }
2323            current_scope = self
2324                .nodes
2325                .get(&current_scope)
2326                .map(|node| node.last_scope_parent)
2327                .unwrap_or(ROOT_SCOPE_ID);
2328        }
2329        None
2330    }
2331
2332    fn update_scope_restore_chain(&mut self, target: FocusHandleId) {
2333        let mut current = Some(target);
2334        while let Some(id) = current {
2335            if let Some(node) = self.nodes.get_mut(&id)
2336                && node.kind == FocusRegistrationKind::Scope
2337            {
2338                node.last_focused_descendant = Some(target);
2339            }
2340            if id == ROOT_SCOPE_ID {
2341                break;
2342            }
2343            current = self
2344                .nodes
2345                .get(&id)
2346                .and_then(|node| node.attachment)
2347                .map(|attachment| attachment.scope_parent);
2348            if current == Some(id) {
2349                break;
2350            }
2351        }
2352        if let Some(root) = self.nodes.get_mut(&ROOT_SCOPE_ID) {
2353            root.last_focused_descendant = Some(target);
2354        }
2355    }
2356
2357    fn snapshot_live_states(&self) -> HashMap<FocusHandleId, FocusState> {
2358        self.stateful_handles
2359            .iter()
2360            .filter_map(|&id| {
2361                self.nodes
2362                    .get(&id)
2363                    .filter(|node| node.is_attached())
2364                    .map(|node| (id, node.state))
2365            })
2366            .collect()
2367    }
2368
2369    fn notify_requester_binding_changes(
2370        &self,
2371        previous_bindings: HashMap<FocusRequesterId, FocusHandleId>,
2372    ) {
2373        let mut changed = HashSet::default();
2374        for (&requester_id, &previous_handle_id) in &previous_bindings {
2375            let current = self.requester_bindings.get(&requester_id).copied();
2376            if current != Some(previous_handle_id) {
2377                changed.insert(requester_id);
2378            }
2379        }
2380        for requester_id in changed {
2381            for reader in focus_requester_read_subscribers(requester_id) {
2382                record_replay_boundary_invalidation_for_instance_key(reader);
2383            }
2384        }
2385    }
2386
2387    fn notify_state_changes(&mut self, previous_states: HashMap<FocusHandleId, FocusState>) {
2388        self.notify_state_changes_from(previous_states, None);
2389    }
2390
2391    fn notify_state_changes_from(
2392        &mut self,
2393        previous_states: HashMap<FocusHandleId, FocusState>,
2394        direction: Option<FocusDirection>,
2395    ) {
2396        let mut changed = HashSet::default();
2397        let mut events = HashSet::default();
2398        let mut changed_requesters = HashSet::default();
2399
2400        for (&id, &previous) in &previous_states {
2401            let current = self
2402                .nodes
2403                .get(&id)
2404                .filter(|node| node.is_attached())
2405                .map(|node| node.state)
2406                .unwrap_or(FocusState::Inactive);
2407            if previous != current {
2408                changed.insert(id);
2409            }
2410            if previous.has_focus() {
2411                events.insert(id);
2412            }
2413        }
2414
2415        for &id in &self.stateful_handles {
2416            let Some(node) = self.nodes.get(&id) else {
2417                continue;
2418            };
2419            if !node.is_attached() {
2420                continue;
2421            }
2422            let previous = previous_states
2423                .get(&id)
2424                .copied()
2425                .unwrap_or(FocusState::Inactive);
2426            if previous != node.state {
2427                changed.insert(id);
2428            }
2429            if node.state.has_focus() {
2430                events.insert(id);
2431            }
2432        }
2433
2434        for &id in &changed {
2435            let state = self
2436                .nodes
2437                .get(&id)
2438                .filter(|node| node.is_attached())
2439                .map(|node| node.state)
2440                .unwrap_or(FocusState::Inactive);
2441            self.pending_notifications.push(FocusNotification {
2442                handle_id: id,
2443                state,
2444                changed: true,
2445                direction,
2446            });
2447            for reader in focus_read_subscribers(id) {
2448                record_replay_boundary_invalidation_for_instance_key(reader);
2449            }
2450            if let Some(node) = self.nodes.get(&id)
2451                && let Some(attachment) = node.attachment
2452                && attachment.host_replay_boundary_key != 0
2453            {
2454                record_replay_boundary_invalidation_for_instance_key(
2455                    attachment.host_replay_boundary_key,
2456                );
2457            }
2458            if let Some(requesters) = self.requesters_by_handle.get(&id) {
2459                changed_requesters.extend(requesters.iter().copied());
2460            }
2461        }
2462
2463        for id in events {
2464            if changed.contains(&id) {
2465                continue;
2466            }
2467            let state = self
2468                .nodes
2469                .get(&id)
2470                .filter(|node| node.is_attached())
2471                .map(|node| node.state)
2472                .unwrap_or(FocusState::Inactive);
2473            self.pending_notifications.push(FocusNotification {
2474                handle_id: id,
2475                state,
2476                changed: false,
2477                direction,
2478            });
2479        }
2480
2481        for requester_id in changed_requesters {
2482            for reader in focus_requester_read_subscribers(requester_id) {
2483                record_replay_boundary_invalidation_for_instance_key(reader);
2484            }
2485        }
2486    }
2487
2488    fn recompute_states(&mut self) {
2489        for id in self.stateful_handles.drain() {
2490            if let Some(node) = self.nodes.get_mut(&id) {
2491                node.state = FocusState::Inactive;
2492            }
2493        }
2494        let Some(active) = self.active else {
2495            return;
2496        };
2497        if !self
2498            .nodes
2499            .get(&active)
2500            .is_some_and(|node| node.is_attached())
2501        {
2502            return;
2503        }
2504
2505        let mut current = Some(active);
2506        let active_state = if self.captured == Some(active) {
2507            FocusState::Captured
2508        } else {
2509            FocusState::Active
2510        };
2511        let mut first = true;
2512        while let Some(id) = current {
2513            if let Some(node) = self.nodes.get_mut(&id)
2514                && node.is_attached()
2515            {
2516                self.stateful_handles.insert(id);
2517                node.state = if first {
2518                    active_state
2519                } else {
2520                    FocusState::ActiveParent
2521                };
2522            }
2523            if id == ROOT_SCOPE_ID {
2524                break;
2525            }
2526            current = self
2527                .nodes
2528                .get(&id)
2529                .and_then(|node| node.attachment)
2530                .map(|attachment| attachment.parent);
2531            first = false;
2532        }
2533    }
2534
2535    fn can_focus(&self, id: FocusHandleId) -> bool {
2536        self.nodes.get(&id).is_some_and(|node| {
2537            node.attachment.is_some_and(FocusAttachment::permits_focus) && node.props.can_focus
2538        })
2539    }
2540
2541    fn can_request_focus(&self, id: FocusHandleId) -> bool {
2542        self.can_focus(id)
2543            && self
2544                .nodes
2545                .get(&id)
2546                .is_some_and(|node| node.props.can_request_focus)
2547    }
2548
2549    fn is_ancestor(&self, ancestor: FocusHandleId, descendant: FocusHandleId) -> bool {
2550        let mut current = Some(descendant);
2551        while let Some(id) = current {
2552            if id == ancestor {
2553                return true;
2554            }
2555            if id == ROOT_SCOPE_ID {
2556                break;
2557            }
2558            current = self
2559                .nodes
2560                .get(&id)
2561                .and_then(|node| node.attachment)
2562                .map(|attachment| attachment.parent);
2563        }
2564        false
2565    }
2566}
2567
2568fn is_eligible_focus_rect(rect: PxRect) -> bool {
2569    rect.width.0 > 0 && rect.height.0 > 0
2570}
2571
2572fn initial_best_candidate_rect(focused_rect: PxRect, direction: FocusDirection) -> PxRect {
2573    match direction {
2574        FocusDirection::Left => PxRect::new(
2575            focused_rect.x + focused_rect.width + crate::Px::new(1),
2576            focused_rect.y,
2577            focused_rect.width,
2578            focused_rect.height,
2579        ),
2580        FocusDirection::Right => PxRect::new(
2581            focused_rect.x - focused_rect.width - crate::Px::new(1),
2582            focused_rect.y,
2583            focused_rect.width,
2584            focused_rect.height,
2585        ),
2586        FocusDirection::Up => PxRect::new(
2587            focused_rect.x,
2588            focused_rect.y + focused_rect.height + crate::Px::new(1),
2589            focused_rect.width,
2590            focused_rect.height,
2591        ),
2592        FocusDirection::Down => PxRect::new(
2593            focused_rect.x,
2594            focused_rect.y - focused_rect.height - crate::Px::new(1),
2595            focused_rect.width,
2596            focused_rect.height,
2597        ),
2598        _ => focused_rect,
2599    }
2600}
2601
2602fn is_better_focus_candidate(
2603    proposed_candidate: PxRect,
2604    current_candidate: PxRect,
2605    focused_rect: PxRect,
2606    direction: FocusDirection,
2607) -> bool {
2608    if !is_focus_candidate(proposed_candidate, focused_rect, direction) {
2609        return false;
2610    }
2611    if !is_focus_candidate(current_candidate, focused_rect, direction) {
2612        return true;
2613    }
2614    if focus_beam_beats(
2615        focused_rect,
2616        proposed_candidate,
2617        current_candidate,
2618        direction,
2619    ) {
2620        return true;
2621    }
2622    if focus_beam_beats(
2623        focused_rect,
2624        current_candidate,
2625        proposed_candidate,
2626        direction,
2627    ) {
2628        return false;
2629    }
2630    weighted_focus_distance(proposed_candidate, focused_rect, direction)
2631        < weighted_focus_distance(current_candidate, focused_rect, direction)
2632}
2633
2634fn is_focus_candidate(rect: PxRect, focused_rect: PxRect, direction: FocusDirection) -> bool {
2635    match direction {
2636        FocusDirection::Left => {
2637            (focused_rect_right(focused_rect) > focused_rect_right(rect)
2638                || focused_rect.x >= focused_rect_right(rect))
2639                && focused_rect.x > rect.x
2640        }
2641        FocusDirection::Right => {
2642            (focused_rect.x < rect.x || focused_rect_right(focused_rect) <= rect.x)
2643                && focused_rect_right(focused_rect) < focused_rect_right(rect)
2644        }
2645        FocusDirection::Up => {
2646            (focused_rect_bottom(focused_rect) > focused_rect_bottom(rect)
2647                || focused_rect.y >= focused_rect_bottom(rect))
2648                && focused_rect.y > rect.y
2649        }
2650        FocusDirection::Down => {
2651            (focused_rect.y < rect.y || focused_rect_bottom(focused_rect) <= rect.y)
2652                && focused_rect_bottom(focused_rect) < focused_rect_bottom(rect)
2653        }
2654        _ => false,
2655    }
2656}
2657
2658fn weighted_focus_distance(rect: PxRect, focused_rect: PxRect, direction: FocusDirection) -> i64 {
2659    let major = major_axis_distance(rect, focused_rect, direction);
2660    let minor = minor_axis_distance(rect, focused_rect, direction);
2661    13 * major * major + minor * minor
2662}
2663
2664fn focus_beam_beats(
2665    source: PxRect,
2666    rect1: PxRect,
2667    rect2: PxRect,
2668    direction: FocusDirection,
2669) -> bool {
2670    if rect2_in_source_beam(rect2, source, direction)
2671        || !rect2_in_source_beam(rect1, source, direction)
2672    {
2673        return false;
2674    }
2675    if !is_in_direction_of_search(rect2, source, direction) {
2676        return true;
2677    }
2678    if matches!(direction, FocusDirection::Left | FocusDirection::Right) {
2679        return true;
2680    }
2681    major_axis_distance(rect1, source, direction)
2682        < major_axis_distance_to_far_edge(rect2, source, direction)
2683}
2684
2685fn rect2_in_source_beam(rect: PxRect, source: PxRect, direction: FocusDirection) -> bool {
2686    match direction {
2687        FocusDirection::Left | FocusDirection::Right => {
2688            focused_rect_bottom(rect) > source.y && rect.y < focused_rect_bottom(source)
2689        }
2690        FocusDirection::Up | FocusDirection::Down => {
2691            focused_rect_right(rect) > source.x && rect.x < focused_rect_right(source)
2692        }
2693        _ => false,
2694    }
2695}
2696
2697fn is_in_direction_of_search(rect: PxRect, source: PxRect, direction: FocusDirection) -> bool {
2698    match direction {
2699        FocusDirection::Left => source.x >= focused_rect_right(rect),
2700        FocusDirection::Right => focused_rect_right(source) <= rect.x,
2701        FocusDirection::Up => source.y >= focused_rect_bottom(rect),
2702        FocusDirection::Down => focused_rect_bottom(source) <= rect.y,
2703        _ => false,
2704    }
2705}
2706
2707fn major_axis_distance(rect: PxRect, focused_rect: PxRect, direction: FocusDirection) -> i64 {
2708    let distance = match direction {
2709        FocusDirection::Left => focused_rect.x.0 - focused_rect_right(rect).0,
2710        FocusDirection::Right => rect.x.0 - focused_rect_right(focused_rect).0,
2711        FocusDirection::Up => focused_rect.y.0 - focused_rect_bottom(rect).0,
2712        FocusDirection::Down => rect.y.0 - focused_rect_bottom(focused_rect).0,
2713        _ => 0,
2714    };
2715    i64::from(distance.max(0))
2716}
2717
2718fn major_axis_distance_to_far_edge(rect: PxRect, source: PxRect, direction: FocusDirection) -> i64 {
2719    let distance = match direction {
2720        FocusDirection::Left => source.x.0 - rect.x.0,
2721        FocusDirection::Right => focused_rect_right(rect).0 - focused_rect_right(source).0,
2722        FocusDirection::Up => source.y.0 - rect.y.0,
2723        FocusDirection::Down => focused_rect_bottom(rect).0 - focused_rect_bottom(source).0,
2724        _ => 1,
2725    };
2726    i64::from(distance.max(1))
2727}
2728
2729fn minor_axis_distance(rect: PxRect, focused_rect: PxRect, direction: FocusDirection) -> i64 {
2730    let focused_center = match direction {
2731        FocusDirection::Left | FocusDirection::Right => {
2732            focused_rect.y.0 + focused_rect.height.0 / 2
2733        }
2734        FocusDirection::Up | FocusDirection::Down => focused_rect.x.0 + focused_rect.width.0 / 2,
2735        _ => 0,
2736    };
2737    let candidate_center = match direction {
2738        FocusDirection::Left | FocusDirection::Right => rect.y.0 + rect.height.0 / 2,
2739        FocusDirection::Up | FocusDirection::Down => rect.x.0 + rect.width.0 / 2,
2740        _ => 0,
2741    };
2742    i64::from(focused_center - candidate_center)
2743}
2744
2745fn focused_rect_right(rect: PxRect) -> crate::Px {
2746    rect.x + rect.width
2747}
2748
2749fn focused_rect_bottom(rect: PxRect) -> crate::Px {
2750    rect.y + rect.height
2751}
2752
2753pub(crate) fn flush_pending_focus_callbacks() {
2754    let callbacks = TesseraRuntime::with_mut(|runtime| {
2755        runtime
2756            .component_tree
2757            .take_pending_focus_callback_invocations()
2758    });
2759    for callback in callbacks {
2760        callback.invoke();
2761    }
2762}