pub fn manage_dialog_lifecycle(
commands: Commands<'_, '_>,
tracker: ResMut<'_, FocusTracker>,
dialogs: Query<'_, '_, (Entity, Option<&Visible>, Option<&mut DialogSession>, Option<&LumenId>, &IfMarker), With<DialogMarker>>,
children: Query<'_, '_, &Children>,
parents: Query<'_, '_, &ChildOf>,
focusables: Query<'_, '_, (&TabIndex, Option<&DocumentOrder>), Without<Disabled>>,
autofocused: Query<'_, '_, Option<&DocumentOrder>, (With<AutoFocus>, Without<Disabled>)>,
focus_visibles: Query<'_, '_, (), With<FocusVisible>>,
live: Query<'_, '_, Entity, Without<IsResource>>,
closed_out: MessageWriter<'_, DialogClosed>,
)Expand description
Qt QDialog lifecycle (W5): initial focus on open, focus restore on close, and the exactly-once accepted/rejected close event.
Open edge (Visible flips true):
- remember the current focus holder,
- focus the first
autofocusdescendant; else the first focusable (TabIndex >= 0, enabled) descendant in markup order; else the dialog panel itself. The body mounts via deferred commands one tick after the edge, so the pass retries (needs_focus) until a target exists.
Close edge:
- emit exactly one
lumen_core::input::DialogClosed-acceptedwhen the default button drove the close (DialogSession::pending_accept),rejectedotherwise (Escape, cancel buttons, script writes), - restore focus to the pre-open holder when focus still sits
inside the dialog subtree (a close caused by focusing another
widget doesn’t yank focus back) - mirrors
lumen_primitives::popup_nav_lifecycle.
The Tab focus trap itself is lumen_input::cycle_focus_on_tab +
the FocusBoundary the spawner puts on every <dialog>.