Skip to content

Commit

Permalink
Add support for virtual elements
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielleHuisman committed Apr 19, 2024
1 parent f066217 commit 232d9ae
Show file tree
Hide file tree
Showing 40 changed files with 548 additions and 216 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ repository = "https://github.com/NixySoftware/floating-ui"
version = "0.0.4"

[workspace.dependencies]
cfg-if = "1.0.0"
dyn-clone = "1.0.17"
serde = { version = "1.0.197", features = ["derive"] }
serde_json = "1.0.114"
Expand Down
26 changes: 13 additions & 13 deletions packages/core/src/compute_position.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use floating_ui_utils::{Coords, Placement, Strategy};
use floating_ui_utils::{Coords, ElementOrVirtual, Placement, Strategy};

use crate::compute_coords_from_placement::compute_coords_from_placement;
use crate::types::{
Expand All @@ -12,7 +12,7 @@ use crate::types::{
///
/// See [`Platform`][`crate::types::Platform`].
pub fn compute_position<Element: Clone, Window: Clone>(
reference: &Element,
reference: ElementOrVirtual<Element>,
floating: &Element,
config: ComputePositionConfig<Element, Window>,
) -> ComputePositionReturn {
Expand All @@ -24,7 +24,7 @@ pub fn compute_position<Element: Clone, Window: Clone>(
let rtl = platform.is_rtl(floating);

let mut rects = platform.get_element_rects(GetElementRectsArgs {
reference: reference.into(),
reference: reference.clone(),
floating,
strategy,
});
Expand Down Expand Up @@ -52,8 +52,8 @@ pub fn compute_position<Element: Clone, Window: Clone>(
rects: &rects,
platform,
elements: Elements {
reference: &reference,
floating: &floating,
reference: reference.clone(),
floating,
},
});

Expand All @@ -79,7 +79,7 @@ pub fn compute_position<Element: Clone, Window: Clone>(
rects = match reset_rects {
ResetRects::True => {
platform.get_element_rects(GetElementRectsArgs {
reference: reference.into(),
reference: reference.clone(),
floating,
strategy,
})
Expand Down Expand Up @@ -128,7 +128,7 @@ mod tests {
#[derive(Clone)]
struct CustomMiddleware {}

impl<Element, Window> Middleware<Element, Window> for CustomMiddleware {
impl<Element: Clone, Window: Clone> Middleware<Element, Window> for CustomMiddleware {
fn name(&self) -> &'static str {
"custom"
}
Expand All @@ -150,7 +150,7 @@ mod tests {
strategy,
middleware_data,
} = compute_position(
&REFERENCE,
(&REFERENCE).into(),
&FLOATING,
ComputePositionConfig {
platform: &PLATFORM,
Expand All @@ -175,7 +175,7 @@ mod tests {
#[derive(Clone)]
struct TestMiddleware {}

impl<Element, Window> Middleware<Element, Window> for TestMiddleware {
impl<Element: Clone, Window: Clone> Middleware<Element, Window> for TestMiddleware {
fn name(&self) -> &'static str {
"test"
}
Expand All @@ -194,7 +194,7 @@ mod tests {
}

let ComputePositionReturn { x, y, .. } = compute_position(
&REFERENCE,
(&REFERENCE).into(),
&FLOATING,
ComputePositionConfig {
platform: &PLATFORM,
Expand All @@ -205,7 +205,7 @@ mod tests {
);

let ComputePositionReturn { x: x2, y: y2, .. } = compute_position(
&REFERENCE,
(&REFERENCE).into(),
&FLOATING,
ComputePositionConfig {
platform: &PLATFORM,
Expand All @@ -223,7 +223,7 @@ mod tests {
#[derive(Clone)]
struct TestMiddleware {}

impl<Element, Window> Middleware<Element, Window> for TestMiddleware {
impl<Element: Clone, Window: Clone> Middleware<Element, Window> for TestMiddleware {
fn name(&self) -> &'static str {
"test"
}
Expand All @@ -241,7 +241,7 @@ mod tests {
let ComputePositionReturn {
middleware_data, ..
} = compute_position(
&REFERENCE,
(&REFERENCE).into(),
&FLOATING,
ComputePositionConfig {
platform: &PLATFORM,
Expand Down
28 changes: 18 additions & 10 deletions packages/core/src/detect_overflow.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use floating_ui_utils::{
get_padding_object, rect_to_client_rect, Coords, OwnedElementOrWindow, Padding, Rect,
SideObject,
get_padding_object, rect_to_client_rect, Coords, ElementOrVirtual, OwnedElementOrWindow,
Padding, Rect, SideObject,
};

use crate::types::{
Expand Down Expand Up @@ -113,20 +113,28 @@ pub fn detect_overflow<Element: Clone, Window: Clone>(
ElementContext::Floating => ElementContext::Reference,
};
let element = match alt_boundary {
true => *elements.get_element_context(alt_context),
false => *elements.get_element_context(element_context),
true => elements.get_element_context(alt_context),
false => elements.get_element_context(element_context),
};

// let document_element = platform.get_document_element(elements.floating);
let document_element = platform.get_document_element(elements.floating);
let context_element: Option<Element>;

let element = match element {
ElementOrVirtual::Element(element) => element,
ElementOrVirtual::VirtualElement(virtual_element) => {
context_element = virtual_element.context_element();

context_element
.as_ref()
.or(document_element.as_ref())
.expect("Element should exist.")
}
};

let clipping_client_rect =
rect_to_client_rect(platform.get_clipping_rect(GetClippingRectArgs {
element,
// TODO: virtual element
// match platform.is_element(element).unwrap_or(true) {
// true => element,
// false => document_element.as_ref().unwrap_or(element),
// },
boundary,
root_boundary,
strategy,
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/middleware/shift.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::{
pub const SHIFT_NAME: &str = "shift";

/// Limiter used by [`Shift`] middleware. Limits the shifting done in order to prevent detachment.
pub trait Limiter<Element, Window>: DynClone {
pub trait Limiter<Element: Clone, Window: Clone>: DynClone {
fn compute(&self, state: MiddlewareState<Element, Window>) -> Coords;
}

Expand Down Expand Up @@ -232,7 +232,7 @@ impl<'a, Element: Clone, Window: Clone>
#[derive(Clone, Debug, Default)]
pub struct DefaultLimiter;

impl<Element, Window> Limiter<Element, Window> for DefaultLimiter {
impl<Element: Clone, Window: Clone> Limiter<Element, Window> for DefaultLimiter {
fn compute(&self, state: MiddlewareState<Element, Window>) -> Coords {
Coords {
x: state.x,
Expand Down Expand Up @@ -278,7 +278,7 @@ impl Default for LimitShiftOffset {

/// Options for [`LimitShift`] limiter.
#[derive(Clone)]
pub struct LimitShiftOptions<'a, Element, Window> {
pub struct LimitShiftOptions<'a, Element: Clone, Window: Clone> {
pub offset: Option<Derivable<'a, Element, Window, LimitShiftOffset>>,

pub main_axis: Option<bool>,
Expand Down
57 changes: 37 additions & 20 deletions packages/core/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ use floating_ui_utils::{

pub type DerivableFn<'a, Element, Window, T> = &'a dyn Fn(MiddlewareState<Element, Window>) -> T;

pub enum Derivable<'a, Element, Window, T: Clone> {
pub enum Derivable<'a, Element: Clone, Window: Clone, T: Clone> {
Value(T),
Fn(DerivableFn<'a, Element, Window, T>),
}

impl<'a, Element, Window, T: Clone> Clone for Derivable<'a, Element, Window, T> {
impl<'a, Element: Clone, Window: Clone, T: Clone> Clone for Derivable<'a, Element, Window, T> {
fn clone(&self) -> Self {
match self {
Self::Value(value) => Self::Value(value.clone()),
Expand All @@ -25,7 +25,7 @@ impl<'a, Element, Window, T: Clone> Clone for Derivable<'a, Element, Window, T>
}
}

impl<'a, Element, Window, T: Clone> Derivable<'a, Element, Window, T> {
impl<'a, Element: Clone, Window: Clone, T: Clone> Derivable<'a, Element, Window, T> {
pub fn evaluate(&self, state: MiddlewareState<Element, Window>) -> T {
match self {
Derivable::Value(value) => value.clone(),
Expand All @@ -34,13 +34,13 @@ impl<'a, Element, Window, T: Clone> Derivable<'a, Element, Window, T> {
}
}

impl<'a, Element, Window, T: Clone> From<T> for Derivable<'a, Element, Window, T> {
impl<'a, Element: Clone, Window: Clone, T: Clone> From<T> for Derivable<'a, Element, Window, T> {
fn from(value: T) -> Self {
Derivable::Value(value)
}
}

impl<'a, Element, Window, T: Clone> From<DerivableFn<'a, Element, Window, T>>
impl<'a, Element: Clone, Window: Clone, T: Clone> From<DerivableFn<'a, Element, Window, T>>
for Derivable<'a, Element, Window, T>
{
fn from(value: DerivableFn<'a, Element, Window, T>) -> Self {
Expand All @@ -64,7 +64,11 @@ pub struct GetClippingRectArgs<'a, Element> {
}

/// Arguments for [`Platform::convert_offset_parent_relative_rect_to_viewport_relative_rect`].
pub struct ConvertOffsetParentRelativeRectToViewportRelativeRectArgs<'a, Element, Window> {
pub struct ConvertOffsetParentRelativeRectToViewportRelativeRectArgs<
'a,
Element: Clone,
Window: Clone,
> {
pub elements: Option<Elements<'a, Element>>,
pub rect: Rect,
pub offset_parent: Option<ElementOrWindow<'a, Element, Window>>,
Expand Down Expand Up @@ -103,7 +107,10 @@ pub trait Platform<Element: Clone, Window: Clone>: Debug {
None
}

fn get_client_rects(&self, _element: &Element) -> Option<Vec<ClientRectObject>> {
fn get_client_rects(
&self,
_element: ElementOrVirtual<Element>,
) -> Option<Vec<ClientRectObject>> {
None
}

Expand Down Expand Up @@ -250,7 +257,7 @@ pub struct MiddlewareReturn {
}

/// Middleware used by [`compute_position`][`crate::compute_position::compute_position`].
pub trait Middleware<Element, Window>: DynClone {
pub trait Middleware<Element: Clone, Window: Clone>: DynClone {
/// The name of this middleware.
fn name(&self) -> &'static str;

Expand All @@ -261,41 +268,51 @@ pub trait Middleware<Element, Window>: DynClone {
dyn_clone::clone_trait_object!(<Element, Window> Middleware<Element, Window>);

/// Middleware with options.
pub trait MiddlewareWithOptions<Element, Window, O: Clone> {
pub trait MiddlewareWithOptions<Element: Clone, Window: Clone, O: Clone> {
/// The options passed to this middleware.
fn options(&self) -> &Derivable<Element, Window, O>;
}

#[derive(Clone, Debug)]
pub struct Elements<'a, Element> {
pub reference: &'a Element,
pub struct Elements<'a, Element: Clone> {
pub reference: ElementOrVirtual<'a, Element>,
pub floating: &'a Element,
}

impl<'a, Element> Elements<'a, Element> {
pub fn get_element_context(&self, element_context: ElementContext) -> &Element {
impl<'a, Element: Clone> Elements<'a, Element> {
pub fn get_element_context(
&self,
element_context: ElementContext,
) -> ElementOrVirtual<'a, Element> {
match element_context {
ElementContext::Reference => self.reference,
ElementContext::Floating => self.floating,
ElementContext::Reference => self.reference.clone(),
ElementContext::Floating => self.floating.into(),
}
}
}

impl<'a, Element: Clone> Clone for Elements<'a, Element> {
fn clone(&self) -> Self {
Self {
reference: self.reference.clone(),
floating: self.floating,
}
}
}

/// State passed to [`Middleware::compute`].
#[derive(Debug)]
pub struct MiddlewareState<'a, Element, Window> {
pub struct MiddlewareState<'a, Element: Clone, Window: Clone> {
pub x: f64,
pub y: f64,
pub initial_placement: Placement,
pub placement: Placement,
pub strategy: Strategy,
pub middleware_data: &'a MiddlewareData,
pub elements: Elements<'a, &'a Element>,
pub elements: Elements<'a, Element>,
pub rects: &'a ElementRects,
pub platform: &'a dyn Platform<Element, Window>,
}

impl<'a, Element, Window> Clone for MiddlewareState<'a, Element, Window> {
impl<'a, Element: Clone, Window: Clone> Clone for MiddlewareState<'a, Element, Window> {
fn clone(&self) -> Self {
Self {
x: self.x,
Expand Down
6 changes: 4 additions & 2 deletions packages/dom/example/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use floating_ui_dom::{
};
use log::Level;
use wasm_bindgen::prelude::*;
use web_sys::HtmlElement;
use web_sys::{Element, HtmlElement};

#[wasm_bindgen(start)]
fn run() -> Result<(), JsValue> {
Expand Down Expand Up @@ -40,14 +40,16 @@ fn run() -> Result<(), JsValue> {
tooltip: &HtmlElement,
arrow: &HtmlElement,
) -> Result<(), JsValue> {
let button_element: &Element = button;

let ComputePositionReturn {
x,
y,
placement,
middleware_data,
..
} = compute_position(
button,
button_element.into(),
tooltip,
Some(
ComputePositionConfig::default()
Expand Down
2 changes: 1 addition & 1 deletion packages/dom/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl ComputePositionConfig {

/// Computes the `x` and `y` coordinates that will place the floating element next to a given reference element.
pub fn compute_position(
reference: &Element,
reference: ElementOrVirtual,
floating: &Element,
config: Option<ComputePositionConfig>,
) -> ComputePositionReturn {
Expand Down
5 changes: 3 additions & 2 deletions packages/dom/src/platform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ use floating_ui_utils::{
};
use web_sys::{Element, Window};

use crate::types::ElementOrVirtual;

use self::convert_offset_parent_relative_rect_to_viewport_relative_rect::convert_offset_parent_relative_rect_to_viewport_relative_rect;
use self::get_client_length::get_client_length;
use self::get_client_rects::get_client_rects;
Expand Down Expand Up @@ -59,15 +61,14 @@ impl CorePlatform<Element, Window> for Platform {
}

fn is_element(&self, _value: &ElementOrWindow<Element, Window>) -> Option<bool> {
// TODO: value should probably be expanded in CorePlatform
Some(true)
}

fn get_document_element(&self, element: &Element) -> Option<Element> {
Some(get_document_element(Some(element.into())))
}

fn get_client_rects(&self, element: &Element) -> Option<Vec<ClientRectObject>> {
fn get_client_rects(&self, element: ElementOrVirtual) -> Option<Vec<ClientRectObject>> {
Some(get_client_rects(element))
}

Expand Down
Loading

0 comments on commit 232d9ae

Please sign in to comment.