Onboarding · Flows and highlights: focus that holds as the flow turns, a tip that closes
navigation::Wizard keeps one focus handle for Next and Finish, so a second press on the step before last finishes; Back that reaches the first step, and a finished step picked by key, hand focus to Next. Popover::with_opener hands its content a close that gives focus back: Got it closes the hotspot's tip before the owner hides it, and the event details close before Edit and Delete run, so focus never lands on a panel that left the tree. The wizard's count and the setup checklist's tally name their selectors after their words, and the bar takes the count's own value.
This commit is contained in:
1 parent
eea99b8e41
commit
1879f6f08b
15 files changed
+180
-54
No files matched your search
+14
-7
@@ -12,7 +12,7 @@ use crate::{
|
||||
theme::ControlSize,
|
||||
};
|
||||
|
||||
type Content = Box<dyn FnOnce(&mut Window, &mut App) -> AnyElement>;
|
||||
type Content = Box<dyn FnOnce(Run, &mut Window, &mut App) -> AnyElement>;
|
||||
type Own = Box<dyn FnOnce(Run) -> AnyElement>;
|
||||
|
||||
/// A popover's own button: its label and look.
|
||||
@@ -73,20 +73,22 @@ impl Popover {
|
||||
variant: ButtonVariant::Secondary,
|
||||
size: ControlSize::default(),
|
||||
}),
|
||||
content: Box::new(move |window, cx| content(window, cx).into_any_element()),
|
||||
content: Box::new(move |_, window, cx| content(window, cx).into_any_element()),
|
||||
}
|
||||
}
|
||||
|
||||
/// A panel that opens from an element of the owner's: `opener` builds it with the run that opens and closes the panel.
|
||||
/// A panel that opens from an element of the owner's: `opener` builds it with the run that opens and closes the panel, and `content` gets the run that closes it and hands focus back, for a press that ends the panel's work.
|
||||
pub fn with_opener<T: IntoElement, E: IntoElement>(
|
||||
id: impl Into<ElementId>,
|
||||
opener: impl FnOnce(Run) -> T + 'static,
|
||||
content: impl FnOnce(&mut Window, &mut App) -> E + 'static,
|
||||
content: impl FnOnce(Run, &mut Window, &mut App) -> E + 'static,
|
||||
) -> Self {
|
||||
Self {
|
||||
id: id.into(),
|
||||
opener: Opener::Own(Box::new(move |toggle| opener(toggle).into_any_element())),
|
||||
content: Box::new(move |window, cx| content(window, cx).into_any_element()),
|
||||
content: Box::new(move |close, window, cx| {
|
||||
content(close, window, cx).into_any_element()
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -179,9 +181,14 @@ impl RenderOnce for Popover {
|
||||
close(&state, window, cx);
|
||||
return host;
|
||||
}
|
||||
let (escape, out, tall) = (state.clone(), state.clone(), state.clone());
|
||||
let (escape, out, tall, done) =
|
||||
(state.clone(), state.clone(), state.clone(), state.clone());
|
||||
let (anchor, height) = (state.read(cx).host, state.read(cx).height);
|
||||
let body = (self.content)(window, cx);
|
||||
let body = (self.content)(
|
||||
Rc::new(move |window, cx| close(&done, window, cx)),
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
let panel = div()
|
||||
.id((self.id.clone(), "panel"))
|
||||
.relative()
|
||||
|
||||
@@ -430,5 +430,5 @@ fn a_tall_dialog_body_keeps_its_height_and_scrolls(cx: &mut TestAppContext) {
|
||||
#[test]
|
||||
#[should_panic(expected = "an icon is for its own button")]
|
||||
fn a_popover_opened_by_its_owner_takes_no_icon() {
|
||||
let _ = Popover::with_opener("own", |_| div(), |_, _| div()).icon(IconName::Clock);
|
||||
let _ = Popover::with_opener("own", |_| div(), |_, _, _| div()).icon(IconName::Clock);
|
||||
}
|
||||
Reference in new issue
Block a user