From c4a45d91855d0098d3a0ee9219fb1e6d6dc437aa Mon Sep 17 00:00:00 2001 From: ryan Date: Mon, 30 Dec 2024 14:18:33 +0300 Subject: [PATCH] Fix (ItemsList)(inprogress): Improve Popup Positioning and Debounced Fetching - Introduced `ActiveCell` struct to manage active cell state and position more robustly. - Added debounce mechanism using `futures_timer::Delay` for optimized Wikidata suggestion fetching. - Enhanced popup rendering logic to include z-index and improved styling for better positioning. - Implemented validation for bounding box dimensions during active cell positioning. - Adjusted event handling for focus and blur with asynchronous state updates. - General refactoring for better readability and maintainability. (Note: Popup functionality remains incomplete and will be addressed in future iterations.) --- src/components/items_list.rs | 70 ++++++++++++++++++++++-------------- 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/src/components/items_list.rs b/src/components/items_list.rs index d3fc4eb..8c4ee0a 100644 --- a/src/components/items_list.rs +++ b/src/components/items_list.rs @@ -8,6 +8,8 @@ use crate::models::item::Item; use std::sync::{Arc, Mutex}; use wasm_bindgen::JsCast; use web_sys::{FocusEvent, HtmlElement, Element, Node}; +use futures_timer::Delay; +use std::time::Duration; #[derive(Deserialize, Clone, Debug)] struct WikidataSuggestion { @@ -15,6 +17,11 @@ struct WikidataSuggestion { label: String, description: Option, } +#[derive(Clone)] +struct ActiveCell { + row_index: usize, + position: (f64, f64), +} #[component] pub fn ItemsList( @@ -32,14 +39,16 @@ pub fn ItemsList( wikidata_id: None, }]); + let (active_cell, set_active_cell) = create_signal(None::); let (active_cell_position, set_active_cell_position) = create_signal(None::<(f64, f64)>); let (active_row_index, set_active_row_index) = create_signal(None::); - let (wikidata_suggestions, set_wikidata_suggestions) = - create_signal(Vec::::new()); + let (wikidata_suggestions, set_wikidata_suggestions) = create_signal(Vec::::new()); + let debounce_duration = Duration::from_millis(300); // Fetch Wikidata suggestions let fetch_wikidata_suggestions = move |query: String| { spawn_local(async move { + Delay::new(debounce_duration).await; if query.is_empty() { set_wikidata_suggestions.set(Vec::new()); return; @@ -56,7 +65,10 @@ pub fn ItemsList( set_wikidata_suggestions.set(data.search); } } - Err(_) => log!("Failed to fetch Wikidata suggestions"), + Err(err) => { + log!("Failed to fetch Wikidata suggestions: {:?}", err); + set_wikidata_suggestions.set(Vec::new()); + } } }); }; @@ -70,10 +82,15 @@ pub fn ItemsList( item.name = value.clone(); fetch_wikidata_suggestions(value.clone()); set_active_row_index.set(Some(index)); - // Set active cell position + // Set active cell position with validation if let Some(element) = document().get_element_by_id(&format!("name-{}", index)) { let rect = element.get_bounding_client_rect(); - set_active_cell_position.set(Some((rect.left(), rect.bottom()))); + log!("Bounding rect: {:?}", rect); // Log rect details + if rect.width() > 0.0 && rect.height() > 0.0 { + set_active_cell_position.set(Some((rect.left(), rect.bottom()))); + } else { + log!("Element bounding box is not valid for popup positioning."); + } } } "description" => { @@ -129,10 +146,15 @@ pub fn ItemsList( class="suggestions-popup" style=move || { let suggestions = wikidata_suggestions.get(); - let position = active_cell_position.get(); - if !suggestions.is_empty() && position.is_some() { - let (x, y) = position.unwrap(); - format!("position: absolute; left: {}px; top: {}px; display: block;", x, y) + if !suggestions.is_empty() { + if let Some((x, y)) = active_cell_position.get() { + format!( + "position: absolute; left: {}px; top: {}px; display: block; z-index: 1000;", + x, y + ) + } else { + "display: none;".to_string() + } } else { "display: none;".to_string() } @@ -190,26 +212,20 @@ pub fn ItemsList(
() { - if let Some(element_ref) = node.dyn_ref::(){ - if let Some(element) = element_ref.dyn_ref::() { - let rect = element.get_bounding_client_rect(); - set_active_cell_position.set(Some((rect.left(), rect.top() + rect.height()))); - set_active_row_index.set(Some(index)); - } else { - log!("Failed to cast to Element"); - } - } else { - log!("Target is not a valid HTML element"); - } - } else { - log!("Target is not a valid Node"); - } + if let Some(element) = event.target().and_then(|t| t.dyn_into::().ok()) { + let rect = element.get_bounding_client_rect(); + set_active_cell.set(Some(ActiveCell { + row_index: index, + position: (rect.left(), rect.top() + rect.height()), + })); } } - on:blur=move |_| set_active_row_index.set(None) + on:blur=move |_| { + spawn_local(async move { + Delay::new(Duration::from_millis(100)).await; + set_active_cell.set(None); + }); + } >