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
//! Implicit-detach event dispatch.
//!
//! When the focused or hovered element is detached from the tree
//! (directly or because an ancestor is being removed), browsers
//! dispatch a small ceremony of events:
//!
//! - **Focus loss:** `blur` (non-bubbling) + `focusout` (bubbles)
//! on the previously-focused element.
//! - **Hover loss:** `mouseout` (bubbles) + `mouseleave` (non-
//! bubbling) on the previously-hovered element.
//!
//! These events fire BEFORE the actual removal in the DOM event
//! model, so bubbling works through the still-intact ancestor
//! chain. `rdom-core::tree::detach_from_parent` emits a
//! `Mutation::PreDetach` record before structural unlink for
//! exactly this hook: this module installs an observer that
//! listens for `PreDetach` and dispatches the appropriate events
//! via the normal `TuiDispatchExt` pipeline, which still walks
//! the live parent chain at the moment of the observer callback.
//!
//! Installed once from `App::with_backend`. No public surface — the
//! observer is opaque; consumers register their own `blur`/
//! `focusout`/`mouseout`/`mouseleave` listeners on whichever
//! nodes they care about and get fired automatically.
//!
//! ## Reentrancy notes for listener authors
//!
//! Handlers run DURING `detach_from_parent`, in the window between
//! the `PreDetach` mutation record firing and the structural
//! unlink. The tree is still intact at that moment. Implications:
//!
//! - **Mutating the tree from a handler is allowed.** Setting
//! focus elsewhere, appending nodes, removing siblings — all
//! work.
//! - **Re-attaching the about-to-be-detached subtree does NOT
//! cancel the in-flight detach.** After every handler in the
//! ceremony returns, `detach_from_parent` proceeds with the
//! structural unlink of the original target. A handler that
//! appends the focused subtree to a different parent will
//! see that re-attachment torn out again immediately.
//! - **A handler that calls `dom.set_focused(another_node)`
//! during `blur`** works as expected — the second
//! `InteractionChanged` record fires the cascade pickup; the
//! purge step then sees that `focused` is no longer in the
//! subtree and skips clearing it.
use Mutation;
use crate::;
/// Observer that translates `Mutation::PreDetach` records into
/// the implicit DOM events browsers fire when the focused or
/// hovered element is removed.
pub ;
/// Install the implicit-detach observer on `dom`. Called once
/// during `App::with_backend`.
pub