Skip to content

Commit e85287f

Browse files
Update to upstream @floating-ui/dom@1.6.11 (#44)
* Update to upstream @floating-ui/dom@1.6.11 * Fix handling HTML relative offset * Fill viewport along an axis if shift is enabled on that axis --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Daniëlle Huisman <danielle@huisman.me>
1 parent 1271d37 commit e85287f

File tree

12 files changed

+313
-46
lines changed

12 files changed

+313
-46
lines changed

packages/dom/src/platform/get_offset_parent.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use floating_ui_utils::dom::{
2-
get_computed_style, get_containing_block, get_parent_node, get_window, is_containing_block,
3-
is_element, is_html_element, is_last_traversable_node, is_table_element, is_top_layer,
2+
get_computed_style, get_containing_block, get_document_element, get_parent_node, get_window,
3+
is_containing_block, is_element, is_html_element, is_last_traversable_node, is_table_element,
4+
is_top_layer, DomNodeOrWindow,
45
};
56
use floating_ui_utils::OwnedElementOrWindow;
67
use web_sys::Window;
@@ -24,7 +25,26 @@ pub fn get_true_offset_parent(element: &Element, polyfill: &Option<Polyfill>) ->
2425
if let Some(polyfill) = polyfill {
2526
polyfill(element)
2627
} else {
27-
element.offset_parent()
28+
let raw_offset_parent = element.offset_parent();
29+
30+
// Firefox returns the <html> element as the offsetParent if it's non-static, while Chrome and Safari return the <body> element.
31+
// The <body> element must be used to perform the correct calculations even if the <html> element is non-static.
32+
if let Some(raw_offset_parent) = raw_offset_parent.as_ref() {
33+
if get_document_element(Some(DomNodeOrWindow::Node(raw_offset_parent)))
34+
== *raw_offset_parent
35+
{
36+
return Some(
37+
raw_offset_parent
38+
.owner_document()
39+
.expect("Element should have owner document.")
40+
.body()
41+
.expect("Document should have body.")
42+
.unchecked_into::<Element>(),
43+
);
44+
}
45+
}
46+
47+
raw_offset_parent
2848
}
2949
}
3050
}

packages/dom/src/utils/get_document_rect.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub fn get_document_rect(element: &Element) -> Rect {
3737
.max()
3838
.expect("Iterator is not empty.") as f64;
3939

40-
let mut x = -scroll.scroll_left + get_window_scroll_bar_x(element);
40+
let mut x = -scroll.scroll_left + get_window_scroll_bar_x(element, None);
4141
let y = -scroll.scroll_top;
4242

4343
if is_rtl(&body) {

packages/dom/src/utils/get_rect_relative_to_offset_parent.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,26 @@ pub fn get_rect_relative_to_offset_parent(
5252
offsets.y = offset_rect.y + offset_parent.client_top() as f64;
5353
}
5454
DomElementOrWindow::Window(_) => {
55-
offsets.x = get_window_scroll_bar_x(&document_element);
55+
// If the <body> scrollbar appears on the left (e.g. RTL systems).
56+
// Use Firefox with layout.scrollbar.side = 3 in about:config to test this.
57+
offsets.x = get_window_scroll_bar_x(&document_element, None);
5658
}
5759
}
5860
}
5961

60-
let x = rect.left + scroll.scroll_left - offsets.x;
61-
let y = rect.top + scroll.scroll_top - offsets.y;
62+
let mut html_x = 0.0;
63+
let mut html_y = 0.0;
64+
65+
if !is_offset_parent_an_element && !is_fixed {
66+
let html_rect = document_element.get_bounding_client_rect();
67+
html_y = html_rect.top() as f64 + scroll.scroll_top;
68+
html_x = html_rect.left()as f64 + scroll.scroll_left
69+
// RTL <body> scrollbar.
70+
- get_window_scroll_bar_x(&document_element, Some(html_rect));
71+
}
72+
73+
let x = rect.left + scroll.scroll_left - offsets.x - html_x;
74+
let y = rect.top + scroll.scroll_top - offsets.y - html_y;
6275

6376
Rect {
6477
x,
Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,22 @@
11
use floating_ui_utils::dom::{get_document_element, get_node_scroll};
2-
use web_sys::Element;
2+
use web_sys::{DomRect, Element};
33

44
use crate::utils::get_bounding_client_rect::get_bounding_client_rect;
55

6-
pub fn get_window_scroll_bar_x(element: &Element) -> f64 {
7-
get_bounding_client_rect(
8-
(&get_document_element(Some(element.into()))).into(),
9-
false,
10-
false,
11-
None,
12-
)
13-
.left
14-
+ get_node_scroll(element.into()).scroll_left
6+
// If <html> has a CSS width greater than the viewport, then this will be incorrect for RTL.
7+
pub fn get_window_scroll_bar_x(element: &Element, rect: Option<DomRect>) -> f64 {
8+
let left_scroll = get_node_scroll(element.into()).scroll_left;
9+
10+
if let Some(rect) = rect {
11+
rect.left() + left_scroll
12+
} else {
13+
get_bounding_client_rect(
14+
(&get_document_element(Some(element.into()))).into(),
15+
false,
16+
false,
17+
None,
18+
)
19+
.left
20+
+ left_scroll
21+
}
1522
}

packages/leptos/tests/visual/index.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,14 @@ main {
201201
display: none;
202202
}
203203

204+
.resize {
205+
resize: both;
206+
max-height: 480px;
207+
max-width: 480px;
208+
min-height: 120px;
209+
min-width: 120px;
210+
}
211+
204212
.prose {
205213
font-size: 1.125rem;
206214
color: #555;

packages/leptos/tests/visual/src/spec/relative.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ pub fn Relative() -> impl IntoView {
1919
let floating_ref = create_node_ref::<Div>();
2020

2121
let (node, set_node) = create_signal(Node::None);
22+
let (offset, set_offset) = create_signal(0);
2223

2324
let UseFloatingReturn {
2425
x,
@@ -38,14 +39,21 @@ pub fn Relative() -> impl IntoView {
3839
.document_element()
3940
.map(|element| element.unchecked_into::<web_sys::HtmlElement>()),
4041
Node::Body => document().body(),
41-
_ => None,
42+
_ => document()
43+
.query_selector(".container")
44+
.expect("Document should be queried.")
45+
.map(|element| element.unchecked_into::<web_sys::HtmlElement>()),
4246
};
4347

4448
if let Some(element) = element {
4549
element
4650
.style()
4751
.set_property("position", "relative")
4852
.expect("Style should be updated.");
53+
element
54+
.style()
55+
.set_property("top", &format!("{}px", -offset.get()))
56+
.expect("Style should be updated.");
4957
}
5058

5159
update();
@@ -65,6 +73,10 @@ pub fn Relative() -> impl IntoView {
6573
.style()
6674
.remove_property("position")
6775
.expect("Style should be updated.");
76+
element
77+
.style()
78+
.remove_property("top")
79+
.expect("Style should be updated.");
6880
}
6981
});
7082

@@ -95,6 +107,7 @@ pub fn Relative() -> impl IntoView {
95107
</div>
96108
</div>
97109

110+
<h2>Node</h2>
98111
<div class="controls">
99112
<For
100113
each=|| ALL_NODES
@@ -116,5 +129,29 @@ pub fn Relative() -> impl IntoView {
116129
}
117130
/>
118131
</div>
132+
133+
<h2>Offset</h2>
134+
<div class="controls">
135+
<For
136+
each=|| [0, 100]
137+
key=|local_offset| format!("{:?}", local_offset)
138+
children=move |local_offset| {
139+
view! {
140+
<button
141+
data-testid=format!("offset-{local_offset}")
142+
style:background-color=move || match offset() == local_offset {
143+
true => "black",
144+
false => ""
145+
}
146+
on:click=move |_| {
147+
set_offset(local_offset);
148+
}
149+
>
150+
{format!("{local_offset}")}
151+
</button>
152+
}
153+
}
154+
/>
155+
</div>
119156
}
120157
}

0 commit comments

Comments
 (0)