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