feat(typeahead_input): add focus management for input fields and enhance initialization
This commit is contained in:
parent
8cfef276df
commit
eeb8e100e8
2 changed files with 174 additions and 143 deletions
src/components
|
@ -143,6 +143,11 @@ pub fn ItemsList(
|
||||||
let (property_cache, set_property_cache) = create_signal(HashMap::<String, HashMap<String, String>>::new());
|
let (property_cache, set_property_cache) = create_signal(HashMap::<String, HashMap<String, String>>::new());
|
||||||
|
|
||||||
let (suggestions, set_suggestions) = create_signal(Vec::<WikidataSuggestion>::new());
|
let (suggestions, set_suggestions) = create_signal(Vec::<WikidataSuggestion>::new());
|
||||||
|
|
||||||
|
// Add a state to track which input field should be focused after re-render
|
||||||
|
let (focus_index, set_focus_index) = create_signal(None::<usize>);
|
||||||
|
let (adding_new_row, set_adding_new_row) = create_signal(false);
|
||||||
|
|
||||||
#[cfg(feature = "ssr")]
|
#[cfg(feature = "ssr")]
|
||||||
fn get_current_url() -> String {
|
fn get_current_url() -> String {
|
||||||
use leptos::use_context;
|
use leptos::use_context;
|
||||||
|
@ -755,9 +760,15 @@ pub fn ItemsList(
|
||||||
let update_item = {
|
let update_item = {
|
||||||
let set_items = set_items.clone();
|
let set_items = set_items.clone();
|
||||||
let current_url = Rc::clone(¤t_url);
|
let current_url = Rc::clone(¤t_url);
|
||||||
|
let set_focus_index = set_focus_index.clone();
|
||||||
|
let set_adding_new_row = set_adding_new_row.clone();
|
||||||
|
|
||||||
Arc::new(move |index: usize, field: &str, value: String| {
|
Arc::new(move |index: usize, field: &str, value: String| {
|
||||||
let set_items = set_items.clone();
|
let set_items = set_items.clone();
|
||||||
let current_url = Rc::clone(¤t_url);
|
let current_url = Rc::clone(¤t_url);
|
||||||
|
let set_focus_index = set_focus_index.clone();
|
||||||
|
let set_adding_new_row = set_adding_new_row.clone();
|
||||||
|
|
||||||
set_items.update(move|items| {
|
set_items.update(move|items| {
|
||||||
if let Some(item) = items.get_mut(index) {
|
if let Some(item) = items.get_mut(index) {
|
||||||
match field {
|
match field {
|
||||||
|
@ -796,6 +807,12 @@ pub fn ItemsList(
|
||||||
}
|
}
|
||||||
// Automatically add a new row when editing the last row
|
// Automatically add a new row when editing the last row
|
||||||
if index == items.len() - 1 && !value.is_empty() {
|
if index == items.len() - 1 && !value.is_empty() {
|
||||||
|
// Set flag that we're adding a new row and need to maintain focus
|
||||||
|
set_adding_new_row.set(true);
|
||||||
|
|
||||||
|
// Remember which index we were editing
|
||||||
|
set_focus_index.set(Some(index));
|
||||||
|
|
||||||
let new_item = Item {
|
let new_item = Item {
|
||||||
id: Uuid::new_v4().to_string(),
|
id: Uuid::new_v4().to_string(),
|
||||||
name: String::new(),
|
name: String::new(),
|
||||||
|
@ -816,7 +833,8 @@ pub fn ItemsList(
|
||||||
}
|
}
|
||||||
log!("Items updated: {:?}", items);
|
log!("Items updated: {:?}", items);
|
||||||
});
|
});
|
||||||
})};
|
})
|
||||||
|
};
|
||||||
|
|
||||||
// List of properties to display as rows
|
// List of properties to display as rows
|
||||||
let properties = vec!["Name", "Description"];
|
let properties = vec!["Name", "Description"];
|
||||||
|
@ -860,7 +878,35 @@ pub fn ItemsList(
|
||||||
view! {
|
view! {
|
||||||
<td>
|
<td>
|
||||||
{match property {
|
{match property {
|
||||||
"Name" => view! {
|
"Name" => {
|
||||||
|
let node_ref = create_node_ref::<Input>();
|
||||||
|
|
||||||
|
// Determine if this input should be focused
|
||||||
|
let should_focus = move || {
|
||||||
|
if adding_new_row.get() {
|
||||||
|
if let Some(focus_idx) = focus_index.get() {
|
||||||
|
// Focus the input that was being edited before adding a new row
|
||||||
|
focus_idx == index
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create an effect to reset the adding_new_row flag after rendering
|
||||||
|
create_effect(move |_| {
|
||||||
|
if adding_new_row.get() && should_focus() {
|
||||||
|
// Reset the flags after focus is applied
|
||||||
|
set_timeout(move || {
|
||||||
|
set_adding_new_row.set(false);
|
||||||
|
set_focus_index.set(None);
|
||||||
|
}, std::time::Duration::from_millis(50));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
view! {
|
||||||
<div class="typeahead-container">
|
<div class="typeahead-container">
|
||||||
<TypeaheadInput
|
<TypeaheadInput
|
||||||
value=item.name.clone()
|
value=item.name.clone()
|
||||||
|
@ -915,47 +961,19 @@ pub fn ItemsList(
|
||||||
})
|
})
|
||||||
is_last_row={index == items.len() - 1}
|
is_last_row={index == items.len() - 1}
|
||||||
on_input=Callback::new({
|
on_input=Callback::new({
|
||||||
// Clone items.len() before moving into the closure
|
let update_item_clone = Arc::clone(&update_item_clone);
|
||||||
let items_len = items.len();
|
|
||||||
let set_items_clone = set_items.clone();
|
|
||||||
let current_url_clone = Rc::clone(¤t_url_clone);
|
|
||||||
let selected_properties_clone = selected_properties.clone();
|
|
||||||
|
|
||||||
move |value: String| {
|
move |value: String| {
|
||||||
if index == items_len - 1 && !value.is_empty() {
|
// Update the item with the new value
|
||||||
let current_url_for_new_item = Rc::clone(¤t_url_clone);
|
update_item_clone(index, "name", value);
|
||||||
let selected_properties_for_new_item = selected_properties_clone.clone();
|
|
||||||
|
|
||||||
set_items_clone.update(|items| {
|
|
||||||
let new_item = Item {
|
|
||||||
id: Uuid::new_v4().to_string(),
|
|
||||||
name: String::new(),
|
|
||||||
description: String::new(),
|
|
||||||
wikidata_id: None,
|
|
||||||
custom_properties: HashMap::new(),
|
|
||||||
};
|
|
||||||
items.push(new_item.clone());
|
|
||||||
|
|
||||||
// Save the new item to the database in a separate task
|
|
||||||
let new_item_clone = new_item.clone();
|
|
||||||
let current_url_for_task = Rc::clone(¤t_url_for_new_item);
|
|
||||||
let selected_properties_for_task = selected_properties_for_new_item;
|
|
||||||
|
|
||||||
spawn_local(async move {
|
|
||||||
save_item_to_db(
|
|
||||||
new_item_clone,
|
|
||||||
selected_properties_for_task,
|
|
||||||
current_url_for_task.to_string()
|
|
||||||
).await;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
node_ref=create_node_ref()
|
node_ref=node_ref
|
||||||
|
should_focus=should_focus()
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}.into_view(),
|
}.into_view()
|
||||||
|
},
|
||||||
|
|
||||||
"Description" => view! {
|
"Description" => view! {
|
||||||
<EditableCell
|
<EditableCell
|
||||||
|
|
|
@ -99,12 +99,25 @@ pub fn TypeaheadInput(
|
||||||
node_ref: NodeRef<Input>,
|
node_ref: NodeRef<Input>,
|
||||||
#[prop(optional)] is_last_row: bool,
|
#[prop(optional)] is_last_row: bool,
|
||||||
#[prop(optional)] on_input: Option<Callback<String>>,
|
#[prop(optional)] on_input: Option<Callback<String>>,
|
||||||
|
#[prop(optional)] should_focus: bool,
|
||||||
) -> impl IntoView {
|
) -> impl IntoView {
|
||||||
let (is_initialized, set_initialized) = create_signal(false);
|
let (is_initialized, set_initialized) = create_signal(false);
|
||||||
|
|
||||||
// Create a unique ID for this component instance
|
// Create a unique ID for this component instance
|
||||||
let component_id = format!("typeahead-{}", uuid::Uuid::new_v4());
|
let component_id = format!("typeahead-{}", uuid::Uuid::new_v4());
|
||||||
|
|
||||||
|
// Clone component_id before moving it into the closure
|
||||||
|
let component_id_for_effect = component_id.clone();
|
||||||
|
// Effect to handle focus when should_focus is true
|
||||||
|
create_effect(move |_| {
|
||||||
|
if should_focus {
|
||||||
|
if let Some(input) = node_ref.get() {
|
||||||
|
let _ = input.focus();
|
||||||
|
log!("[FOCUS] Auto-focusing input: {}", component_id_for_effect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// WASM-specific initialization
|
// WASM-specific initialization
|
||||||
#[cfg(target_arch = "wasm32")]
|
#[cfg(target_arch = "wasm32")]
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue