#![deny(missing_docs)]
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use wasm_bindgen::{prelude::Closure, JsCast};
use web_sys::HtmlIFrameElement;
use yew::{html, Callback, Component, NodeRef, Properties};
const IFRAME_STYLE: &str = "display: block; position: absolute; top: 0; left: 0; width: 100%; height: 100%; overflow: hidden; border: 0; opacity: 0; pointer-events: none; z-index: -1;";
#[derive(Debug)]
pub struct ComponentSizeObserver {
props: Props,
iframe_ref: NodeRef,
on_resize: Option<Closure<dyn Fn()>>,
}
#[derive(Properties, Clone, PartialEq, Debug)]
pub struct Props {
pub onsize: Callback<ComponentSize>,
}
#[derive(Default, Clone, PartialEq, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct ComponentSize {
pub width: f64,
pub height: f64,
}
impl Component for ComponentSizeObserver {
type Message = ();
type Properties = Props;
fn create(props: Self::Properties, _link: yew::ComponentLink<Self>) -> Self {
Self {
props,
iframe_ref: Default::default(),
on_resize: None,
}
}
fn update(&mut self, _msg: Self::Message) -> yew::ShouldRender {
false
}
fn change(&mut self, props: Self::Properties) -> yew::ShouldRender {
if self.props != props {
self.props = props;
self.add_resize_listener();
false
} else {
false
}
}
fn view(&self) -> yew::Html {
html! {
<iframe style=IFRAME_STYLE ref=self.iframe_ref.clone() />
}
}
fn rendered(&mut self, first_render: bool) {
if first_render {
self.add_resize_listener();
}
}
}
impl ComponentSizeObserver {
fn add_resize_listener(&mut self) {
let iframe = self.iframe_ref.cast::<HtmlIFrameElement>().unwrap();
let window = iframe.content_window().unwrap();
let iframe_ref = self.iframe_ref.clone();
let size_callback = self.props.onsize.clone();
let on_resize = Closure::wrap(Box::new(move || {
let iframe = iframe_ref.cast::<HtmlIFrameElement>().unwrap();
let bcr = iframe.get_bounding_client_rect();
size_callback.emit(ComponentSize {
width: bcr.width(),
height: bcr.height(),
});
}) as Box<dyn Fn()>);
window.set_onresize(Some(on_resize.as_ref().unchecked_ref()));
self.on_resize = Some(on_resize);
}
}