fix: exclude scroll area padding from pane sizing

This commit is contained in:
2026-11-09 08:35:07 +07:00
parent d8663593b6
commit 8c438ed8a6
9 changed files with 269 additions and 209 deletions
+19 -14
View File
@@ -222,6 +222,9 @@ pub(crate) fn thumb_geometry(
impl RenderOnce for ScrollArea {
fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
let mut pane_style = self.style.clone();
pane_style.padding = Default::default();
let mut pane = div()
.id(self.id.clone())
.overflow_hidden()
@@ -239,7 +242,7 @@ impl RenderOnce for ScrollArea {
// Keep wheel events from scrolling an outer scroll area too.
cx.stop_propagation();
})
.refine_style(&self.style);
.refine_style(&pane_style);
// Extend with children
pane.extend(self.children);
@@ -248,17 +251,18 @@ impl RenderOnce for ScrollArea {
wrapper.extend(std::iter::once(pane.into_any_element()));
if let Some(handle) = self.handle {
let id = self.id.clone();
let autohide = match self.visibility {
ScrollbarVisibility::Platform => cx.theme().scrollbar.autohide,
ScrollbarVisibility::Always => false,
ScrollbarVisibility::Autohide => true,
};
let id = self.id.clone();
wrapper.extend(std::iter::once(
canvas(|_, _, _| {}, {
canvas(|bounds, _, _| bounds, {
let handle = handle.clone();
move |_, _, window, cx| {
paint_scrollbar(&handle, &id, autohide, window, cx);
move |overlay, _, window, cx| {
paint_scrollbar(&handle, &id, autohide, overlay, window, cx);
}
})
.absolute()
@@ -276,6 +280,7 @@ fn paint_scrollbar(
handle: &ScrollHandle,
key: &ElementId,
autohide: bool,
overlay: Bounds<Pixels>,
window: &mut Window,
cx: &mut App,
) {
@@ -287,10 +292,10 @@ fn paint_scrollbar(
let inset = theme.scrollbar.inset;
let min_thumb = theme.scrollbar.min_thumb;
let viewport = handle.bounds();
let max_offset = handle.max_offset().y;
let bounds = handle.bounds();
if max_offset <= Pixels::ZERO || bounds.size.height <= Pixels::ZERO {
if max_offset <= Pixels::ZERO || viewport.size.height <= Pixels::ZERO {
return;
}
@@ -306,21 +311,21 @@ fn paint_scrollbar(
_ => 1.0,
};
let track = bounds.size.height - inset * 2.0;
let track = overlay.size.height - inset * 2.0;
let (thumb_length, thumb_top) = thumb_geometry(
bounds.size.height,
bounds.size.height + max_offset,
viewport.size.height,
viewport.size.height + max_offset,
handle.offset().y,
track,
min_thumb,
);
let thumb_x = bounds.right() - width - inset;
let thumb_x = overlay.right() - width - inset;
let thumb_bounds = Bounds::from_corners(
point(thumb_x, bounds.top() + inset + thumb_top),
point(thumb_x, overlay.top() + inset + thumb_top),
point(
thumb_x + width,
bounds.top() + inset + thumb_top + thumb_length,
overlay.top() + inset + thumb_top + thumb_length,
),
);
@@ -332,7 +337,7 @@ fn paint_scrollbar(
window.on_mouse_event({
let state = state.clone();
move |event: &ScrollEvent, phase, window, cx| {
if phase != DispatchPhase::Bubble || !bounds.contains(&event.position) {
if phase != DispatchPhase::Bubble || !overlay.contains(&event.position) {
return;
}
state.touch(window, cx);