Kit · K02: Tab binds under FocusScope's ElyFocus context, so a deeper context's Tab wins
This commit is contained in:
1 parent
c61a5b22b0
commit
a9b30c7eab
7 files changed
+58
-11
No files matched your search
+3
-3
@@ -50,7 +50,7 @@ pub use assets::Assets;
|
||||
use anyhow::Context as _;
|
||||
use gpui::{App, KeyBinding};
|
||||
|
||||
use crate::primitives::{FocusNext, FocusPrev, IconName};
|
||||
use crate::primitives::{FOCUS_CONTEXT, FocusNext, FocusPrev, IconName};
|
||||
|
||||
/// Loads fonts and the theme, binds Tab and text keys. Call once, first.
|
||||
pub fn init(cx: &mut App) -> anyhow::Result<()> {
|
||||
@@ -76,8 +76,8 @@ pub fn init_for_tests(cx: &mut App) {
|
||||
fn setup(cx: &mut App) {
|
||||
theme::Theme::init(cx);
|
||||
cx.bind_keys([
|
||||
KeyBinding::new("tab", FocusNext, None),
|
||||
KeyBinding::new("shift-tab", FocusPrev, None),
|
||||
KeyBinding::new("tab", FocusNext, Some(FOCUS_CONTEXT)),
|
||||
KeyBinding::new("shift-tab", FocusPrev, Some(FOCUS_CONTEXT)),
|
||||
]);
|
||||
forms::bind_keys(cx);
|
||||
editor::bind_keys(cx);
|
||||
|
||||
@@ -8,6 +8,9 @@ use crate::theme::ActiveTheme;
|
||||
|
||||
actions!(ely, [FocusNext, FocusPrev]);
|
||||
|
||||
/// The key context of every `FocusScope`; Tab and Shift-Tab bind under it.
|
||||
pub(crate) const CONTEXT: &str = "ElyFocus";
|
||||
|
||||
/// Focus-colored border while focused. Give the element a 1px border.
|
||||
pub trait FocusRing: InteractiveElement + Sized {
|
||||
fn focus_ring(self, cx: &App) -> Self {
|
||||
@@ -30,7 +33,7 @@ pub struct FocusScope {
|
||||
impl FocusScope {
|
||||
pub fn new(handle: &FocusHandle) -> Self {
|
||||
Self {
|
||||
base: div().track_focus(handle),
|
||||
base: div().key_context(CONTEXT).track_focus(handle),
|
||||
handle: handle.clone(),
|
||||
trap: false,
|
||||
root: false,
|
||||
|
||||
@@ -20,8 +20,10 @@ pub use disclosure::Disclosure;
|
||||
pub use divider::Divider;
|
||||
pub use files::IconTheme;
|
||||
pub(crate) use files::{file_icon, icon_theme};
|
||||
pub(crate) use focus::{
|
||||
CONTEXT as FOCUS_CONTEXT, Takeover, give_back, hand_back, hold_focus, tab_stop, take_focus,
|
||||
};
|
||||
pub use focus::{FocusNext, FocusPrev, FocusRing, FocusScope};
|
||||
pub(crate) use focus::{Takeover, give_back, hand_back, hold_focus, tab_stop, take_focus};
|
||||
pub use ghost::DragGhost;
|
||||
pub use icon::{Icon, IconName};
|
||||
pub use image::Image;
|
||||
|
||||
+44
-3
@@ -1,11 +1,11 @@
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
use gpui::{
|
||||
App, Context, Entity, FocusHandle, IntoElement, Modifiers, ParentElement, Render, RenderOnce,
|
||||
Styled, TestAppContext, Window, anchored, div, point, prelude::*, px,
|
||||
App, Context, Entity, FocusHandle, IntoElement, KeyBinding, Modifiers, ParentElement, Render,
|
||||
RenderOnce, Styled, TestAppContext, Window, actions, anchored, div, point, prelude::*, px,
|
||||
};
|
||||
|
||||
use super::raise;
|
||||
use super::{FocusScope, raise};
|
||||
use crate::theme::Theme;
|
||||
|
||||
/// A raised square holding a raised button, under a cover drawn after it in the same layer.
|
||||
@@ -130,3 +130,44 @@ fn a_raise_keeps_its_state_while_another_comes_before_it(cx: &mut TestAppContext
|
||||
"the box kept focus"
|
||||
);
|
||||
}
|
||||
|
||||
actions!(host, [Indent]);
|
||||
|
||||
/// A root scope around a field whose own context binds Tab.
|
||||
struct Field {
|
||||
root: FocusHandle,
|
||||
field: FocusHandle,
|
||||
indents: usize,
|
||||
}
|
||||
|
||||
impl Render for Field {
|
||||
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
||||
let view = cx.entity();
|
||||
FocusScope::new(&self.root).root().size_full().child(
|
||||
div()
|
||||
.key_context("HostField")
|
||||
.track_focus(&self.field)
|
||||
.size(px(100.0))
|
||||
.on_action(move |_: &Indent, _, cx| view.update(cx, |field, _| field.indents += 1)),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn a_deeper_context_keeps_its_own_tab_whatever_init_ran_last(cx: &mut TestAppContext) {
|
||||
cx.update(|cx| {
|
||||
cx.bind_keys([KeyBinding::new("tab", Indent, Some("HostField"))]);
|
||||
crate::init_for_tests(cx);
|
||||
});
|
||||
let (view, cx) = cx.add_window_view(|_, cx| Field {
|
||||
root: cx.focus_handle(),
|
||||
field: cx.focus_handle(),
|
||||
indents: 0,
|
||||
});
|
||||
cx.update(|window, cx| {
|
||||
let field = view.read(cx).field.clone();
|
||||
window.focus(&field, cx);
|
||||
});
|
||||
cx.simulate_keystrokes("tab");
|
||||
assert_eq!(view.read_with(cx, |field, _| field.indents), 1);
|
||||
}
|
||||
Reference in new issue
Block a user