-
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5f7aac2
commit d9ec770
Showing
13 changed files
with
312 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
[package] | ||
name = "floating-ui-leptos-example" | ||
description = "Example for Floating UI Leptos." | ||
publish = false | ||
|
||
authors.workspace = true | ||
edition.workspace = true | ||
license.workspace = true | ||
repository.workspace = true | ||
version.workspace = true | ||
|
||
[dependencies] | ||
console_log = "1.0.0" | ||
console_error_panic_hook = "0.1.7" | ||
leptos = { version = "0.6.9", features = ["csr", "nightly"] } | ||
log = "0.4.21" | ||
floating-ui-leptos = { path = ".." } | ||
wasm-bindgen.workspace = true | ||
web-sys.workspace = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
<!doctype html> | ||
<html> | ||
<head></head> | ||
<body></body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
use floating_ui_leptos::{use_floating, UseFloatingOptions, UseFloatingReturn}; | ||
use leptos::{ | ||
html::{Div, Span}, | ||
*, | ||
}; | ||
|
||
#[component] | ||
pub fn App() -> impl IntoView { | ||
let reference = create_node_ref::<Span>(); | ||
let floating = create_node_ref::<Div>(); | ||
|
||
let UseFloatingReturn { | ||
floating_styles, .. | ||
} = use_floating(reference, floating, UseFloatingOptions::default().into()); | ||
|
||
view! { | ||
<span _ref=reference>Reference</span> | ||
<div _ref=floating style=floating_styles> | ||
Floating | ||
</div> | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
// TODO: remove after leptos is fixed | ||
#![allow(clippy::empty_docs)] | ||
|
||
mod app; | ||
|
||
use crate::app::App; | ||
|
||
pub fn main() { | ||
_ = console_log::init_with_level(log::Level::Debug); | ||
console_error_panic_hook::set_once(); | ||
|
||
leptos::mount_to_body(App); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
mod types; | ||
mod use_floating; | ||
mod utils; | ||
|
||
pub use types::*; | ||
pub use use_floating::*; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
use floating_ui_dom::{Middleware, MiddlewareData, Placement, Strategy}; | ||
use leptos::{Attribute, IntoAttribute, Signal}; | ||
use web_sys::{Element, Window}; | ||
|
||
/// Options for [`use_floating`]. | ||
#[derive(Clone, Default)] | ||
pub struct UseFloatingOptions<'a> { | ||
/// Represents the open/close state of the floating element. | ||
/// | ||
/// Defaults to `true`. | ||
pub open: Option<bool>, | ||
|
||
/// Where to place the floating element relative to the reference element. | ||
/// | ||
/// Defaults to [`Placement::Bottom`]. | ||
pub placement: Option<Placement>, | ||
|
||
/// The strategy to use when positioning the floating element. | ||
/// | ||
/// Defaults to [`Strategy::Absolute`]. | ||
pub strategy: Option<Strategy>, | ||
|
||
/// Array of middleware objects to modify the positioning or provide data for rendering. | ||
/// | ||
/// Defaults to an empty vector. | ||
pub middleware: Option<Vec<&'a dyn Middleware<Element, Window>>>, | ||
|
||
/// Whether to use `transform` for positioning instead of `top` and `left` in the `floatingStyles` object. | ||
/// | ||
/// Defaults to `true`. | ||
pub transform: Option<bool>, | ||
|
||
/// Callback to handle mounting/unmounting of the elements. | ||
/// | ||
///Detauls to [`Option::None`]. | ||
pub while_elements_mounted: Option<bool>, // TODO: type | ||
} | ||
|
||
#[derive(Clone, Debug, PartialEq)] | ||
pub struct FloatingStyles { | ||
pub position: Strategy, | ||
pub top: String, | ||
pub left: String, | ||
pub transform: Option<String>, | ||
pub will_change: Option<String>, | ||
} | ||
|
||
impl IntoAttribute for FloatingStyles { | ||
fn into_attribute(self) -> Attribute { | ||
Attribute::String( | ||
format!( | ||
"position: {:?}; top: {}; left: {};{}{}", | ||
self.position, | ||
self.top, | ||
self.left, | ||
self.transform | ||
.map_or("".into(), |transform| format!(" transform: {};", transform),), | ||
self.will_change.map_or("".into(), |will_change| format!( | ||
" will-change: {};", | ||
will_change | ||
)) | ||
) | ||
.into(), | ||
) | ||
} | ||
|
||
fn into_attribute_boxed(self: Box<Self>) -> Attribute { | ||
self.into_attribute() | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct UseFloatingReturn { | ||
/// The x-coord of the floating element. | ||
pub x: Signal<f64>, | ||
|
||
/// The y-coord of the floating element. | ||
pub y: Signal<f64>, | ||
|
||
/// The stateful placement, which can be different from the initial `placement` passed as options. | ||
pub placement: Signal<Placement>, | ||
|
||
/// The strategy to use when positioning the floating element. | ||
pub strategy: Signal<Strategy>, | ||
|
||
/// Additional data from middleware. | ||
pub middleware_data: Signal<MiddlewareData>, | ||
|
||
/// Indicates if the floating element has been positioned. | ||
pub is_positioned: Signal<bool>, | ||
|
||
/// CSS styles to apply to the floating element to position it. | ||
pub floating_styles: Signal<FloatingStyles>, | ||
|
||
/// The function to update floating position manually. | ||
pub update: bool, // TODO: type | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,60 +1,137 @@ | ||
use floating_ui_dom::{Middleware, MiddlewareData, Placement, Strategy}; | ||
use leptos::{create_signal, MaybeSignal}; | ||
use web_sys::{Element, Window}; | ||
|
||
/// Options for [`use_floating`]. | ||
#[derive(Clone, Default)] | ||
pub struct UseFloatingOptions<'a> { | ||
/// Where to place the floating element relative to the reference element. | ||
/// | ||
/// Defaults to [`Placement::Bottom`]. | ||
pub placement: Option<Placement>, | ||
|
||
/// The strategy to use when positioning the floating element. | ||
/// | ||
/// Defaults to [`Strategy::Absolute`]. | ||
pub strategy: Option<Strategy>, | ||
|
||
/// Array of middleware objects to modify the positioning or provide data for rendering. | ||
/// | ||
/// Defaults to an empty vector. | ||
pub middleware: Option<Vec<&'a dyn Middleware<Element, Window>>>, | ||
} | ||
use std::ops::Deref; | ||
|
||
/// Data stored by [`use_floating`]. | ||
pub struct UseFloatingData { | ||
pub x: f64, | ||
pub y: f64, | ||
pub strategy: Strategy, | ||
pub placement: Placement, | ||
pub middleware_data: MiddlewareData, | ||
pub is_positioned: bool, | ||
} | ||
use floating_ui_dom::{ | ||
compute_position, ComputePositionConfig, MiddlewareData, Placement, Strategy, | ||
}; | ||
use leptos::{create_memo, create_signal, html::ElementDescriptor, MaybeSignal, NodeRef, Signal}; | ||
use log::info; | ||
|
||
use crate::{ | ||
types::{FloatingStyles, UseFloatingOptions, UseFloatingReturn}, | ||
utils::{get_dpr::get_dpr, round_by_dpr::round_by_dpr}, | ||
}; | ||
|
||
pub fn use_floating<Reference, Floating, ReferenceEl, FloatingEl>( | ||
reference: NodeRef<Reference>, | ||
floating: NodeRef<Floating>, | ||
options: MaybeSignal<UseFloatingOptions>, | ||
) -> UseFloatingReturn | ||
where | ||
Reference: ElementDescriptor + Deref<Target = ReferenceEl> + Clone + 'static, | ||
ReferenceEl: Deref<Target = web_sys::HtmlElement>, | ||
Floating: ElementDescriptor + Deref<Target = FloatingEl> + Clone + 'static, | ||
FloatingEl: Deref<Target = web_sys::HtmlElement>, | ||
{ | ||
let options = Signal::derive(options); | ||
|
||
let open_option = move || options().open.unwrap_or(true); | ||
let placement_option = move || options().placement.unwrap_or(Placement::Bottom); | ||
let strategy_option = move || options().strategy.unwrap_or(Strategy::Absolute); | ||
let middleware_option = move || options().middleware; | ||
let transform_option = move || options().transform.unwrap_or(true); | ||
|
||
let (x, set_x) = create_signal(0.0); | ||
let (y, set_y) = create_signal(0.0); | ||
let (strategy, set_strategy) = create_signal(strategy_option()); | ||
let (placement, set_placement) = create_signal(placement_option()); | ||
let (middleware_data, set_middleware_data) = create_signal(MiddlewareData::default()); | ||
let (is_positioned, set_is_positioned) = create_signal(false); | ||
let floating_styles = create_memo(move |_| { | ||
let initial_styles = FloatingStyles { | ||
position: strategy(), | ||
top: "0".into(), | ||
left: "0".into(), | ||
transform: None, | ||
will_change: None, | ||
}; | ||
|
||
info!("floating styles memo"); | ||
|
||
if let Some(floating_element) = floating.get() { | ||
info!("floating element exists"); | ||
|
||
pub fn use_floating(options: MaybeSignal<UseFloatingOptions>) { | ||
// let placement = create_memo(move |_| { | ||
// options.with(|options| options.placement.unwrap_or(Placement::Bottom)) | ||
// }); | ||
|
||
// let strategy = create_memo(move |_| { | ||
// options.with(|options| options.strategy.unwrap_or(Strategy::Absolute)) | ||
// }); | ||
|
||
let (_data, _set_data) = create_signal(UseFloatingData { | ||
x: 0.0, | ||
y: 0.0, | ||
strategy: options().strategy.unwrap_or(Strategy::Absolute), | ||
placement: options().placement.unwrap_or(Placement::Bottom), | ||
middleware_data: MiddlewareData::default(), | ||
is_positioned: false, | ||
let x_val = round_by_dpr(&floating_element, x()); | ||
let y_val = round_by_dpr(&floating_element, y()); | ||
|
||
if transform_option() { | ||
FloatingStyles { | ||
transform: Some(format!("translate({x_val}px, {y_val}px)")), | ||
will_change: match get_dpr(&floating_element) >= 1.5 { | ||
true => Some("transform".into()), | ||
false => None, | ||
}, | ||
..initial_styles | ||
} | ||
} else { | ||
FloatingStyles { | ||
left: format!("{x_val}px"), | ||
top: format!("{y_val}px"), | ||
..initial_styles | ||
} | ||
} | ||
} else { | ||
initial_styles | ||
} | ||
}); | ||
|
||
// let (_latest_middleware, _set_latest_middleware) = create_signal(options.middleware); | ||
let update = move || { | ||
info!("update"); | ||
if let Some(reference_element) = reference.get() { | ||
info!("ref"); | ||
if let Some(floating_element) = floating.get() { | ||
info!("float"); | ||
let config = ComputePositionConfig { | ||
placement: Some(placement_option()), | ||
strategy: Some(strategy_option()), | ||
middleware: middleware_option(), | ||
}; | ||
|
||
let position = | ||
compute_position(&reference_element, &floating_element, Some(config)); | ||
set_x(position.x); | ||
set_y(position.x); | ||
set_strategy(position.strategy); | ||
set_placement(position.placement); | ||
set_middleware_data(position.middleware_data); | ||
set_is_positioned(true); | ||
} | ||
} | ||
}; | ||
|
||
let cleanup = move || { | ||
// TODO | ||
}; | ||
|
||
let attach = move || { | ||
cleanup(); | ||
|
||
// TODO: the rest of the function | ||
update(); | ||
}; | ||
|
||
let reset = move || { | ||
if !open_option() { | ||
set_is_positioned(false); | ||
} | ||
}; | ||
|
||
// TODO: call attach/reset | ||
|
||
// // TODO: compare latest_middleware and options.middleware and update it | ||
create_memo(move |_| { | ||
info!("{} {}", reference.get().is_some(), floating.get().is_some()); | ||
|
||
// let (_reference, _set_reference) = create_signal::<Option<Element>>(None); | ||
// let (_floating, _set_floating) = create_signal::<Option<Element>>(None); | ||
info!("memo"); | ||
attach() | ||
})(); | ||
|
||
// // TODO: setReference and setFloating | ||
UseFloatingReturn { | ||
x: x.into(), | ||
y: y.into(), | ||
placement: placement.into(), | ||
strategy: strategy.into(), | ||
middleware_data: middleware_data.into(), | ||
is_positioned: is_positioned.into(), | ||
floating_styles: floating_styles.into(), | ||
update: false, // TODO | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pub mod get_dpr; | ||
pub mod round_by_dpr; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
use floating_ui_dom::dom::get_window; | ||
use web_sys::Element; | ||
|
||
pub fn get_dpr(element: &Element) -> f64 { | ||
get_window(Some(element)).device_pixel_ratio() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
use web_sys::Element; | ||
|
||
use crate::utils::get_dpr::get_dpr; | ||
|
||
pub fn round_by_dpr(element: &Element, value: f64) -> f64 { | ||
let dpr = get_dpr(element); | ||
(value * dpr).round() / dpr | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters