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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
//! Moving keyboard focus from Rust: a handle a widget is bound to, and a request that
//! puts focus on that widget's node.
use Cell;
use fmt;
use Rc;
use cratewith_composer_if_idle;
/// What a handle and the composition share: the node the handle is bound to, 0 while it
/// is bound to none, and whether a request for it is waiting for the next batch.
pub
/// A way to put keyboard focus on one widget. Compose's `FocusRequester`.
///
/// Make one with [`use_focus_handle`], give it to a widget with `.focus_handle(&handle)`,
/// and call [`FocusHandle::request`] from a handler or an effect. Cloning is cheap: every
/// clone is the same handle. The handle follows its widget's node across re-renders, and
/// when the widget is replaced by a new node, it follows the new one.
///
/// A drawer that takes focus when it opens and gives it back to the control that opened
/// it when Escape closes it:
///
/// ```ignore
/// use compose_rust::runtime::*;
/// use compose_rust::ui::*;
///
/// #[Composable]
/// fn Screen() {
/// let open = remember(|| mutable_state_of(false));
/// let opener = use_focus_handle();
/// let drawer = use_focus_handle();
/// Column().content(|| {
/// Button("Menu")
/// .focus_handle(&opener)
/// .on_click(move || open.set(true));
/// if open.get() {
/// let back = opener.clone();
/// Column()
/// .focus_handle(&drawer)
/// .on_key_down(move |key| {
/// if key.text() == "Escape" {
/// key.consume();
/// open.set(false);
/// back.request();
/// }
/// })
/// .content(|| {
/// Text("Drawer");
/// });
/// }
/// });
/// // The drawer's node exists once the composition that opened it is applied, so
/// // the request runs as an effect of that composition rather than in the click.
/// let take = drawer.clone();
/// let is_open = open.get();
/// launched_effect(is_open, move || async move {
/// if is_open {
/// take.request();
/// }
/// });
/// }
/// ```
///
/// A request made while the handle's node is not on screen does nothing and is not kept
/// for later, which is why the drawer above asks from an effect.
/// A focus handle this call site keeps across compositions. Compose's
/// `remember { FocusRequester() }`.
/// Binds `handle` to the node the widget being composed is about to create or update.
/// Called right before the widget's `emit`.
pub