Skip to content

Commit 8298fa0

Browse files
committed
feat: allow free input in AutoComplete
1 parent 396e654 commit 8298fa0

File tree

1 file changed

+39
-16
lines changed

1 file changed

+39
-16
lines changed

thaw/src/auto_complete/mod.rs

+39-16
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ pub fn AutoComplete(
3333
#[prop(optional, into)] clear_after_select: MaybeSignal<bool>,
3434
#[prop(optional, into)] on_select: Option<Callback<String>>,
3535
#[prop(optional, into)] disabled: MaybeSignal<bool>,
36+
#[prop(optional, into)] allow_free_input: bool,
3637
#[prop(optional, into)] invalid: MaybeSignal<bool>,
3738
#[prop(optional, into)] class: OptionalProp<MaybeSignal<String>>,
3839
#[prop(optional)] auto_complete_prefix: Option<AutoCompletePrefix>,
@@ -57,13 +58,15 @@ pub fn AutoComplete(
5758
css_vars
5859
});
5960

60-
let select_option_index = create_rw_signal::<usize>(0);
61+
let default_index = if allow_free_input { None } else { Some(0) };
62+
63+
let select_option_index = create_rw_signal::<Option<usize>>(default_index);
6164
let menu_ref = create_node_ref::<html::Div>();
6265
let is_show_menu = create_rw_signal(false);
6366
let auto_complete_ref = create_node_ref::<html::Div>();
6467
let options = StoredMaybeSignal::from(options);
6568
let open_menu = move || {
66-
select_option_index.set(0);
69+
select_option_index.set(default_index);
6770
is_show_menu.set(true);
6871
};
6972
let allow_value = move |_| {
@@ -82,39 +85,59 @@ pub fn AutoComplete(
8285
if let Some(on_select) = on_select {
8386
on_select.call(option_value);
8487
}
88+
if allow_free_input {
89+
select_option_index.set(None);
90+
}
8591
is_show_menu.set(false);
8692
};
8793

94+
// we unset selection index whenever options get changed
95+
// otherwise e.g. selection could move from one item to
96+
// another staying on the same index
97+
create_effect(move |_| {
98+
options.get();
99+
select_option_index.set(default_index);
100+
});
101+
88102
let on_keydown = move |event: ev::KeyboardEvent| {
89103
if !is_show_menu.get_untracked() {
90104
return;
91105
}
92106
let key = event.key();
93107
if key == *"ArrowDown" {
94108
select_option_index.update(|index| {
95-
if *index == options.with_untracked(|options| options.len()) - 1 {
96-
*index = 0
109+
if *index == Some(options.with_untracked(|options| options.len()) - 1) {
110+
*index = default_index
97111
} else {
98-
*index += 1
112+
*index = Some(index.map_or(0, |index| index + 1))
99113
}
100114
});
101115
} else if key == *"ArrowUp" {
102116
select_option_index.update(|index| {
103-
if *index == 0 {
104-
*index = options.with_untracked(|options| options.len()) - 1;
117+
if *index == Some(0) {
118+
if allow_free_input {
119+
*index = None
120+
} else {
121+
*index = Some(options.with_untracked(|options| options.len()) - 1);
122+
}
105123
} else {
106-
*index -= 1
124+
*index = index.map(|index| index - 1)
107125
}
108126
});
109127
} else if key == *"Enter" {
110128
event.prevent_default();
111129
let option_value = options.with_untracked(|options| {
112130
let index = select_option_index.get_untracked();
113-
if options.len() > index {
114-
let option = &options[index];
115-
Some(option.value.clone())
116-
} else {
117-
None
131+
match index {
132+
None if allow_free_input => {
133+
let value = value.get_untracked();
134+
(!value.is_empty()).then_some(value)
135+
}
136+
Some(index) if options.len() > index => {
137+
let option = &options[index];
138+
Some(option.value.clone())
139+
}
140+
_ => None,
118141
}
119142
});
120143
if let Some(option_value) = option_value {
@@ -189,13 +212,13 @@ pub fn AutoComplete(
189212
select_value(option_value.clone());
190213
};
191214
let on_mouseenter = move |_| {
192-
select_option_index.set(index);
215+
select_option_index.set(Some(index));
193216
};
194217
let on_mousedown = move |ev: ev::MouseEvent| {
195218
ev.prevent_default();
196219
};
197220
create_effect(move |_| {
198-
if index == select_option_index.get() {
221+
if Some(index) == select_option_index.get() {
199222
if !is_show_menu.get() {
200223
return;
201224
}
@@ -218,7 +241,7 @@ pub fn AutoComplete(
218241
class="thaw-auto-complete__menu-item"
219242
class=(
220243
"thaw-auto-complete__menu-item--selected",
221-
move || index == select_option_index.get(),
244+
move || Some(index) == select_option_index.get(),
222245
)
223246

224247
on:click=on_click

0 commit comments

Comments
 (0)