1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
// SPDX-License-Identifier: MPL-2.0
// SPDX-FileCopyrightText: 2026 FernTech
/// How focus was acquired — used for `:focus-visible` behavior.
/// Only show focus ring when focus was gained via keyboard, not pointer click.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FocusOrigin {
/// Focus gained via Tab/Shift-Tab keyboard navigation.
Keyboard,
/// Focus gained via pointer click.
Pointer,
/// Focus set programmatically by the application.
Programmatic,
}
/// Policy for a focus **traversal scope**, declared via the `FocusScope`
/// wrapper widget. Controls what Tab / Shift+Tab does when it reaches the
/// scope's ends.
///
/// A scope groups + scopes the `tab_index` numbering of its descendants:
/// two sibling scopes that both number their children `1, 2, 3` never
/// interleave — each scope is an independent, ordered unit within its
/// parent. This is Teksilo's analogue of Flutter `FocusTraversalGroup` /
/// WPF `KeyboardNavigation.TabNavigation`.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TraversalScopePolicy {
/// Tab flows *out* of the scope at its ends into the enclosing scope's
/// next member. The scope groups `tab_index` numbering without trapping
/// focus — use for logical regions in a continuous Tab order (e.g. dock
/// panels, where each panel numbers its own controls without colliding
/// with sibling panels).
Continue,
/// Tab *wraps* within the scope and never exits via keyboard navigation.
/// Use for modal dialogs — the one surface whose pattern (ARIA's Dialog
/// (Modal)) actually calls for containing focus.
///
/// **Not for popovers or menus.** Those implement Disclosure and Menu,
/// which mandate the opposite: Tab is an exit gesture there, and the
/// framework already answers it by dismissing the overlay focus leaves
/// rather than by trapping focus inside it. Wrapping such an overlay in a
/// `Cycle` scope defeats that — focus can no longer leave, so the
/// dismissal never fires and the panel becomes keyboard-inescapable except
/// via Escape.
Cycle,
}