parent
b3f62bf096
commit
e86f90d309
5 changed files with 83 additions and 16 deletions
|
|
@ -1,15 +1,25 @@
|
|||
use gpui::{
|
||||
px, IntoElement, ParentElement, Render, SharedString, Styled, View, ViewContext, VisualContext,
|
||||
WindowContext,
|
||||
actions, px, AppContext, InteractiveElement, IntoElement, KeyBinding, ParentElement, Render,
|
||||
SharedString, Styled, View, ViewContext, VisualContext, WindowContext,
|
||||
};
|
||||
|
||||
use ui::{
|
||||
dropdown::{Dropdown, DropdownEvent, DropdownItem, SearchableVec},
|
||||
h_flex,
|
||||
theme::ActiveTheme,
|
||||
v_flex, IconName, Sizable,
|
||||
v_flex, FocusableCycle, IconName, Sizable,
|
||||
};
|
||||
|
||||
actions!(dropdown_story, [Tab, TabPrev]);
|
||||
|
||||
const CONTEXT: &str = "DropdownStory";
|
||||
pub fn init(cx: &mut AppContext) {
|
||||
cx.bind_keys([
|
||||
KeyBinding::new("shift-tab", TabPrev, Some(CONTEXT)),
|
||||
KeyBinding::new("tab", Tab, Some(CONTEXT)),
|
||||
])
|
||||
}
|
||||
|
||||
struct Country {
|
||||
name: SharedString,
|
||||
code: SharedString,
|
||||
|
|
@ -138,11 +148,39 @@ impl DropdownStory {
|
|||
DropdownEvent::Confirm(value) => println!("Selected country: {:?}", value),
|
||||
}
|
||||
}
|
||||
|
||||
fn on_key_tab(&mut self, _: &Tab, cx: &mut ViewContext<Self>) {
|
||||
self.cycle_focus(true, cx);
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn on_key_shift_tab(&mut self, _: &TabPrev, cx: &mut ViewContext<Self>) {
|
||||
self.cycle_focus(false, cx);
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
impl FocusableCycle for DropdownStory {
|
||||
fn cycle_focus_handles(&self, cx: &mut ViewContext<Self>) -> Vec<gpui::FocusHandle>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
vec![
|
||||
self.country_dropdown.focus_handle(cx),
|
||||
self.fruit_dropdown.focus_handle(cx),
|
||||
self.simple_dropdown1.focus_handle(cx),
|
||||
self.simple_dropdown2.focus_handle(cx),
|
||||
self.simple_dropdown3.focus_handle(cx),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for DropdownStory {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
v_flex()
|
||||
.key_context(CONTEXT)
|
||||
.on_action(cx.listener(Self::on_key_tab))
|
||||
.on_action(cx.listener(Self::on_key_shift_tab))
|
||||
.size_full()
|
||||
.gap_4()
|
||||
.child(
|
||||
|
|
|
|||
|
|
@ -17,10 +17,12 @@ use crate::section;
|
|||
|
||||
actions!(input_story, [Tab, TabPrev]);
|
||||
|
||||
const CONTEXT: &str = "InputStory";
|
||||
|
||||
pub fn init(cx: &mut AppContext) {
|
||||
cx.bind_keys([
|
||||
KeyBinding::new("shift-tab", TabPrev, Some("InputStory")),
|
||||
KeyBinding::new("tab", Tab, Some("InputStory")),
|
||||
KeyBinding::new("shift-tab", TabPrev, Some(CONTEXT)),
|
||||
KeyBinding::new("tab", Tab, Some(CONTEXT)),
|
||||
])
|
||||
}
|
||||
|
||||
|
|
@ -204,7 +206,7 @@ impl FocusableCycle for InputStory {
|
|||
impl Render for InputStory {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
v_flex()
|
||||
.key_context("InputStory")
|
||||
.key_context(CONTEXT)
|
||||
.on_action(cx.listener(Self::tab))
|
||||
.on_action(cx.listener(Self::tab_prev))
|
||||
.size_full()
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ use ui::{divider::Divider, h_flex, label::Label, v_flex};
|
|||
|
||||
pub fn init(cx: &mut AppContext) {
|
||||
input_story::init(cx);
|
||||
dropdown_story::init(cx);
|
||||
}
|
||||
|
||||
pub fn section(title: impl IntoElement, cx: &WindowContext) -> Div {
|
||||
|
|
|
|||
|
|
@ -81,3 +81,8 @@ DatePicker:
|
|||
en: Select date
|
||||
zh-CN: 选择日期
|
||||
zh-HK: 選擇日期
|
||||
Dropdown:
|
||||
placeholder:
|
||||
en: "Please select"
|
||||
zh-CN: "请选择"
|
||||
zh-HK: "請選擇"
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use gpui::{
|
|||
Render, SharedString, StatefulInteractiveElement, Styled, Task, View, ViewContext,
|
||||
VisualContext, WeakView, WindowContext,
|
||||
};
|
||||
use rust_i18n::t;
|
||||
|
||||
use crate::{
|
||||
h_flex,
|
||||
|
|
@ -16,13 +17,14 @@ use crate::{
|
|||
|
||||
actions!(dropdown, [Up, Down, Enter, Escape]);
|
||||
|
||||
const CONTEXT: &str = "Dropdown";
|
||||
|
||||
pub fn init(cx: &mut AppContext) {
|
||||
let context = Some("Dropdown");
|
||||
cx.bind_keys([
|
||||
KeyBinding::new("up", Up, context),
|
||||
KeyBinding::new("down", Down, context),
|
||||
KeyBinding::new("enter", Enter, context),
|
||||
KeyBinding::new("escape", Escape, context),
|
||||
KeyBinding::new("up", Up, Some(CONTEXT)),
|
||||
KeyBinding::new("down", Down, Some(CONTEXT)),
|
||||
KeyBinding::new("enter", Enter, Some(CONTEXT)),
|
||||
KeyBinding::new("escape", Escape, Some(CONTEXT)),
|
||||
])
|
||||
}
|
||||
|
||||
|
|
@ -301,6 +303,7 @@ where
|
|||
selected_index: Option<usize>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Self {
|
||||
let focus_handle = cx.focus_handle();
|
||||
let delegate = DropdownListDelegate {
|
||||
delegate,
|
||||
dropdown: cx.view().downgrade(),
|
||||
|
|
@ -316,10 +319,14 @@ where
|
|||
}
|
||||
list
|
||||
});
|
||||
|
||||
cx.on_blur(&list.focus_handle(cx), Self::on_blur).detach();
|
||||
cx.on_blur(&focus_handle, Self::on_blur).detach();
|
||||
|
||||
let mut this = Self {
|
||||
id: id.into(),
|
||||
focus_handle: cx.focus_handle(),
|
||||
placeholder: "Select...".into(),
|
||||
focus_handle,
|
||||
placeholder: t!("Dropdown.placeholder").into(),
|
||||
list,
|
||||
size: Size::Medium,
|
||||
icon: None,
|
||||
|
|
@ -427,6 +434,16 @@ where
|
|||
self.focus_handle.focus(cx);
|
||||
}
|
||||
|
||||
fn on_blur(&mut self, cx: &mut ViewContext<Self>) {
|
||||
// When the dropdown and dropdown menu are both not focused, close the dropdown menu.
|
||||
if self.list.focus_handle(cx).is_focused(cx) || self.focus_handle.is_focused(cx) {
|
||||
return;
|
||||
}
|
||||
|
||||
self.open = false;
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn up(&mut self, _: &Up, cx: &mut ViewContext<Self>) {
|
||||
if !self.open {
|
||||
return;
|
||||
|
|
@ -514,8 +531,12 @@ impl<D> FocusableView for Dropdown<D>
|
|||
where
|
||||
D: DropdownDelegate + 'static,
|
||||
{
|
||||
fn focus_handle(&self, _cx: &AppContext) -> FocusHandle {
|
||||
self.focus_handle.clone()
|
||||
fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
|
||||
if self.open {
|
||||
self.list.focus_handle(cx)
|
||||
} else {
|
||||
self.focus_handle.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -531,7 +552,7 @@ where
|
|||
|
||||
div()
|
||||
.id(self.id.clone())
|
||||
.key_context("Dropdown")
|
||||
.key_context(CONTEXT)
|
||||
.track_focus(&self.focus_handle)
|
||||
.on_action(cx.listener(Self::up))
|
||||
.on_action(cx.listener(Self::down))
|
||||
|
|
|
|||
Loading…
Reference in a new issue