select, list: Update searchable default to false. (#1504)
Continue #1503 to update the `searchable` default to `false`.
This commit is contained in:
parent
2870bc6e36
commit
087cb70d00
7 changed files with 37 additions and 31 deletions
|
|
@ -304,6 +304,7 @@ impl DrawerStory {
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
List::new(&list)
|
List::new(&list)
|
||||||
|
.searchable(true)
|
||||||
.border_1()
|
.border_1()
|
||||||
.border_color(cx.theme().border)
|
.border_color(cx.theme().border)
|
||||||
.rounded(cx.theme().radius)
|
.rounded(cx.theme().radius)
|
||||||
|
|
|
||||||
|
|
@ -536,6 +536,7 @@ impl Render for ListStory {
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
List::new(&self.company_list)
|
List::new(&self.company_list)
|
||||||
|
.searchable(true)
|
||||||
.p(px(8.))
|
.p(px(8.))
|
||||||
.flex_1()
|
.flex_1()
|
||||||
.w_full()
|
.w_full()
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,7 @@ impl Render for SelectStory {
|
||||||
.child(
|
.child(
|
||||||
section("Select").max_w_128().child(
|
section("Select").max_w_128().child(
|
||||||
Select::new(&self.country_select)
|
Select::new(&self.country_select)
|
||||||
|
.searchable(true)
|
||||||
.search_placeholder("Search country by name or code")
|
.search_placeholder("Search country by name or code")
|
||||||
.cleanable()
|
.cleanable()
|
||||||
.disabled(self.disabled),
|
.disabled(self.disabled),
|
||||||
|
|
@ -199,6 +200,7 @@ impl Render for SelectStory {
|
||||||
.child(
|
.child(
|
||||||
section("Searchable").max_w_128().child(
|
section("Searchable").max_w_128().child(
|
||||||
Select::new(&self.fruit_select)
|
Select::new(&self.fruit_select)
|
||||||
|
.searchable(true)
|
||||||
.disabled(self.disabled)
|
.disabled(self.disabled)
|
||||||
.icon(IconName::Search)
|
.icon(IconName::Search)
|
||||||
.w(px(320.))
|
.w(px(320.))
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ impl Default for ListOptions {
|
||||||
scrollbar_visible: true,
|
scrollbar_visible: true,
|
||||||
max_height: None,
|
max_height: None,
|
||||||
selectable: true,
|
selectable: true,
|
||||||
searchable: true,
|
searchable: false,
|
||||||
search_placeholder: None,
|
search_placeholder: None,
|
||||||
paddings: EdgesRefinement::default(),
|
paddings: EdgesRefinement::default(),
|
||||||
}
|
}
|
||||||
|
|
@ -70,9 +70,9 @@ impl Default for ListOptions {
|
||||||
|
|
||||||
/// The state for List.
|
/// The state for List.
|
||||||
pub struct ListState<D: ListDelegate> {
|
pub struct ListState<D: ListDelegate> {
|
||||||
focus_handle: FocusHandle,
|
pub(crate) focus_handle: FocusHandle,
|
||||||
|
pub(crate) query_input: Entity<InputState>,
|
||||||
options: ListOptions,
|
options: ListOptions,
|
||||||
query_input: Option<Entity<InputState>>,
|
|
||||||
delegate: D,
|
delegate: D,
|
||||||
last_query: Option<String>,
|
last_query: Option<String>,
|
||||||
scroll_handle: VirtualListScrollHandle,
|
scroll_handle: VirtualListScrollHandle,
|
||||||
|
|
@ -104,7 +104,7 @@ where
|
||||||
options: ListOptions::default(),
|
options: ListOptions::default(),
|
||||||
delegate,
|
delegate,
|
||||||
rows_cache: RowsCache::default(),
|
rows_cache: RowsCache::default(),
|
||||||
query_input: Some(query_input),
|
query_input,
|
||||||
last_query: None,
|
last_query: None,
|
||||||
selected_index: None,
|
selected_index: None,
|
||||||
item_to_measure_index: IndexPath::default(),
|
item_to_measure_index: IndexPath::default(),
|
||||||
|
|
@ -131,6 +131,11 @@ where
|
||||||
self.focus_handle(cx).focus(window);
|
self.focus_handle(cx).focus(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return true if either the list or the search input is focused.
|
||||||
|
pub(crate) fn is_focused(&self, window: &Window, cx: &App) -> bool {
|
||||||
|
self.focus_handle.is_focused(window) || self.query_input.focus_handle(cx).is_focused(window)
|
||||||
|
}
|
||||||
|
|
||||||
/// Set the selected index of the list,
|
/// Set the selected index of the list,
|
||||||
/// this will also scroll to the selected item.
|
/// this will also scroll to the selected item.
|
||||||
pub(crate) fn _set_selected_index(
|
pub(crate) fn _set_selected_index(
|
||||||
|
|
@ -254,10 +259,8 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_searching(&mut self, searching: bool, window: &mut Window, cx: &mut Context<Self>) {
|
fn set_searching(&mut self, searching: bool, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
if let Some(input) = &self.query_input {
|
self.query_input
|
||||||
input.update(cx, |input, cx| input.set_loading(searching, window, cx))
|
.update(cx, |input, cx| input.set_loading(searching, window, cx));
|
||||||
}
|
|
||||||
cx.notify();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dispatch delegate's `load_more` method when the
|
/// Dispatch delegate's `load_more` method when the
|
||||||
|
|
@ -523,12 +526,8 @@ where
|
||||||
D: ListDelegate,
|
D: ListDelegate,
|
||||||
{
|
{
|
||||||
fn focus_handle(&self, cx: &App) -> FocusHandle {
|
fn focus_handle(&self, cx: &App) -> FocusHandle {
|
||||||
if !self.options.searchable {
|
if self.options.searchable {
|
||||||
return self.focus_handle.clone();
|
self.query_input.focus_handle(cx)
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(query_input) = &self.query_input {
|
|
||||||
query_input.focus_handle(cx)
|
|
||||||
} else {
|
} else {
|
||||||
self.focus_handle.clone()
|
self.focus_handle.clone()
|
||||||
}
|
}
|
||||||
|
|
@ -552,16 +551,12 @@ where
|
||||||
let loading = self.delegate().loading(cx);
|
let loading = self.delegate().loading(cx);
|
||||||
let query_input = if self.options.searchable {
|
let query_input = if self.options.searchable {
|
||||||
// sync placeholder
|
// sync placeholder
|
||||||
if let Some(query_input) = &self.query_input {
|
if let Some(placeholder) = &self.options.search_placeholder {
|
||||||
if let Some(placeholder) = &self.options.search_placeholder {
|
self.query_input.update(cx, |input, cx| {
|
||||||
query_input.update(cx, |input, cx| {
|
input.set_placeholder(placeholder.clone(), window, cx);
|
||||||
input.set_placeholder(placeholder.clone(), window, cx);
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
Some(query_input.clone())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
|
Some(self.query_input.clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
@ -591,7 +586,7 @@ where
|
||||||
.size_full()
|
.size_full()
|
||||||
.relative()
|
.relative()
|
||||||
.overflow_hidden()
|
.overflow_hidden()
|
||||||
.when_some(query_input.clone(), |this, input| {
|
.when_some(query_input, |this, input| {
|
||||||
this.child(
|
this.child(
|
||||||
div()
|
div()
|
||||||
.map(|this| match self.options.size {
|
.map(|this| match self.options.size {
|
||||||
|
|
@ -670,7 +665,7 @@ where
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets whether the list is searchable, default is `true`.
|
/// Sets whether the list is searchable, default is `false`.
|
||||||
///
|
///
|
||||||
/// When `true`, there will be a search input at the top of the list.
|
/// When `true`, there will be a search input at the top of the list.
|
||||||
pub fn searchable(mut self, searchable: bool) -> Self {
|
pub fn searchable(mut self, searchable: bool) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -324,7 +324,7 @@ impl Default for SelectOptions {
|
||||||
menu_width: Length::Auto,
|
menu_width: Length::Auto,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
appearance: true,
|
appearance: true,
|
||||||
searchable: true,
|
searchable: false,
|
||||||
search_placeholder: None,
|
search_placeholder: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -559,9 +559,12 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
let list = cx.new(|cx| ListState::new(delegate, window, cx).reset_on_cancel(false));
|
let list = cx.new(|cx| ListState::new(delegate, window, cx).reset_on_cancel(false));
|
||||||
|
let list_focus_handle = list.read(cx).focus_handle.clone();
|
||||||
|
let list_search_focus_handle = list.read(cx).query_input.focus_handle(cx);
|
||||||
|
|
||||||
let _subscriptions = vec![
|
let _subscriptions = vec![
|
||||||
cx.on_blur(&list.focus_handle(cx), window, Self::on_blur),
|
cx.on_blur(&list_focus_handle, window, Self::on_blur),
|
||||||
|
cx.on_blur(&list_search_focus_handle, window, Self::on_blur),
|
||||||
cx.on_blur(&focus_handle, window, Self::on_blur),
|
cx.on_blur(&focus_handle, window, Self::on_blur),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -645,7 +648,7 @@ where
|
||||||
|
|
||||||
fn on_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
fn on_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
// When the select and dropdown menu are both not focused, close the dropdown menu.
|
// When the select and dropdown menu are both not focused, close the dropdown menu.
|
||||||
if self.list.focus_handle(cx).is_focused(window) || self.focus_handle.is_focused(window) {
|
if self.list.read(cx).is_focused(window, cx) || self.focus_handle.is_focused(window) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -954,7 +957,7 @@ where
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets whether the dropdown menu is searchable, default is `true`.
|
/// Sets whether the dropdown menu is searchable, default is `false`.
|
||||||
///
|
///
|
||||||
/// When `true`, there will be a search input at the top of the dropdown menu.
|
/// When `true`, there will be a search input at the top of the dropdown menu.
|
||||||
pub fn searchable(mut self, searchable: bool) -> Self {
|
pub fn searchable(mut self, searchable: bool) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -171,6 +171,8 @@ fn render_item(
|
||||||
|
|
||||||
The list automatically includes a search input by default. Implement `perform_search` to handle queries:
|
The list automatically includes a search input by default. Implement `perform_search` to handle queries:
|
||||||
|
|
||||||
|
And you should use `searchable(true)` when creating the list to show search input.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
impl ListDelegate for MyListDelegate {
|
impl ListDelegate for MyListDelegate {
|
||||||
fn perform_search(
|
fn perform_search(
|
||||||
|
|
@ -190,9 +192,8 @@ impl ListDelegate for MyListDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create list without search input
|
|
||||||
let state = cx.new(|cx| ListState::new(delegate, window, cx));
|
let state = cx.new(|cx| ListState::new(delegate, window, cx));
|
||||||
List::new(&state).searchable(false)
|
List::new(&state).searchable(true)
|
||||||
```
|
```
|
||||||
|
|
||||||
### List with Loading State
|
### List with Loading State
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,8 @@ Select::new(&state)
|
||||||
|
|
||||||
### Searchable
|
### Searchable
|
||||||
|
|
||||||
|
Use `searchable(true)` to enable search functionality within the dropdown.
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let fruits = SearchableVec::new(vec![
|
let fruits = SearchableVec::new(vec![
|
||||||
"Apple", "Orange", "Banana", "Grape", "Pineapple",
|
"Apple", "Orange", "Banana", "Grape", "Pineapple",
|
||||||
|
|
@ -75,6 +77,7 @@ let state = cx.new(|cx| {
|
||||||
});
|
});
|
||||||
|
|
||||||
Select::new(&state)
|
Select::new(&state)
|
||||||
|
.searchable(true)
|
||||||
.icon(IconName::Search) // Shows search icon
|
.icon(IconName::Search) // Shows search icon
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue