Compare commits

..

1 Commits

Author SHA1 Message Date
Greg Johnston
d8eafe1d2c Fix missing docs error 2023-01-27 12:29:06 -05:00
24 changed files with 171 additions and 264 deletions

View File

@@ -24,17 +24,17 @@ members = [
exclude = ["benchmarks", "examples"]
[workspace.package]
version = "0.1.3"
version = "0.1.1"
[workspace.dependencies]
leptos = { path = "./leptos", default-features = false, version = "0.1.3" }
leptos_dom = { path = "./leptos_dom", default-features = false, version = "0.1.3" }
leptos_macro = { path = "./leptos_macro", default-features = false, version = "0.1.3" }
leptos_reactive = { path = "./leptos_reactive", default-features = false, version = "0.1.3" }
leptos_server = { path = "./leptos_server", default-features = false, version = "0.1.3" }
leptos_config = { path = "./leptos_config", default-features = false, version = "0.1.3" }
leptos_router = { path = "./router", version = "0.1.3" }
leptos_meta = { path = "./meta", default-feature = false, version = "0.1.3" }
leptos = { path = "./leptos", default-features = false, version = "0.1.1" }
leptos_dom = { path = "./leptos_dom", default-features = false, version = "0.1.1" }
leptos_macro = { path = "./leptos_macro", default-features = false, version = "0.1.1" }
leptos_reactive = { path = "./leptos_reactive", default-features = false, version = "0.1.1" }
leptos_server = { path = "./leptos_server", default-features = false, version = "0.1.1" }
leptos_config = { path = "./leptos_config", default-features = false, version = "0.1.1" }
leptos_router = { path = "./router", version = "0.1.1" }
leptos_meta = { path = "./meta", default-feature = false, version = "0.1.1" }
[profile.release]
codegen-units = 1

View File

@@ -4,4 +4,4 @@ version = "0.1.0"
edition = "2021"
[dependencies]
leptos = "0.1"
leptos = "0.0.18"

View File

@@ -1,5 +1,5 @@
use leptos::*;
fn main() {
mount_to_body(|cx| view! { cx, <p>"Hello, world!"</p> })
mount_to_body(|_cx| view! { cx, <p>"Hello, world!"</p> })
}

View File

@@ -4,4 +4,4 @@ version = "0.1.0"
edition = "2021"
[dependencies]
leptos = "0.1"
leptos = "0.0.18"

View File

@@ -4,9 +4,7 @@ fn main() {
mount_to_body(|cx| {
let name = "gbj";
let userid = 0;
// This will be filled by _ref=input below.
let input_element = NodeRef::<HtmlElement<Input>>::new(cx);
let _input_element: Element;
view! {
cx,
@@ -19,7 +17,7 @@ fn main() {
prop:value="todo" // `prop:` lets you set a property on a DOM node
value="initial" // side note: the DOM `value` attribute only sets *initial* value
// this is very important when working with forms!
_ref=input_element // `_ref` stores tis element in a variable
_ref=_input_element // `_ref` stores tis element in a variable
/>
<ul data-user=userid> // attributes can take expressions as values
<li class="todo my-todo" // here we set the `class` attribute

View File

@@ -4,4 +4,4 @@ version = "0.1.0"
edition = "2021"
[dependencies]
leptos = "0.1"
leptos = "0.0.18"

View File

@@ -6,7 +6,7 @@ const APP_ID: &str = "dev.leptos.Counter";
// Basic GTK app setup from https://gtk-rs.org/gtk4-rs/stable/latest/book/hello_world.html
fn main() {
_ = create_scope(create_runtime(), |cx| {
_ = create_scope(|cx| {
// Create a new application
let app = Application::builder().application_id(APP_ID).build();

View File

@@ -11,7 +11,6 @@ console_error_panic_hook = "0.1.7"
uuid = { version = "1", features = ["v4", "js", "serde"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
web-sys = { version = "0.3", features = ["Storage"] }
[dev-dependencies]
wasm-bindgen-test = "0.3.0"

View File

@@ -2,29 +2,6 @@ use leptos_dom::{Errors, Fragment, IntoView};
use leptos_macro::component;
use leptos_reactive::{create_rw_signal, provide_context, RwSignal, Scope};
/// When you render a `Result<_, _>` in your view, in the `Err` case it will
/// render nothing, and search up through the view tree for an `<ErrorBoundary/>`.
/// This component lets you define a fallback that should be rendered in that
/// error case, allowing you to handle errors within a section of the interface.
///
/// ```
/// # use leptos_reactive::*;
/// # use leptos_macro::*;
/// # use leptos_dom::*; use leptos::*;
/// # run_scope(create_runtime(), |cx| {
/// let (value, set_value) = create_signal(cx, Ok(0));
/// let on_input = move |ev| set_value(event_target_value(&ev).parse::<i32>());
///
/// view! { cx,
/// <input type="text" on:input=on_input/>
/// <ErrorBoundary
/// fallback=move |_, _| view! { cx, <p class="error">"Enter a valid number."</p>}
/// >
/// <p>"Value is: " {value}</p>
/// </ErrorBoundary>
/// }
/// # });
/// ```
#[component(transparent)]
pub fn ErrorBoundary<F, IV>(
cx: Scope,

View File

@@ -3,27 +3,8 @@ use leptos_dom::{Fragment, IntoView};
use leptos_reactive::Scope;
use once_cell::sync::Lazy;
/// A component that will show its children when the `when` condition is `true`,
/// and show the fallback when it is `false`, without rerendering every time
/// the condition changes.
///
/// ```rust
/// # use leptos_reactive::*;
/// # use leptos_macro::*;
/// # use leptos_dom::*; use leptos::*;
/// # run_scope(create_runtime(), |cx| {
/// let (value, set_value) = create_signal(cx, 0);
///
/// view! { cx,
/// <Show
/// when=move || value() < 5
/// fallback=|cx| view! { cx, "Big number!" }
/// >
/// "Small number!"
/// </Show>
/// }
/// # });
/// ```
/// A component that will show it's children when the passed in closure is True, and show the fallback
/// when the closure is false
#[component]
pub fn Show<F, W, IV>(
/// The scope the component is running in

View File

@@ -12,6 +12,7 @@ cfg-if = "1"
drain_filter_polyfill = "0.1"
educe = "0.4"
futures = "0.3"
gloo = { version = "0.8", features = ["futures"] }
html-escape = "0.2"
indexmap = "1.9"
itertools = "0.10"
@@ -33,11 +34,8 @@ leptos = { path = "../leptos" }
[dependencies.web-sys]
version = "0.3"
features = [
"console",
"Comment",
"Document",
"DomTokenList",
"Location",
"Range",
"Text",
"HtmlCollection",
@@ -51,7 +49,6 @@ features = [
"DeviceMotionEvent",
"DeviceOrientationEvent",
"DragEvent",
"ErrorEvent",
"FocusEvent",
"GamepadEvent",
"HashChangeEvent",

View File

@@ -19,28 +19,23 @@ where
match use_context::<RwSignal<Errors>>(cx) {
Some(errors) => {
let id = HydrationCtx::id();
errors.update({
#[cfg(all(target_arch = "wasm32", feature = "web"))]
let id = id.clone();
move |errors: &mut Errors| errors.insert(id, error)
});
errors.update(move |errors: &mut Errors| errors.insert(id, error));
// remove the error from the list if this drops,
// i.e., if it's in a DynChild that switches from Err to Ok
// Only can run on the client, will panic on the server
cfg_if! {
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
use leptos_reactive::{on_cleanup, queue_microtask};
on_cleanup(cx, move || {
queue_microtask(move || {
errors.update(|errors: &mut Errors| {
crate::log!("removing error at {id}");
errors.remove::<E>(&id);
});
});
if #[cfg(any(feature = "hydrate", feature="csr"))] {
use leptos_reactive::{on_cleanup, queue_microtask};
on_cleanup(cx, move || {
queue_microtask(move || {
errors.update(|errors: &mut Errors| {
errors.remove::<E>(&id);
});
});
});
}
}
}
}
None => {
#[cfg(debug_assertions)]

View File

@@ -6,8 +6,12 @@ use cfg_if::cfg_if;
cfg_if! {
if #[cfg(all(target_arch = "wasm32", feature = "web"))] {
use crate::events::*;
use crate::macro_helpers::*;
use crate::macro_helpers::Property;
use crate::macro_helpers::{
attribute_expression, class_expression, property_expression,
};
use crate::{mount_child, MountKind};
use leptos_reactive::create_render_effect;
use once_cell::unsync::Lazy as LazyCell;
use wasm_bindgen::JsCast;
@@ -42,7 +46,7 @@ cfg_if! {
use crate::{
ev::EventDescriptor,
hydration::HydrationCtx,
macro_helpers::{IntoAttribute, IntoClass, IntoProperty},
macro_helpers::{Attribute, Class, IntoAttribute, IntoClass, IntoProperty},
Element, Fragment, IntoView, NodeRef, Text, View,
};
use leptos_reactive::Scope;
@@ -199,8 +203,10 @@ impl Custom {
el.unchecked_into()
} else {
crate::warn!(
"element with id {id} not found, ignoring it for hydration"
gloo::console::warn!(
"element with id",
format!("_{id}"),
"not found, ignoring it for hydration"
);
crate::document().create_element(&name).unwrap()
@@ -489,18 +495,26 @@ impl<El: ElementDescriptor + 'static> HtmlElement<El> {
#[cfg(all(target_arch = "wasm32", feature = "web"))]
{
attribute_helper(
self.element.as_ref(),
name,
attr.into_attribute(self.cx),
);
let el = self.element.as_ref();
let value = attr.into_attribute(self.cx);
match value {
Attribute::Fn(cx, f) => {
let el = el.clone();
create_render_effect(cx, move |old| {
let new = f();
if old.as_ref() != Some(&new) {
attribute_expression(&el, &name, new.clone());
}
new
});
}
_ => attribute_expression(el, &name, value),
};
self
}
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
{
use crate::macro_helpers::Attribute;
let mut this = self;
let mut attr = attr.into_attribute(this.cx);
@@ -540,16 +554,26 @@ impl<El: ElementDescriptor + 'static> HtmlElement<El> {
#[cfg(all(target_arch = "wasm32", feature = "web"))]
{
let el = self.element.as_ref();
let class_list = el.class_list();
let value = class.into_class(self.cx);
class_helper(el, name, value);
match value {
Class::Fn(cx, f) => {
create_render_effect(cx, move |old| {
let new = f();
if old.as_ref() != Some(&new) && (old.is_some() || new) {
class_expression(&class_list, &name, new)
}
new
});
}
Class::Value(value) => class_expression(&class_list, &name, value),
};
self
}
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
{
use crate::macro_helpers::Class;
let mut this = self;
let class = class.into_class(this.cx);
@@ -585,7 +609,25 @@ impl<El: ElementDescriptor + 'static> HtmlElement<El> {
let name = name.into();
let value = value.into_property(self.cx);
let el = self.element.as_ref();
property_helper(el, name, value);
match value {
Property::Fn(cx, f) => {
let el = el.clone();
create_render_effect(cx, move |old| {
let new = f();
let prop_name = wasm_bindgen::intern(&name);
if old.as_ref() != Some(&new)
&& !(old.is_none() && new == wasm_bindgen::JsValue::UNDEFINED)
{
property_expression(&el, prop_name, new.clone())
}
new
});
}
Property::Value(value) => {
let prop_name = wasm_bindgen::intern(&name);
property_expression(el, prop_name, value)
}
};
}
#[cfg(not(all(target_arch = "wasm32", feature = "web")))]
@@ -806,18 +848,63 @@ macro_rules! generate_html_tags {
let id = HydrationCtx::id();
#[cfg(all(target_arch = "wasm32", feature = "web"))]
let element = create_leptos_element(
&stringify!([<$tag:upper>]),
id,
|| {
let element = if HydrationCtx::is_hydrating() {
if let Some(el) = crate::document().get_element_by_id(
&format!("_{id}")
) {
#[cfg(debug_assertions)]
assert_eq!(
el.node_name().to_ascii_uppercase(),
stringify!([<$tag:upper>]),
"SSR and CSR elements have the same `TopoId` \
but different node kinds. This is either a \
discrepancy between SSR and CSR rendering
logic, which is considered a bug, or it \
can also be a leptos hydration issue."
);
el.remove_attribute("id").unwrap();
el.unchecked_into()
} else if let Ok(Some(el)) = crate::document().query_selector(
&format!("[leptos-hk=_{id}]")
) {
#[cfg(debug_assertions)]
assert_eq!(
el.node_name().to_ascii_uppercase(),
stringify!([<$tag:upper>]),
"SSR and CSR elements have the same `TopoId` \
but different node kinds. This is either a \
discrepancy between SSR and CSR rendering
logic, which is considered a bug, or it \
can also be a leptos hydration issue."
);
el.remove_attribute("leptos-hk").unwrap();
el.unchecked_into()
} else {
gloo::console::warn!(
"element with id",
format!("_{id}"),
"not found, ignoring it for hydration"
);
[<$tag:upper>]
.with(|el|
el.clone_node()
.unwrap()
.unchecked_into()
)
}
} else {
[<$tag:upper>]
.with(|el|
el.clone_node()
.unwrap()
.unchecked_into()
)
}
);
};
Self {
#[cfg(all(target_arch = "wasm32", feature = "web"))]
@@ -892,70 +979,24 @@ macro_rules! generate_html_tags {
}
}
#[cfg(all(target_arch = "wasm32", feature = "web"))]
fn create_leptos_element(
tag: &str,
id: crate::HydrationKey,
clone_element: fn() -> web_sys::HtmlElement,
) -> web_sys::HtmlElement {
if HydrationCtx::is_hydrating() {
if let Some(el) = crate::document().get_element_by_id(&format!("_{id}")) {
#[cfg(debug_assertions)]
assert_eq!(
&el.node_name().to_ascii_uppercase(),
tag,
"SSR and CSR elements have the same `TopoId` but different node \
kinds. This is either a discrepancy between SSR and CSR rendering
logic, which is considered a bug, or it can also be a leptos \
hydration issue."
);
el.remove_attribute("id").unwrap();
el.unchecked_into()
} else if let Ok(Some(el)) =
crate::document().query_selector(&format!("[leptos-hk=_{id}]"))
{
#[cfg(debug_assertions)]
assert_eq!(
el.node_name().to_ascii_uppercase(),
tag,
"SSR and CSR elements have the same `TopoId` but different node \
kinds. This is either a discrepancy between SSR and CSR rendering
logic, which is considered a bug, or it can also be a leptos \
hydration issue."
);
el.remove_attribute("leptos-hk").unwrap();
el.unchecked_into()
} else {
crate::warn!("element with id {id} not found, ignoring it for hydration");
clone_element()
}
} else {
clone_element()
}
}
#[cfg(all(debug_assertions, target_arch = "wasm32", feature = "web"))]
fn warn_on_ambiguous_a(parent: &web_sys::Element, child: &View) {
if let View::Element(el) = &child {
if (el.name == "a"
if el.name == "a"
|| el.name == "script"
|| el.name == "style"
|| el.name == "title")
&& parent.namespace_uri() != el.element.namespace_uri()
|| el.name == "title"
{
crate::warn!(
"Warning: you are appending an SVG element to an HTML element, or an \
HTML element to an SVG. Typically, this occurs when you create an \
<a/> or <script/> with the `view` macro and append it to an SVG, but \
the framework assumed it was HTML when you created it. To specify \
that it is an SVG element, use <svg::{{tag name}}/> in the view \
macro."
)
if parent.namespace_uri() != el.element.namespace_uri() {
crate::warn!(
"Warning: you are appending an SVG element to an HTML element, or \
an HTML element to an SVG. Typically, this occurs when you create \
an <a/> or <script/> with the `view` macro and append it to an \
SVG, but the framework assumed it was HTML when you created it. To \
specify that it is an SVG element, use <svg::{{tag name}}/> in the \
view macro."
)
}
}
}
}

View File

@@ -95,8 +95,10 @@ macro_rules! generate_math_tags {
el.unchecked_into()
} else {
crate::warn!(
"element with id {id} not found, ignoring it for hydration"
gloo::console::warn!(
"element with id",
format!("_{id}"),
"not found, ignoring it for hydration"
);
[<$tag:upper $(_ $second:upper $(_ $third:upper)?)?>]

View File

@@ -92,8 +92,10 @@ macro_rules! generate_svg_tags {
el.unchecked_into()
} else {
crate::warn!(
"element with id {id} not found, ignoring it for hydration"
gloo::console::warn!(
"element with id",
format!("_{id}"),
"not found, ignoring it for hydration"
);
[<$tag:upper $(_ $second:upper $(_ $third:upper)?)?>]

View File

@@ -21,7 +21,7 @@ cfg_if! {
while let Ok(Some(node)) = walker.next_node() {
if let Some(content) = node.text_content() {
if let Some(hk) = content.strip_prefix("hk=") {
if let Some(hk) = hk.split('|').next() {
if let Some(hk) = hk.split("|").next() {
map.insert(hk.into(), node.unchecked_into());
}
}

View File

@@ -308,8 +308,10 @@ impl Comment {
marker.remove();
} else {
crate::warn!(
"component with id {id} not found, ignoring it for hydration"
gloo::console::warn!(
"component with id",
id,
"not found, ignoring it for hydration"
);
}
}

View File

@@ -168,30 +168,6 @@ attr_type!(f32);
attr_type!(f64);
attr_type!(char);
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use std::borrow::Cow;
#[cfg(all(target_arch = "wasm32", feature = "web"))]
pub(crate) fn attribute_helper(
el: &web_sys::Element,
name: Cow<'static, str>,
value: Attribute,
) {
use leptos_reactive::create_render_effect;
match value {
Attribute::Fn(cx, f) => {
let el = el.clone();
create_render_effect(cx, move |old| {
let new = f();
if old.as_ref() != Some(&new) {
attribute_expression(&el, &name, new.clone());
}
new
});
}
_ => attribute_expression(el, &name, value),
};
}
#[cfg(all(target_arch = "wasm32", feature = "web"))]
pub(crate) fn attribute_expression(
el: &web_sys::Element,

View File

@@ -66,32 +66,6 @@ impl<T: IntoClass> IntoClass for (Scope, T) {
}
}
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use std::borrow::Cow;
#[cfg(all(target_arch = "wasm32", feature = "web"))]
pub(crate) fn class_helper(
el: &web_sys::Element,
name: Cow<'static, str>,
value: Class,
) {
use leptos_reactive::create_render_effect;
let class_list = el.class_list();
match value {
Class::Fn(cx, f) => {
create_render_effect(cx, move |old| {
let new = f();
if old.as_ref() != Some(&new) && (old.is_some() || new) {
class_expression(&class_list, &name, new)
}
new
});
}
Class::Value(value) => class_expression(&class_list, &name, value),
};
}
#[cfg(all(target_arch = "wasm32", feature = "web"))]
pub(crate) fn class_expression(
class_list: &web_sys::DomTokenList,

View File

@@ -76,38 +76,6 @@ prop_type!(f32);
prop_type!(f64);
prop_type!(bool);
#[cfg(all(target_arch = "wasm32", feature = "web"))]
use std::borrow::Cow;
#[cfg(all(target_arch = "wasm32", feature = "web"))]
pub(crate) fn property_helper(
el: &web_sys::Element,
name: Cow<'static, str>,
value: Property,
) {
use leptos_reactive::create_render_effect;
match value {
Property::Fn(cx, f) => {
let el = el.clone();
create_render_effect(cx, move |old| {
let new = f();
let prop_name = wasm_bindgen::intern(&name);
if old.as_ref() != Some(&new)
&& !(old.is_none() && new == wasm_bindgen::JsValue::UNDEFINED)
{
property_expression(&el, prop_name, new.clone())
}
new
});
}
Property::Value(value) => {
let prop_name = wasm_bindgen::intern(&name);
property_expression(el, prop_name, value)
}
};
}
#[cfg(all(target_arch = "wasm32", feature = "web"))]
pub(crate) fn property_expression(
el: &web_sys::Element,

View File

@@ -96,11 +96,6 @@ where
self.0.with(|a| a.pending.read_only())
}
/// Updates whether the action is currently pending.
pub fn set_pending(&self, pending: bool) {
self.0.with(|a| a.pending.set(pending))
}
/// The URL associated with the action (typically as part of a server function.)
/// This enables integration with the `ActionForm` component in `leptos_router`.
pub fn url(&self) -> Option<String> {

View File

@@ -1,6 +1,6 @@
[package]
name = "leptos_meta"
version = "0.1.3"
version = "0.1.1"
edition = "2021"
authors = ["Greg Johnston"]
license = "MIT"

View File

@@ -1,6 +1,6 @@
[package]
name = "leptos_router"
version = "0.1.3"
version = "0.1.1"
edition = "2021"
authors = ["Greg Johnston"]
license = "MIT"

View File

@@ -155,10 +155,7 @@ where
let on_form_data = Rc::new(move |form_data: &web_sys::FormData| {
let data = action_input_from_form_data(form_data);
match data {
Ok(data) => {
input.set(Some(data));
action.set_pending(true);
}
Ok(data) => input.set(Some(data)),
Err(e) => log::error!("{e}"),
}
});
@@ -170,6 +167,11 @@ where
JsFuture::from(resp.text().expect("couldn't get .text() from Response")).await;
match body {
Ok(json) => {
log::debug!(
"body is {:?}\nO is {:?}",
json.as_string().unwrap(),
std::any::type_name::<O>()
);
match O::from_json(
&json.as_string().expect("couldn't get String from JsString"),
) {
@@ -180,9 +182,7 @@ where
}
}
Err(e) => log::error!("{e:?}"),
};
input.set(None);
action.set_pending(false);
}
});
});