floating_ui_yew/
arrow.rs

1use floating_ui_dom::{
2    ARROW_NAME, Arrow as CoreArrow, ArrowOptions as CoreArrowOptions, Middleware, MiddlewareReturn,
3    MiddlewareState, Padding,
4};
5use web_sys::wasm_bindgen::JsCast;
6use yew::NodeRef;
7
8/// Options for [`Arrow`].
9#[derive(Clone, PartialEq)]
10pub struct ArrowOptions {
11    /// The arrow element to be positioned.
12    pub element: NodeRef,
13
14    /// The padding between the arrow element and the floating element edges.
15    /// Useful when the floating element has rounded corners.
16    ///
17    /// Defaults to `0` on all sides.
18    pub padding: Option<Padding>,
19}
20
21impl ArrowOptions {
22    pub fn new(element: NodeRef) -> Self {
23        ArrowOptions {
24            element,
25            padding: None,
26        }
27    }
28
29    /// Set `element` option.
30    pub fn element(mut self, value: NodeRef) -> Self {
31        self.element = value;
32        self
33    }
34
35    /// Set `padding` option.
36    pub fn padding(mut self, value: Padding) -> Self {
37        self.padding = Some(value);
38        self
39    }
40}
41
42/// Arrow middleware.
43///
44/// Provides data to position an inner element of the floating element so that it appears centered to the reference element.
45///
46/// See [the Rust Floating UI book](https://floating-ui.rustforweb.org/middleware/arrow.html) for more documentation.
47#[derive(Clone, PartialEq)]
48pub struct Arrow {
49    options: ArrowOptions,
50}
51
52impl Arrow {
53    pub fn new(options: ArrowOptions) -> Self {
54        Arrow { options }
55    }
56}
57
58impl Middleware<web_sys::Element, web_sys::Window> for Arrow {
59    fn name(&self) -> &'static str {
60        ARROW_NAME
61    }
62
63    fn compute(
64        &self,
65        state: MiddlewareState<web_sys::Element, web_sys::Window>,
66    ) -> MiddlewareReturn {
67        match self.options.element.get() {
68            Some(element) => CoreArrow::new(CoreArrowOptions {
69                element: element
70                    .dyn_into()
71                    .expect("Arrow element should be an Element."),
72                padding: self.options.padding.clone(),
73            })
74            .compute(state),
75            _ => MiddlewareReturn {
76                x: None,
77                y: None,
78                data: None,
79                reset: None,
80            },
81        }
82    }
83}