Skip to content

Instantly share code, notes, and snippets.

@qknight
Last active December 8, 2024 09:54
Show Gist options
  • Save qknight/6d2a06a00e03542087cfcbb3704fccb6 to your computer and use it in GitHub Desktop.
Save qknight/6d2a06a00e03542087cfcbb3704fccb6 to your computer and use it in GitHub Desktop.
This features two textareas in a horizontal layout which adapt their height to the content and sync the height among both textareas. It supports downsizing as well.
// This features two textareas in a horizontal layout which adapt their height to the content and
// sync the height among both textareas. It supports downsizing as well.
// It is also quite a hack but it works!
#[component]
pub fn DescriptionEdit(
description_source: RwSignal<String>,
description_destination: RwSignal<String>,
merge_ui_element_states: RwSignal<HashMap<&'static str, i32>>,
unique_name: &'static str,
) -> impl IntoView {
let are_equal = create_memo(move |_| description_source.get() == description_destination.get());
// refactoring WARNING: do not touch this code below because this makes sure that
// the textareas both sync the same maxium height and there is virtually no other easier way
let adaptHeightRight = move |ev: &Event| {
if let Some(target) = ev
.target()
.and_then(|t| t.dyn_into::<HtmlTextAreaElement>().ok())
{
// left
let textarea_left = document()
.get_element_by_id("textarea-left")
.unwrap()
.dyn_into::<HtmlTextAreaElement>()
.unwrap();
textarea_left.set_value(description_source.get().as_str());
// this makes it too small, so we can read the scroll_height and adapt the height accordingly
textarea_left.set_attribute("style", "height: 80px;");
let textarea_height_left = textarea_left.scroll_height() + 25;
// right
// this makes it too small, so we can read the scroll_height and adapt the height accordingly
target.set_attribute("style", "height: 80px;");
let textarea_height_right = target.scroll_height() + 25;
// common
let common_height = if textarea_height_left >= textarea_height_right {
textarea_height_left
} else {
textarea_height_right
};
target.set_attribute("style", format!("height: {}px", common_height).as_str());
textarea_left.set_attribute("style", format!("height: {}px", common_height).as_str());
}
};
fn resize_textareas(
description_source: RwSignal<String>,
description_destination: RwSignal<String>,
) {
let textarea_left = document()
.get_element_by_id("textarea-left")
.unwrap()
.dyn_into::<HtmlTextAreaElement>()
.unwrap();
textarea_left.set_value(description_source.get().as_str());
textarea_left.set_attribute("style", "height: 80px;");
let textarea_height_left = textarea_left.scroll_height() + 25;
let textarea_right = document()
.get_element_by_id("textarea-right")
.unwrap()
.dyn_into::<HtmlTextAreaElement>()
.unwrap();
textarea_right.set_value(description_destination.get().as_str());
textarea_right.set_attribute("style", "height: 80px;");
let textarea_height_right = textarea_right.scroll_height() + 25;
let common_height = if textarea_height_left >= textarea_height_right {
textarea_height_left
} else {
textarea_height_right
};
textarea_left.set_attribute("style", format!("height: {}px", common_height).as_str());
textarea_right.set_attribute("style", format!("height: {}px", common_height).as_str());
}
Effect::new(move |_| {
resize_textareas(description_source, description_destination);
});
view! {
<div class="border border-gray-300 rounded-md p-1 w-full">
<p class="text-xl font-bold mb-2">"Description"</p>
<div class="grid grid-cols-[1fr_auto_1fr] items-center gap-2 w-full">
// Source description (read-only)
<textarea
type="text"
id="textarea-left"
class="border border-gray-300 focus:ring-indigo-600 border focus:ring-2 focus:ring-inset rounded-md px-3 py-2 bg-gray-100 w-full h-full"
readonly
/>
// Equality display
<div class="text-lg flex items-center justify-center">
{move || {
if are_equal.get() {
view! { <EqualIcon on_click=move |_| {} /> }.into_view()
} else {
view! {
<CopyRightIcon on_click=move |_| {
description_destination.set(description_source.get());
} />
}
.into_view()
}
}}
</div>
// Destination description (editable)
<textarea
type="text"
id="textarea-right"
class="border border-gray-300 rounded-md px-3 focus:ring-2 focus:ring-inset py-2 w-full h-full"
on:input=move |ev| {
adaptHeightRight(&ev);
description_destination.set(event_target_value(&ev))
}
/>
</div>
</div>
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment