From: Shannon Sterz <s.sterz@proxmox.com>
To: yew-devel@lists.proxmox.com
Subject: [PATCH yew-widget-toolkit 2/3] dropdown/align: make the picker render above or below a dropdown
Date: Mon, 4 May 2026 16:39:10 +0200 [thread overview]
Message-ID: <20260504143911.288747-3-s.sterz@proxmox.com> (raw)
In-Reply-To: <20260504143911.288747-1-s.sterz@proxmox.com>
and detect dropup mode. this allows better ux restricting the height
of the picker to the maximum of the space below or above a `Dropdown`.
by setting the `pwt-dropup` class the picker can also set the proper
flex direction for its content. for example, rendering filter input
fields closer to the `Dropdown` itself, further improving usability.
this implements the fix outlined in [1].
[1]:
https://git.proxmox.com/?p=proxmox-datacenter-manager.git;a=commit;f=ui/css/desktop-yew-style.scss;h=dafa21a3
Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
---
src/dom/align.rs | 6 +++-
src/widget/dropdown.rs | 62 +++++++++++++++++++++++++++++++++++-------
2 files changed, 57 insertions(+), 11 deletions(-)
diff --git a/src/dom/align.rs b/src/dom/align.rs
index 603a5b8d..a20cc6ed 100644
--- a/src/dom/align.rs
+++ b/src/dom/align.rs
@@ -456,7 +456,11 @@ where
style.remove_property("overflow")?;
}
let padding = 2.0 * options.viewport_padding;
- style.set_property("max-height", &format!("calc(100dvh - {padding}px)"))?;
+
+ if style.get_property_value("max-height")? == "" {
+ style.set_property("max-height", &format!("calc(100dvh - {padding}px)"))?;
+ }
+
style.set_property("max-width", &format!("calc(100dvw - {padding}px)"))?;
if options.align_width {
diff --git a/src/widget/dropdown.rs b/src/widget/dropdown.rs
index 1af09633..64db380a 100644
--- a/src/widget/dropdown.rs
+++ b/src/widget/dropdown.rs
@@ -1,7 +1,11 @@
+use std::cmp;
+
use html::Scope;
use wasm_bindgen::JsCast;
use web_sys::HtmlInputElement;
+use crate::dom::IntoHtmlElement;
+
use yew::html::{IntoEventCallback, IntoPropValue};
use yew::prelude::*;
@@ -155,15 +159,18 @@ impl PwtDropdown {
}
fn update_picker_placer(&mut self, _props: &Dropdown) {
- let align_options = _props.align_options.clone().unwrap_or(
- AlignOptions::new(
- Point::BottomStart,
- Point::TopStart,
- GrowDirection::TopBottom,
- )
- .viewport_padding(5.0)
- .align_width(true),
- );
+ let align_options =
+ AlignOptions::new(Point::BottomStart, Point::TopStart, GrowDirection::None)
+ .viewport_padding(5.0)
+ .align_width(true)
+ .with_fallback_placement(Point::TopStart, Point::BottomStart, GrowDirection::None)
+ .with_fallback_placement(
+ Point::BottomStart,
+ Point::TopStart,
+ GrowDirection::TopBottom,
+ );
+
+ let align_options = _props.align_options.clone().unwrap_or(align_options);
self.picker_placer = match AutoFloatingPlacement::new(
self.dropdown_ref.clone(),
self.picker_ref.clone(),
@@ -497,7 +504,6 @@ impl Component for PwtDropdown {
fn rendered(&mut self, ctx: &Context<Self>, first_render: bool) {
if first_render {
let props = ctx.props();
-
self.update_picker_placer(props);
if props.input_props.autofocus {
@@ -525,6 +531,42 @@ impl Component for PwtDropdown {
}
}
+ // intentionally fail silently here; if any of these values aren't available here, falling
+ // back to the default logic is fine, this should just provide improved ui/ux.
+ let dropdown_rect = self
+ .dropdown_ref
+ .clone()
+ .into_html_element()
+ .map(|e| e.get_bounding_client_rect());
+
+ let window_height = web_sys::window()
+ .and_then(|w| w.inner_height().ok())
+ .and_then(|h| h.as_f64().map(|h| h as i64));
+
+ if let Some(dropdown_rect) = dropdown_rect
+ && let Some(window_height) = window_height
+ {
+ let top = dropdown_rect.y() as i64;
+ let bottom = window_height - (top + (dropdown_rect.height() as i64));
+ let height = cmp::max(top, bottom) - 5;
+
+ if let Some(picker) = self.picker_ref.clone().into_html_element() {
+ let _ = picker
+ .style()
+ .set_property("max-height", &format!("{height}px"))
+ .ok();
+
+ let height = picker.get_bounding_client_rect().height() as i64;
+ let class_list = picker.class_list();
+
+ if height > bottom && height <= top {
+ let _ = class_list.add_1("pwt-dropup");
+ } else {
+ let _ = class_list.remove_1("pwt-dropup");
+ }
+ }
+ }
+
// update picker placement after we opened/closed to cope with a bug that only seems to
// affect webkit based browsers like Safari
if let Some(placer) = &self.picker_placer {
--
2.47.3
next prev parent reply other threads:[~2026-05-04 14:39 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-04 14:39 [RFC yew-comp/yew-widget-toolkit/yew-widget-toolkit-assets 0/3] minor ui/ux tweaks for pwt and yew-comp Shannon Sterz
2026-05-04 14:39 ` [PATCH yew-widget-toolkit-assets 1/3] dropdown: add class for dropup mode Shannon Sterz
2026-05-04 14:39 ` Shannon Sterz [this message]
2026-05-04 14:39 ` [PATCH yew-comp 3/3] task_viewer/syslog: make padding margin to improve ux Shannon Sterz
2026-05-06 7:53 ` [RFC yew-comp/yew-widget-toolkit/yew-widget-toolkit-assets 0/3] minor ui/ux tweaks for pwt and yew-comp Dominik Csapak
2026-05-06 9:43 ` Shannon Sterz
2026-05-06 9:55 ` Dominik Csapak
2026-05-06 9:56 ` Superseded: " Shannon Sterz
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260504143911.288747-3-s.sterz@proxmox.com \
--to=s.sterz@proxmox.com \
--cc=yew-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.