mirror of
https://github.com/leptos-rs/leptos
synced 2024-11-10 06:44:17 +00:00
Merge branch 'leptos_dom_v2' of https://github.com/jquesada2016/leptos into leptos_dom_v2
This commit is contained in:
commit
b06a4ba805
5 changed files with 142 additions and 48 deletions
|
@ -23,7 +23,7 @@ pub fn location() -> web_sys::Location {
|
|||
/// Current [`window.location.hash`](https://developer.mozilla.org/en-US/docs/Web/API/Window/location)
|
||||
/// without the beginning #.
|
||||
pub fn location_hash() -> Option<String> {
|
||||
if is_server!() {
|
||||
if is_server() {
|
||||
None
|
||||
} else {
|
||||
location().hash().ok().map(|hash| hash.replace('#', ""))
|
||||
|
@ -125,7 +125,7 @@ pub fn window_event_listener(
|
|||
event_name: &str,
|
||||
cb: impl Fn(web_sys::Event) + 'static,
|
||||
) {
|
||||
if !is_server!() {
|
||||
if !is_server() {
|
||||
let handler = Box::new(cb) as Box<dyn FnMut(web_sys::Event)>;
|
||||
|
||||
let cb = Closure::wrap(handler).into_js_value();
|
||||
|
|
|
@ -14,9 +14,6 @@ use crate::{
|
|||
};
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
use crate::{mount_child, MountKind};
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
use std::cell::OnceCell;
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
use leptos_reactive::create_render_effect;
|
||||
|
@ -29,6 +26,13 @@ use std::{cell::LazyCell, ops::Deref};
|
|||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
use wasm_bindgen::JsCast;
|
||||
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
const HTML_ELEMENT_DEREF_UNIMPLEMENTED_MSG: &str =
|
||||
"`Deref<Target = web_sys::HtmlElement>` can only be used on web targets. \
|
||||
This is for the same reason that normal `wasm_bindgen` methods can be used \
|
||||
only in the browser. Please use `leptos::is_server()` or \
|
||||
`leptos::is_browser()` to check where you're running.";
|
||||
|
||||
/// Trait alias for the trait bounts on [`IntoElement`].
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
pub trait IntoElementBounds:
|
||||
|
@ -69,7 +73,8 @@ pub trait IntoElement: IntoElementBounds {
|
|||
fn hydration_id(&self) -> usize;
|
||||
}
|
||||
|
||||
/// Trait for converting [`web_sys::Element`] to [`HtmlElement`].
|
||||
/// Trait for converting any type which impl [`AsRef<web_sys::Element>`]
|
||||
/// to [`HtmlElement`].
|
||||
pub trait ToHtmlElement {
|
||||
/// Converts the type to [`HtmlElement`].
|
||||
fn to_leptos_element(self, cx: Scope) -> HtmlElement<AnyElement>;
|
||||
|
@ -104,16 +109,25 @@ where
|
|||
|
||||
/// Represents potentially any element.
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(all(target_arch = "wasm32", feature = "web"), derive(educe::Educe))]
|
||||
#[cfg_attr(all(target_arch = "wasm32", feature = "web"), educe(Deref))]
|
||||
pub struct AnyElement {
|
||||
name: Cow<'static, str>,
|
||||
pub(crate) name: Cow<'static, str>,
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
#[educe(Deref)]
|
||||
element: web_sys::HtmlElement,
|
||||
is_void: bool,
|
||||
pub(crate) element: web_sys::HtmlElement,
|
||||
pub(crate) is_void: bool,
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
id: usize,
|
||||
pub(crate) id: usize,
|
||||
}
|
||||
|
||||
impl std::ops::Deref for AnyElement {
|
||||
type Target = web_sys::HtmlElement;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
return &self.element;
|
||||
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
unimplemented!("{HTML_ELEMENT_DEREF_UNIMPLEMENTED_MSG}");
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoElement for AnyElement {
|
||||
|
@ -174,12 +188,9 @@ impl IntoElement for Custom {
|
|||
cfg_if! {
|
||||
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
|
||||
/// Represents an HTML element.
|
||||
#[derive(educe::Educe)]
|
||||
#[educe(Debug, Deref)]
|
||||
pub struct HtmlElement<El: IntoElement> {
|
||||
cx: Scope,
|
||||
#[educe(Deref)]
|
||||
element: El,
|
||||
pub(crate) cx: Scope,
|
||||
pub(crate) element: El,
|
||||
}
|
||||
// Server needs to build a virtualized DOM tree
|
||||
} else {
|
||||
|
@ -189,7 +200,6 @@ cfg_if! {
|
|||
pub struct HtmlElement<El: IntoElement> {
|
||||
pub(crate) cx: Scope,
|
||||
pub(crate) element: El,
|
||||
pub(crate) id: OnceCell<Cow<'static, str>>,
|
||||
#[educe(Debug(ignore))]
|
||||
pub(crate) attrs: SmallVec<[(Cow<'static, str>, Cow<'static, str>); 4]>,
|
||||
#[educe(Debug(ignore))]
|
||||
|
@ -199,6 +209,18 @@ cfg_if! {
|
|||
}
|
||||
}
|
||||
|
||||
impl<El: IntoElement> std::ops::Deref for HtmlElement<El> {
|
||||
type Target = web_sys::HtmlElement;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
return &self.element;
|
||||
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
unimplemented!("{HTML_ELEMENT_DEREF_UNIMPLEMENTED_MSG}");
|
||||
}
|
||||
}
|
||||
|
||||
impl<El: IntoElement> HtmlElement<El> {
|
||||
fn new(cx: Scope, element: El) -> Self {
|
||||
cfg_if! {
|
||||
|
@ -210,7 +232,6 @@ impl<El: IntoElement> HtmlElement<El> {
|
|||
} else {
|
||||
Self {
|
||||
cx,
|
||||
id: Default::default(),
|
||||
attrs: smallvec![],
|
||||
children: smallvec![],
|
||||
element,
|
||||
|
@ -239,7 +260,6 @@ impl<El: IntoElement> HtmlElement<El> {
|
|||
} else {
|
||||
let Self {
|
||||
cx,
|
||||
id,
|
||||
attrs,
|
||||
children,
|
||||
element,
|
||||
|
@ -247,7 +267,6 @@ impl<El: IntoElement> HtmlElement<El> {
|
|||
|
||||
HtmlElement {
|
||||
cx,
|
||||
id,
|
||||
attrs,
|
||||
children,
|
||||
element: AnyElement {
|
||||
|
@ -608,12 +627,9 @@ macro_rules! generate_html_tags {
|
|||
});
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
#[cfg_attr(all(target_arch = "wasm32", feature = "web"), derive(educe::Educe))]
|
||||
#[cfg_attr(all(target_arch = "wasm32", feature = "web"), educe(Deref))]
|
||||
#[$meta]
|
||||
pub struct [<$tag:camel $($trailing_)?>] {
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
#[educe(Deref)]
|
||||
element: web_sys::HtmlElement,
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
id: usize,
|
||||
|
@ -677,6 +693,18 @@ macro_rules! generate_html_tags {
|
|||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for [<$tag:camel $($trailing_)?>] {
|
||||
type Target = web_sys::HtmlElement;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
return &self.element;
|
||||
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
unimplemented!("{HTML_ELEMENT_DEREF_UNIMPLEMENTED_MSG}");
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoElement for [<$tag:camel $($trailing_)?>] {
|
||||
fn name(&self) -> Cow<'static, str> {
|
||||
stringify!($tag).into()
|
||||
|
|
|
@ -177,6 +177,46 @@ cfg_if! {
|
|||
}
|
||||
}
|
||||
|
||||
impl Element {
|
||||
/// Converts this leptos [`Element`] into [`HtmlElement<AnyElement`].
|
||||
pub fn into_html_element(self, cx: Scope) -> HtmlElement<AnyElement> {
|
||||
#[cfg(all(target_arch = "wasm32", feature = "web"))]
|
||||
{
|
||||
let Self { element, .. } = self;
|
||||
|
||||
let name = element.node_name().to_ascii_lowercase();
|
||||
|
||||
let element = AnyElement {
|
||||
name: name.into(),
|
||||
element,
|
||||
is_void: false,
|
||||
};
|
||||
|
||||
HtmlElement { cx, element }
|
||||
}
|
||||
|
||||
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
|
||||
{
|
||||
let Self {
|
||||
name,
|
||||
is_void,
|
||||
attrs,
|
||||
children,
|
||||
id,
|
||||
} = self;
|
||||
|
||||
let element = AnyElement { name, is_void, id };
|
||||
|
||||
HtmlElement {
|
||||
cx,
|
||||
element,
|
||||
attrs,
|
||||
children: children.into_iter().collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoView for Element {
|
||||
#[cfg_attr(debug_assertions, instrument(level = "trace", name = "<Element />", skip_all, fields(tag = %self.name)))]
|
||||
fn into_view(self, _: Scope) -> View {
|
||||
|
@ -451,6 +491,19 @@ impl View {
|
|||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns [`Ok(HtmlElement<AnyElement>)`] if this [`View`] is
|
||||
/// of type [`Element`]. [`Err(View)`] otherwise.
|
||||
pub fn into_html_element(
|
||||
self,
|
||||
cx: Scope,
|
||||
) -> Result<HtmlElement<AnyElement>, Self> {
|
||||
if let Self::Element(el) = self {
|
||||
Ok(el.into_html_element(cx))
|
||||
} else {
|
||||
Err(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(debug_assertions, instrument)]
|
||||
|
@ -553,7 +606,7 @@ pub fn document() -> web_sys::Document {
|
|||
DOCUMENT.with(|document| document.clone())
|
||||
}
|
||||
|
||||
/// Shorthand to test for whether an `ssr` feature is enabled.
|
||||
/// Returns true if running on the server (SSR).
|
||||
///
|
||||
/// In the past, this was implemented by checking whether `not(target_arch = "wasm32")`.
|
||||
/// Now that some cloud platforms are moving to run Wasm on the edge, we really can't
|
||||
|
@ -562,31 +615,44 @@ pub fn document() -> web_sys::Document {
|
|||
///
|
||||
/// ```
|
||||
/// # use leptos_dom::is_server;
|
||||
/// let todos = if is_server!() {
|
||||
/// let todos = if is_server() {
|
||||
/// // if on the server, load from DB
|
||||
/// } else {
|
||||
/// // if on the browser, do something else
|
||||
/// };
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! is_server {
|
||||
() => {
|
||||
!cfg!(all(target_arch = "wasm32", feature = "web"))
|
||||
};
|
||||
pub const fn is_server() -> bool {
|
||||
cfg!(all(target_arch = "wasm32", feature = "web"))
|
||||
}
|
||||
|
||||
/// A shorthand macro to test whether this is a debug build.
|
||||
/// Returns true if running on the browser (CSR).
|
||||
///
|
||||
/// ```
|
||||
/// # use leptos_dom::is_browser;
|
||||
/// let todos = if is_browser() {
|
||||
/// // if on the browser, call `wasm_bindgen` methods
|
||||
/// } else {
|
||||
/// // if on the server, do something else
|
||||
/// };
|
||||
/// ```
|
||||
pub const fn is_browser() -> bool {
|
||||
!is_server()
|
||||
}
|
||||
|
||||
/// Returns true if `debug_assertions` are enabled.
|
||||
/// ```
|
||||
/// # use leptos_dom::is_dev;
|
||||
/// if is_dev!() {
|
||||
/// // log something or whatever
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! is_dev {
|
||||
() => {
|
||||
cfg!(debug_assertions)
|
||||
};
|
||||
pub const fn is_dev() -> bool {
|
||||
cfg!(debug_assertions)
|
||||
}
|
||||
|
||||
/// Returns true if `debug_assertions` are disabled.
|
||||
pub const fn is_release() -> bool {
|
||||
!is_dev()
|
||||
}
|
||||
|
||||
macro_rules! impl_into_view_for_tuples {
|
||||
|
@ -673,6 +739,12 @@ impl IntoView for String {
|
|||
}
|
||||
}
|
||||
|
||||
impl IntoView for &'static str {
|
||||
fn into_view(self, _: Scope) -> View {
|
||||
View::Text(Text::new(self.into()))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! viewable_primitive {
|
||||
($child_type:ty) => {
|
||||
impl IntoView for $child_type {
|
||||
|
@ -683,12 +755,6 @@ macro_rules! viewable_primitive {
|
|||
};
|
||||
}
|
||||
|
||||
impl IntoView for &'static str {
|
||||
fn into_view(self, cx: Scope) -> View {
|
||||
View::Text(Text::new(self.into()))
|
||||
}
|
||||
}
|
||||
|
||||
viewable_primitive!(&String);
|
||||
viewable_primitive!(usize);
|
||||
viewable_primitive!(u8);
|
||||
|
|
|
@ -44,7 +44,7 @@ macro_rules! debug_warn {
|
|||
/// Log a string to the console (in the browser)
|
||||
/// or via `println!()` (if not in the browser).
|
||||
pub fn console_log(s: &str) {
|
||||
if is_server!() {
|
||||
if is_server() {
|
||||
println!("{}", s);
|
||||
} else {
|
||||
web_sys::console::log_1(&JsValue::from_str(s));
|
||||
|
@ -54,7 +54,7 @@ pub fn console_log(s: &str) {
|
|||
/// Log a warning to the console (in the browser)
|
||||
/// or via `println!()` (if not in the browser).
|
||||
pub fn console_warn(s: &str) {
|
||||
if is_server!() {
|
||||
if is_server() {
|
||||
eprintln!("{}", s);
|
||||
} else {
|
||||
web_sys::console::warn_1(&JsValue::from_str(s));
|
||||
|
@ -64,7 +64,7 @@ pub fn console_warn(s: &str) {
|
|||
/// Log an error to the console (in the browser)
|
||||
/// or via `println!()` (if not in the browser).
|
||||
pub fn console_error(s: &str) {
|
||||
if is_server!() {
|
||||
if is_server() {
|
||||
eprintln!("{}", s);
|
||||
} else {
|
||||
web_sys::console::warn_1(&JsValue::from_str(s));
|
||||
|
@ -76,7 +76,7 @@ pub fn console_error(s: &str) {
|
|||
pub fn console_debug_warn(s: &str) {
|
||||
cfg_if! {
|
||||
if #[cfg(debug_assertions)] {
|
||||
if is_server!() {
|
||||
if is_server() {
|
||||
eprintln!("{}", s);
|
||||
} else {
|
||||
web_sys::console::warn_1(&JsValue::from_str(s));
|
||||
|
|
Loading…
Reference in a new issue