chore: clear up... a few warnings

This commit is contained in:
Greg Johnston 2024-05-31 21:31:33 -04:00
parent 7c526cfa52
commit 8ed8b5605b
74 changed files with 390 additions and 856 deletions

View file

@ -28,10 +28,6 @@ sqlx = { version = "0.7", features = [
thiserror = "1.0"
wasm-bindgen = "0.2"
tracing = "0.1"
tracing-subscriber = "0.3"
tracing-subscriber-wasm = "0.1"
[features]
hydrate = ["leptos/hydrate"]
ssr = [

View file

@ -1,7 +1,4 @@
use crate::errors::TodoAppError;
use leptos::prelude::*;
#[cfg(feature = "ssr")]
use leptos_axum::ResponseOptions;
// A basic function to display errors served by the error boundaries. Feel free to do more complicated things
// here than just displaying them

View file

@ -23,7 +23,6 @@ pub async fn file_and_error_handler(
let mut errors = Errors::default();
errors.insert_with_default_key(TodoAppError::NotFound);
let handler = leptos_axum::render_app_to_stream(
options.to_owned(),
move || view! { <ErrorTemplate outside_errors=errors.clone()/> },
);
handler(req).await.into_response()

View file

@ -8,21 +8,6 @@ pub mod todo;
#[wasm_bindgen::prelude::wasm_bindgen]
pub fn hydrate() {
use crate::todo::TodoApp;
/* use tracing_subscriber::fmt;
use tracing_subscriber_wasm::MakeConsoleWriter;
fmt()
.with_writer(
// To avoide trace events in the browser from showing their
// JS backtrace, which is very annoying, in my opinion
MakeConsoleWriter::default()
.map_trace_level_to(tracing::Level::DEBUG),
)
// For some reason, if we don't do this in the browser, we get
// a runtime error.
.without_time()
.init();
_ = console_log::init_with_level(log::Level::Error);*/
console_error_panic_hook::set_once();
leptos::mount::hydrate_body(TodoApp);

View file

@ -1,7 +1,7 @@
use crate::{fallback::file_and_error_handler, todo::*};
use axum::{
body::Body,
extract::{Path, State},
extract::Path,
http::Request,
response::{IntoResponse, Response},
routing::get,
@ -14,11 +14,9 @@ use todo_app_sqlite_axum::*;
//Define a handler to test extractor with state
async fn custom_handler(
Path(id): Path<String>,
State(options): State<LeptosOptions>,
req: Request<Body>,
) -> Response {
let handler = leptos_axum::render_app_to_stream_with_context(
options,
move || {
provide_context(id.clone());
},

View file

@ -142,7 +142,7 @@ impl SharedContext for HydrateSharedContext {
}
#[inline(always)]
fn seal_errors(&self, boundary_id: &SerializedDataId) {}
fn seal_errors(&self, _boundary_id: &SerializedDataId) {}
fn take_errors(&self) -> Vec<(SerializedDataId, ErrorId, Error)> {
self.errors.clone()

View file

@ -6,7 +6,7 @@ use futures::{
};
use or_poisoned::OrPoisoned;
use std::{
collections::{HashMap, HashSet},
collections::HashSet,
fmt::{Debug, Write},
mem,
sync::{
@ -89,7 +89,7 @@ impl SharedContext for SsrSharedContext {
initial_chunk.push_str("__SERIALIZED_ERRORS=[");
for error in mem::take(&mut *self.errors.write().or_poisoned()) {
write!(
_ = write!(
initial_chunk,
"[{}, {}, {:?}],",
error.0 .0, error.1, error.2
@ -100,7 +100,7 @@ impl SharedContext for SsrSharedContext {
// pending async resources
initial_chunk.push_str("__PENDING_RESOURCES=[");
for (id, _) in &async_data {
write!(&mut initial_chunk, "{},", id.0).unwrap();
_ = write!(&mut initial_chunk, "{},", id.0);
}
initial_chunk.push_str("];");
@ -121,7 +121,7 @@ impl SharedContext for SsrSharedContext {
let sealed = sealed.read().or_poisoned();
for error in mem::take(&mut *errors.write().or_poisoned()) {
if !sealed.contains(&error.0) {
write!(
_ = write!(
val,
"__SERIALIZED_ERRORS.push([{}, {}, {:?}]);",
error.0 .0,

View file

@ -19,9 +19,9 @@ http-body-util = "0.1"
leptos = { workspace = true, features = ["nonce", "hydration"] }
server_fn = { workspace = true, features = ["axum-no-default"] }
leptos_macro = { workspace = true, features = ["axum"] }
leptos_meta = { workspace = true }
leptos_meta = { workspace = true, features = ["ssr"] }
reactive_graph = { workspace = true, features = ["sandboxed-arenas"] }
leptos_router = { workspace = true }
leptos_router = { workspace = true, features = ["ssr"] }
#leptos_integration_utils = { workspace = true }
parking_lot = "0.12"
serde_json = "1"

View file

@ -43,42 +43,24 @@ use axum::{
response::{Html, IntoResponse},
routing::{delete, get, patch, post, put},
};
use futures::{
channel::mpsc::{Receiver, Sender},
stream::once,
Future, FutureExt, SinkExt, Stream, StreamExt,
};
use futures::{stream::once, Future, Stream, StreamExt};
use hydration_context::SsrSharedContext;
use leptos::{
config::LeptosOptions,
context::{provide_context, use_context},
reactive_graph::{computed::ScopedFuture, owner::Owner},
tachys::ssr::StreamBuilder,
IntoView,
};
use leptos_meta::{MetaContext, ServerMetaContext};
use leptos_meta::ServerMetaContext;
use leptos_router::{
location::RequestUrl, PathSegment, RouteList, RouteListing, SsrMode,
StaticDataMap, StaticMode,
};
use once_cell::sync::OnceCell;
use parking_lot::RwLock;
use reactive_graph::owner::Sandboxed;
use server_fn::{
error::{NoCustomError, ServerFnErrorSerde},
redirect::REDIRECT_HEADER, ServerFnError,
,
};
use std::{
collections::HashSet,
fmt::{Debug, Write},
io,
pin::Pin,
sync::Arc,
thread::available_parallelism,
};
use tracing::Instrument;
use server_fn::{redirect::REDIRECT_HEADER, ServerFnError};
use std::{fmt::Debug, io, pin::Pin, sync::Arc};
// use tracing::Instrument; // TODO check tracing span -- was this used in 0.6 for a missing link?
/// This struct lets you define headers and override the status of the Response from an Element or a Server Function
/// Typically contained inside of a ResponseOptions. Setting this is useful for cookies and custom responses.
@ -251,27 +233,6 @@ fn init_executor() {
}
}
/// Leptos pool causes wasm to panic and leptos_reactive::spawn::spawn_local causes native
/// to panic so we define a macro to conditionally compile the correct code.
macro_rules! spawn_task {
($block:expr) => {
#[cfg(feature = "wasm")]
spawn_local($block);
#[cfg(all(not(feature = "wasm"), feature = "default"))]
spawn($block);
#[cfg(all(not(feature = "wasm"), not(feature = "default")))]
{
eprintln!(
"It appears you have set 'default-features = false' on \
'leptos_axum', but are not using the 'wasm' feature. Either \
remove 'default-features = false' or, if you are running in \
a JS-hosted WASM server environment, add the 'wasm' feature."
);
spawn_local($block);
}
};
}
/// An Axum handlers to listens for a request with Leptos server function arguments in the body,
/// run the server function if found, and return the resulting [`Response`].
///
@ -310,9 +271,7 @@ async fn handle_server_fns_inner(
let path = req.uri().path().to_string();
let (req, parts) = generate_request_and_parts(req);
let res = if let Some(mut service) =
server_fn::axum::get_server_fn_service(&path)
{
if let Some(mut service) = server_fn::axum::get_server_fn_service(&path) {
let owner = Owner::new();
owner
.with(|| {
@ -379,25 +338,14 @@ async fn handle_server_fns_inner(
function type, somewhere in your `main` function.",
)))
}
.expect("could not build Response");
res
/*rx.await.unwrap_or_else(|e| {
(
StatusCode::INTERNAL_SERVER_ERROR,
ServerFnErrorSerde::ser(
&ServerFnError::<NoCustomError>::ServerError(e.to_string()),
)
.unwrap_or_default(),
)
.into_response()
})*/
.expect("could not build Response")
}
pub type PinnedHtmlStream =
Pin<Box<dyn Stream<Item = io::Result<Bytes>> + Send>>;
type PinnedStream<T> = Pin<Box<dyn Stream<Item = T> + Send>>;
type PinnedFuture<T> = Pin<Box<dyn Future<Output = T> + Send>>;
type BoxedFnOnce<T> = Box<dyn FnOnce() -> T + Send>;
/// Returns an Axum [Handler](axum::handler::Handler) that listens for a `GET` request and tries
/// to route it using [leptos_router], serving an HTML stream of your application.
@ -447,11 +395,10 @@ type PinnedStream<T> = Pin<Box<dyn Stream<Item = T> + Send>>;
/// This function always provides context values including the following types:
/// - [`Parts`]
/// - [`ResponseOptions`]
/// - [`MetaContext`](leptos_meta::MetaContext)
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
#[tracing::instrument(level = "trace", fields(error), skip_all)]
pub fn render_app_to_stream<IV>(
options: LeptosOptions,
app_fn: impl Fn() -> IV + Clone + Send + 'static,
) -> impl Fn(
Request<Body>,
@ -462,7 +409,7 @@ pub fn render_app_to_stream<IV>(
where
IV: IntoView + 'static,
{
render_app_to_stream_with_context(options, || {}, app_fn)
render_app_to_stream_with_context(|| {}, app_fn)
}
/// Returns an Axum [Handler](axum::handler::Handler) that listens for a `GET` request and tries
@ -472,7 +419,6 @@ where
/// This is useful if you are using `.leptos_routes_with_handler()`
#[tracing::instrument(level = "trace", fields(error), skip_all)]
pub fn render_route<IV>(
options: LeptosOptions,
paths: Vec<AxumRouteListing>,
app_fn: impl Fn() -> IV + Clone + Send + 'static,
) -> impl Fn(
@ -484,7 +430,7 @@ pub fn render_route<IV>(
where
IV: IntoView + 'static,
{
render_route_with_context(options, paths, || {}, app_fn)
render_route_with_context(paths, || {}, app_fn)
}
/// Returns an Axum [Handler](axum::handler::Handler) that listens for a `GET` request and tries
@ -538,11 +484,10 @@ where
/// This function always provides context values including the following types:
/// - [`Parts`]
/// - [`ResponseOptions`]
/// - [`MetaContext`](leptos_meta::MetaContext)
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
#[tracing::instrument(level = "trace", fields(error), skip_all)]
pub fn render_app_to_stream_in_order<IV>(
options: LeptosOptions,
app_fn: impl Fn() -> IV + Clone + Send + 'static,
) -> impl Fn(
Request<Body>,
@ -553,7 +498,7 @@ pub fn render_app_to_stream_in_order<IV>(
where
IV: IntoView + 'static,
{
render_app_to_stream_in_order_with_context(options, || {}, app_fn)
render_app_to_stream_in_order_with_context(|| {}, app_fn)
}
/// Returns an Axum [Handler](axum::handler::Handler) that listens for a `GET` request and tries
@ -579,11 +524,10 @@ where
/// This function always provides context values including the following types:
/// - [`Parts`]
/// - [`ResponseOptions`]
/// - [`MetaContext`](leptos_meta::MetaContext)
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
#[tracing::instrument(level = "trace", fields(error), skip_all)]
pub fn render_app_to_stream_with_context<IV>(
options: LeptosOptions,
additional_context: impl Fn() + 'static + Clone + Send,
app_fn: impl Fn() -> IV + Clone + Send + 'static,
) -> impl Fn(
@ -596,7 +540,6 @@ where
IV: IntoView + 'static,
{
render_app_to_stream_with_context_and_replace_blocks(
options,
additional_context,
app_fn,
false,
@ -610,7 +553,6 @@ where
/// This is useful if you are using `.leptos_routes_with_handler()`.
#[tracing::instrument(level = "trace", fields(error), skip_all)]
pub fn render_route_with_context<IV>(
options: LeptosOptions,
paths: Vec<AxumRouteListing>,
additional_context: impl Fn() + 'static + Clone + Send,
app_fn: impl Fn() -> IV + Clone + Send + 'static,
@ -624,23 +566,19 @@ where
IV: IntoView + 'static,
{
let ooo = render_app_to_stream_with_context(
LeptosOptions::from_ref(&options),
additional_context.clone(),
app_fn.clone(),
);
let pb = render_app_to_stream_with_context_and_replace_blocks(
LeptosOptions::from_ref(&options),
additional_context.clone(),
app_fn.clone(),
true,
);
let io = render_app_to_stream_in_order_with_context(
LeptosOptions::from_ref(&options),
additional_context.clone(),
app_fn.clone(),
);
let asyn = render_app_async_stream_with_context(
LeptosOptions::from_ref(&options),
additional_context.clone(),
app_fn.clone(),
);
@ -690,11 +628,10 @@ where
/// This function always provides context values including the following types:
/// - [`Parts`]
/// - [`ResponseOptions`]
/// - [`MetaContext`](leptos_meta::MetaContext)
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
#[tracing::instrument(level = "trace", fields(error), skip_all)]
pub fn render_app_to_stream_with_context_and_replace_blocks<IV>(
options: LeptosOptions,
additional_context: impl Fn() + 'static + Clone + Send,
app_fn: impl Fn() -> IV + Clone + Send + 'static,
replace_blocks: bool,
@ -707,7 +644,8 @@ pub fn render_app_to_stream_with_context_and_replace_blocks<IV>(
where
IV: IntoView + 'static,
{
handle_response(options, additional_context, app_fn, |app, chunks| {
_ = replace_blocks; // TODO
handle_response(additional_context, app_fn, |app, chunks| {
Box::pin(async move {
Box::pin(app.to_html_stream_out_of_order().chain(chunks()))
as PinnedStream<String>
@ -740,11 +678,10 @@ where
/// This function always provides context values including the following types:
/// - [`Parts`]
/// - [`ResponseOptions`]
/// - [`MetaContext`](leptos_meta::MetaContext)
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
#[tracing::instrument(level = "trace", fields(error), skip_all)]
pub fn render_app_to_stream_in_order_with_context<IV>(
options: LeptosOptions,
additional_context: impl Fn() + 'static + Clone + Send,
app_fn: impl Fn() -> IV + Clone + Send + 'static,
) -> impl Fn(
@ -756,7 +693,7 @@ pub fn render_app_to_stream_in_order_with_context<IV>(
where
IV: IntoView + 'static,
{
handle_response(options, additional_context, app_fn, |app, chunks| {
handle_response(additional_context, app_fn, |app, chunks| {
Box::pin(async move {
Box::pin(app.to_html_stream_in_order().chain(chunks()))
as PinnedStream<String>
@ -765,29 +702,17 @@ where
}
fn handle_response<IV>(
options: LeptosOptions,
additional_context: impl Fn() + 'static + Clone + Send,
app_fn: impl Fn() -> IV + Clone + Send + 'static,
stream_builder: fn(
IV,
Box<dyn FnOnce() -> Pin<Box<dyn Stream<Item = String> + Send>> + Send>,
) -> Pin<
Box<
dyn Future<Output = Pin<Box<dyn Stream<Item = String> + Send>>>
+ Send,
>,
>,
) -> impl Fn(
Request<Body>,
) -> Pin<Box<dyn Future<Output = Response<Body>> + Send + 'static>>
+ Clone
+ Send
+ 'static
BoxedFnOnce<PinnedStream<String>>,
) -> PinnedFuture<PinnedStream<String>>,
) -> impl Fn(Request<Body>) -> PinnedFuture<Response<Body>> + Clone + Send + 'static
where
IV: IntoView + 'static,
{
move |req: Request<Body>| {
let options = options.clone();
let app_fn = app_fn.clone();
let add_context = additional_context.clone();
let res_options = ResponseOptions::default();
@ -941,11 +866,10 @@ fn provide_contexts(
/// This function always provides context values including the following types:
/// - [`Parts`]
/// - [`ResponseOptions`]
/// - [`MetaContext`](leptos_meta::MetaContext)
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
#[tracing::instrument(level = "trace", fields(error), skip_all)]
pub fn render_app_async<IV>(
options: LeptosOptions,
app_fn: impl Fn() -> IV + Clone + Send + 'static,
) -> impl Fn(
Request<Body>,
@ -956,7 +880,7 @@ pub fn render_app_async<IV>(
where
IV: IntoView + 'static,
{
render_app_async_with_context(options, || {}, app_fn)
render_app_async_with_context(|| {}, app_fn)
}
/// Returns an Axum [Handler](axum::handler::Handler) that listens for a `GET` request and tries
@ -983,11 +907,10 @@ where
/// This function always provides context values including the following types:
/// - [`Parts`]
/// - [`ResponseOptions`]
/// - [`MetaContext`](leptos_meta::MetaContext)
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
#[tracing::instrument(level = "trace", fields(error), skip_all)]
pub fn render_app_async_stream_with_context<IV>(
options: LeptosOptions,
additional_context: impl Fn() + 'static + Clone + Send,
app_fn: impl Fn() -> IV + Clone + Send + 'static,
) -> impl Fn(
@ -999,7 +922,7 @@ pub fn render_app_async_stream_with_context<IV>(
where
IV: IntoView + 'static,
{
handle_response(options, additional_context, app_fn, |app, chunks| {
handle_response(additional_context, app_fn, |app, chunks| {
Box::pin(async move {
let app = app.to_html_stream_in_order().collect::<String>().await;
let chunks = chunks();
@ -1033,11 +956,10 @@ where
/// This function always provides context values including the following types:
/// - [`Parts`]
/// - [`ResponseOptions`]
/// - [`MetaContext`](leptos_meta::MetaContext)
/// - [`ServerMetaContext`](leptos_meta::ServerMetaContext)
/// - [`RouterIntegrationContext`](leptos_router::RouterIntegrationContext)
#[tracing::instrument(level = "trace", fields(error), skip_all)]
pub fn render_app_async_with_context<IV>(
options: LeptosOptions,
additional_context: impl Fn() + 'static + Clone + Send,
app_fn: impl Fn() -> IV + Clone + Send + 'static,
) -> impl Fn(
@ -1049,7 +971,7 @@ pub fn render_app_async_with_context<IV>(
where
IV: IntoView + 'static,
{
handle_response(options, additional_context, app_fn, |app, chunks| {
handle_response(additional_context, app_fn, |app, chunks| {
Box::pin(async move {
let app = app.to_html_stream_in_order().collect::<String>().await;
let chunks = chunks();
@ -1101,6 +1023,7 @@ where
}
/// TODO docs
#[allow(unused)]
pub async fn build_static_routes<IV>(
options: &LeptosOptions,
app_fn: impl Fn() -> IV + 'static + Send + Clone,
@ -1398,11 +1321,11 @@ where
})
}*/
#[allow(unused)] // TODO
#[cfg(feature = "default")]
fn static_route<IV, S>(
router: axum::Router<S>,
path: &str,
options: LeptosOptions,
app_fn: impl Fn() -> IV + Clone + Send + 'static,
additional_context: impl Fn() + Clone + Send + 'static,
method: leptos_router::Method,
@ -1541,20 +1464,20 @@ where
#[tracing::instrument(level = "trace", fields(error), skip_all)]
fn leptos_routes<IV>(
self,
options: &S,
state: &S,
paths: Vec<AxumRouteListing>,
app_fn: impl Fn() -> IV + Clone + Send + 'static,
) -> Self
where
IV: IntoView + 'static,
{
self.leptos_routes_with_context(options, paths, || {}, app_fn)
self.leptos_routes_with_context(state, paths, || {}, app_fn)
}
#[tracing::instrument(level = "trace", fields(error), skip_all)]
fn leptos_routes_with_context<IV>(
self,
options: &S,
state: &S,
paths: Vec<AxumRouteListing>,
additional_context: impl Fn() + 'static + Clone + Send,
app_fn: impl Fn() -> IV + Clone + Send + 'static,
@ -1566,7 +1489,7 @@ where
// S represents the router's finished state allowing us to provide
// it to the user's server functions.
let state = options.clone();
let state = state.clone();
let cx_with_state = move || {
provide_context::<S>(state.clone());
additional_context();
@ -1618,8 +1541,7 @@ where
{
static_route(
router,
&path,
LeptosOptions::from_ref(options),
path,
app_fn.clone(),
cx_with_state_and_method.clone(),
method,
@ -1636,11 +1558,10 @@ where
}
} else {
router.route(
&path,
path,
match listing.mode() {
SsrMode::OutOfOrder => {
let s = render_app_to_stream_with_context(
LeptosOptions::from_ref(options),
cx_with_state_and_method.clone(),
app_fn.clone(),
);
@ -1654,7 +1575,6 @@ where
}
SsrMode::PartiallyBlocked => {
let s = render_app_to_stream_with_context_and_replace_blocks(
LeptosOptions::from_ref(options),
cx_with_state_and_method.clone(),
app_fn.clone(),
true
@ -1669,7 +1589,6 @@ where
}
SsrMode::InOrder => {
let s = render_app_to_stream_in_order_with_context(
LeptosOptions::from_ref(options),
cx_with_state_and_method.clone(),
app_fn.clone(),
);
@ -1683,7 +1602,6 @@ where
}
SsrMode::Async => {
let s = render_app_async_with_context(
LeptosOptions::from_ref(options),
cx_with_state_and_method.clone(),
app_fn.clone(),
);

View file

@ -40,11 +40,6 @@
//!
//! Use `SyncCallback` when you want the function to be `Sync` and `Send`.
#![cfg_attr(feature = "nightly", feature(fn_traits))]
#![cfg_attr(feature = "nightly", feature(unboxed_closures))]
#![cfg_attr(feature = "nightly", feature(auto_traits))]
#![cfg_attr(feature = "nightly", feature(negative_impls))]
use reactive_graph::owner::StoredValue;
use std::{fmt, rc::Rc, sync::Arc};

View file

@ -5,14 +5,14 @@ use reactive_graph::{
computed::ArcMemo,
owner::Owner,
signal::ArcRwSignal,
traits::{Get, GetUntracked, Update, With, WithUntracked},
traits::{Get, Update, With, WithUntracked},
};
use rustc_hash::FxHashMap;
use std::{marker::PhantomData, sync::Arc};
use tachys::{
html::attribute::Attribute,
hydration::Cursor,
renderer::{CastFrom, Renderer},
renderer::Renderer,
ssr::StreamBuilder,
view::{
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,

View file

@ -1,12 +1,8 @@
use crate::into_view::IntoView;
use leptos_macro::component;
use reactive_graph::owner::Owner;
use std::{hash::Hash, marker::PhantomData};
use tachys::{
reactive_graph::OwnedView,
renderer::Renderer,
view::{keyed::keyed, RenderHtml},
};
use std::hash::Hash;
use tachys::{reactive_graph::OwnedView, view::keyed::keyed};
/// Iterates over children and displays them, keyed by the `key` function given.
///
@ -79,30 +75,6 @@ where
move || keyed(each(), key.clone(), children.clone())
}
#[component]
pub fn FlatFor<Rndr, IF, I, T, EF, N, KF, K>(
/// Items over which the component should iterate.
each: IF,
/// A key function that will be applied to each item.
key: KF,
/// A function that takes the item, and returns the view that will be displayed for each item.
children: EF,
#[prop(optional)] _rndr: PhantomData<Rndr>,
) -> impl IntoView
where
IF: Fn() -> I + 'static,
I: IntoIterator<Item = T>,
EF: Fn(T) -> N + Clone + 'static,
N: RenderHtml<Rndr> + 'static,
KF: Fn(&T) -> K + Clone + 'static,
K: Eq + Hash + 'static,
T: 'static,
Rndr: Renderer + 'static,
{
//move || keyed(each(), key.clone(), children.clone())
"bar"
}
#[cfg(test)]
mod tests {
use crate::For;

View file

@ -8,12 +8,10 @@ use server_fn::{
use tachys::{
either::Either,
html::{
attribute::any_attribute::AnyAttribute,
element::{form, Form},
event::submit,
},
reactive_graph::node_ref::NodeRef,
renderer::dom::Dom,
};
use thiserror::Error;
use wasm_bindgen::{JsCast, JsValue, UnwrapThrowExt};
@ -84,9 +82,6 @@ pub fn ActionForm<ServFn>(
/// A [`NodeRef`] in which the `<form>` element should be stored.
#[prop(optional)]
node_ref: Option<NodeRef<Form>>,
/// Arbitrary attributes to add to the `<form>`
#[prop(attrs, optional)]
attributes: Vec<AnyAttribute<Dom>>,
/// Component children; should include the HTML of the form elements.
children: Children,
) -> impl IntoView
@ -168,9 +163,6 @@ pub fn MultiActionForm<ServFn>(
/// A [`NodeRef`] in which the `<form>` element should be stored.
#[prop(optional)]
node_ref: Option<NodeRef<Form>>,
/// Arbitrary attributes to add to the `<form>`
#[prop(attrs, optional)]
attributes: Vec<AnyAttribute<Dom>>,
/// Component children; should include the HTML of the form elements.
children: Children,
) -> impl IntoView

View file

@ -4,10 +4,15 @@ use reactive_graph::owner::Owner;
use std::marker::PhantomData;
use tachys::{
dom::body,
hydration::Cursor,
renderer::{dom::Dom, Renderer},
view::{Mountable, PositionState, Render, RenderHtml},
view::{Mountable, Render},
};
#[cfg(feature = "hydrate")]
use tachys::{
hydration::Cursor,
view::{PositionState, RenderHtml},
};
#[cfg(feature = "hydrate")]
use wasm_bindgen::JsCast;
use web_sys::HtmlElement;
@ -36,7 +41,9 @@ where
use std::sync::Arc;
// use wasm-bindgen-futures to drive the reactive system
Executor::init_wasm_bindgen();
// we ignore the return value because an Err here just means the wasm-bindgen executor is
// already initialized, which is not an issue
_ = Executor::init_wasm_bindgen();
// create a new reactive owner and use it as the root node to run the app
let owner = Owner::new_root(Some(Arc::new(HydrateSharedContext::new())));
@ -74,7 +81,9 @@ where
N: IntoView,
{
// use wasm-bindgen-futures to drive the reactive system
Executor::init_wasm_bindgen();
// we ignore the return value because an Err here just means the wasm-bindgen executor is
// already initialized, which is not an issue
_ = Executor::init_wasm_bindgen();
// create a new reactive owner and use it as the root node to run the app
let owner = Owner::new();
@ -105,14 +114,16 @@ where
R: Renderer,
{
// use wasm-bindgen-futures to drive the reactive system
Executor::init_wasm_bindgen();
// we ignore the return value because an Err here just means the wasm-bindgen executor is
// already initialized, which is not an issue
_ = Executor::init_wasm_bindgen();
// create a new reactive owner and use it as the root node to run the app
let owner = Owner::new();
let mountable = owner.with(move || {
let view = f();
let mut mountable = view.build();
mountable.mount(&parent, None);
mountable.mount(parent, None);
mountable
});
@ -132,7 +143,9 @@ pub fn hydrate_islands() {
use std::sync::Arc;
// use wasm-bindgen-futures to drive the reactive system
Executor::init_wasm_bindgen();
// we ignore the return value because an Err here just means the wasm-bindgen executor is
// already initialized, which is not an issue
_ = Executor::init_wasm_bindgen();
// create a new reactive owner and use it as the root node to run the app
let owner = Owner::new_root(Some(Arc::new(HydrateSharedContext::new())));

View file

@ -1,8 +1,4 @@
use crate::{
children::{ChildrenFn, TypedChildrenFn},
mount, IntoView,
};
use cfg_if::cfg_if;
use crate::{children::TypedChildrenFn, mount, IntoView};
use leptos_dom::helpers::document;
use leptos_macro::component;
use reactive_graph::{effect::Effect, owner::Owner};

View file

@ -4,7 +4,7 @@ use crate::{
};
use leptos_macro::component;
use reactive_graph::{computed::ArcMemo, traits::Get};
use tachys::{either::Either, renderer::dom::Dom, view::RenderHtml};
use tachys::either::Either;
#[component]
pub fn Show<W, C>(

View file

@ -1,36 +1,27 @@
use crate::{
children::{TypedChildren, ViewFnOnce},
into_view::View,
IntoView,
};
use any_spawner::Executor;
use futures::{pin_mut, FutureExt};
use futures::FutureExt;
use leptos_macro::component;
use reactive_graph::{
computed::{suspense::SuspenseContext, ArcMemo, ScopedFuture},
owner::{provide_context, use_context},
signal::ArcRwSignal,
traits::{Get, Read, Track, Update, With, Writeable},
transition::AsyncTransition,
traits::{Get, Read, Track, With},
};
use slotmap::{DefaultKey, SlotMap};
use std::{
cell::RefCell,
fmt::Debug,
future::{ready, Future},
pin::Pin,
rc::Rc,
};
use std::{cell::RefCell, fmt::Debug, future::Future, pin::Pin, rc::Rc};
use tachys::{
either::Either,
html::attribute::Attribute,
hydration::Cursor,
reactive_graph::{OwnedView, RenderEffectState},
renderer::{dom::Dom, Renderer},
renderer::Renderer,
ssr::StreamBuilder,
view::{
add_attr::AddAnyAttr,
any_view::AnyView,
either::{EitherKeepAlive, EitherKeepAliveState},
iterators::OptionState,
Mountable, Position, PositionState, Render, RenderHtml,
@ -46,7 +37,6 @@ pub fn Suspense<Chil>(
) -> impl IntoView
where
Chil: IntoView + Send + 'static,
SuspenseBoundary<false, AnyView<Dom>, View<Chil>>: IntoView,
{
let fallback = fallback.run();
let children = children.into_inner()();
@ -163,7 +153,7 @@ where
}
fn to_html_async_with_buf<const OUT_OF_ORDER: bool>(
mut self,
self,
buf: &mut StreamBuilder,
position: &mut Position,
) where
@ -177,11 +167,13 @@ where
let mut tx = Some(tx);
let eff =
reactive_graph::effect::RenderEffect::new_isomorphic(move |prev| {
reactive_graph::effect::RenderEffect::new_isomorphic(move |_| {
tasks.track();
if tasks.read().is_empty() {
if let Some(tx) = tx.take() {
tx.send(());
// If the receiver has dropped, it means the ScopedFuture has already
// dropped, so it doesn't matter if we manage to send this.
_ = tx.send(());
}
}
});
@ -427,14 +419,14 @@ where
const MIN_LENGTH: usize = Fut::Output::MIN_LENGTH;
fn to_html_with_buf(self, buf: &mut String, position: &mut Position) {
fn to_html_with_buf(self, _buf: &mut String, _position: &mut Position) {
todo!()
}
fn to_html_async_with_buf<const OUT_OF_ORDER: bool>(
self,
buf: &mut StreamBuilder,
position: &mut Position,
_buf: &mut StreamBuilder,
_position: &mut Position,
) where
Self: Sized,
{

View file

@ -1,23 +1,17 @@
use crate::{
children::{TypedChildren, ViewFnOnce},
into_view::View,
suspense_component::SuspenseBoundary,
IntoView,
};
use leptos_macro::component;
use reactive_graph::{
computed::{suspense::SuspenseContext, ArcMemo},
owner::{provide_context, Owner},
owner::provide_context,
signal::ArcRwSignal,
traits::With,
};
use slotmap::{DefaultKey, SlotMap};
use std::future::Future;
use tachys::{
reactive_graph::OwnedView,
renderer::dom::Dom,
view::{any_view::AnyView, RenderHtml},
};
use tachys::reactive_graph::OwnedView;
/// TODO docs!
#[component]
@ -26,7 +20,7 @@ pub fn Transition<Chil>(
children: TypedChildren<Chil>,
) -> impl IntoView
where
SuspenseBoundary<true, AnyView<Dom>, View<Chil>>: IntoView,
Chil: IntoView + Send + 'static,
{
let fallback = fallback.run();
let children = children.into_inner()();

View file

@ -264,7 +264,7 @@ impl ToTokens for Model {
#component_id,
#component
)
// #island_serialized_props
#island_serialized_props
}
}
} else {
@ -299,66 +299,6 @@ impl ToTokens for Model {
}
};
let count = props
.iter()
.filter(
|Prop {
prop_opts: PropOpt { attrs, .. },
..
}| *attrs,
)
.count();
let dyn_attrs_props = props
.iter()
.filter(
|Prop {
prop_opts: PropOpt { attrs, .. },
..
}| *attrs,
)
.enumerate()
.map(|(idx, Prop { name, .. })| {
let ident = &name.ident;
if idx < count - 1 {
quote! {
self.#ident = v.clone().into();
}
} else {
quote! {
self.#ident = v.into();
}
}
})
.collect::<TokenStream>();
let dyn_binding_props = props
.iter()
.filter(
|Prop {
prop_opts: PropOpt { attrs, .. },
..
}| *attrs,
)
.filter_map(
|Prop {
name,
prop_opts: PropOpt { attrs, .. },
..
}| {
let ident = &name.ident;
if *attrs {
Some(quote! {
::leptos::leptos_dom::html::Binding::Attribute { name, value } => self.#ident.push((name, value)),
})
} else {
None
}
},
)
.collect::<TokenStream>();
let body = quote! {
#destructure_props
#tracing_span_expr

View file

@ -13,7 +13,6 @@ use component::DummyModel;
use proc_macro::TokenStream;
use proc_macro2::{Span, TokenTree};
use quote::{quote, ToTokens};
use rstml::node::KeyedAttribute;
use syn::{parse_macro_input, spanned::Spanned, token::Pub, Visibility};
#[derive(Copy, Clone, Debug, PartialEq, Eq)]

View file

@ -65,10 +65,8 @@ impl ToTokens for Model {
body,
} = self;
let (impl_generics, generics, where_clause) =
body.generics.split_for_impl();
let (_, generics, where_clause) = body.generics.split_for_impl();
let builder_name = quote::format_ident!("{name}Builder");
let prop_builder_fields = prop_builder_fields(vis, props);
let prop_docs = generate_prop_docs(props);
let builder_name_doc = LitStr::new(
@ -76,39 +74,6 @@ impl ToTokens for Model {
name.span(),
);
let count = props
.iter()
.filter(
|Prop {
prop_opts: PropOpt { attrs, .. },
..
}| *attrs,
)
.count();
let dyn_attrs_props = props
.iter()
.filter(
|Prop {
prop_opts: PropOpt { attrs, .. },
..
}| *attrs,
)
.enumerate()
.map(|(idx, Prop { name, .. })| {
let ident = &name;
if idx < count - 1 {
quote! {
self.#ident = v.clone().into();
}
} else {
quote! {
self.#ident = v.into();
}
}
})
.collect::<TokenStream>();
let output = quote! {
#[doc = #builder_name_doc]
#[doc = ""]
@ -120,14 +85,13 @@ impl ToTokens for Model {
#prop_builder_fields
}
/*
impl #generics From<#name #generics> for Vec<#name #generics> #where_clause {
fn from(value: #name #generics) -> Self {
vec![value]
}
}
impl #impl_generics ::leptos::Props for #name #generics #where_clause {
/*impl #impl_generics ::leptos::Props for #name #generics #where_clause {
type Builder = #builder_name #generics;
fn builder() -> Self::Builder {
#name::builder()
@ -139,8 +103,7 @@ impl ToTokens for Model {
#dyn_attrs_props
self
}
}
*/
}*/
};
tokens.append_all(output)

View file

@ -1,13 +1,8 @@
use super::{event_to_tokens, fragment_to_tokens, TagType};
use crate::view::{
attribute_absolute, attribute_to_tokens, attribute_value,
event_type_and_handler,
};
use super::{fragment_to_tokens, TagType};
use crate::view::attribute_absolute;
use proc_macro2::{Ident, TokenStream, TokenTree};
use quote::{format_ident, quote, quote_spanned};
use rstml::node::{
NodeAttribute, NodeBlock, NodeElement, NodeName, NodeNameFragment,
};
use rstml::node::{NodeAttribute, NodeBlock, NodeElement};
use std::collections::HashMap;
use syn::{spanned::Spanned, Expr, ExprRange, RangeLimits, Stmt};
@ -16,6 +11,8 @@ pub(crate) fn component_to_tokens(
global_class: Option<&TokenTree>,
) -> TokenStream {
let name = node.name();
#[allow(unused)] // TODO this is used by hot-reloading
#[cfg(debug_assertions)]
let component_name = super::ident_from_tag_name(node.name());
@ -53,30 +50,6 @@ pub(crate) fn component_to_tokens(
}
});
let spread_bindings = node.attributes().iter().filter_map(|node| {
use rstml::node::NodeBlock;
use syn::{Expr, ExprRange, RangeLimits, Stmt};
if let NodeAttribute::Block(NodeBlock::ValidBlock(block)) = node {
match block.stmts.first()? {
Stmt::Expr(
Expr::Range(ExprRange {
start: None,
limits: RangeLimits::HalfOpen(_),
end: Some(end),
..
}),
_,
) => Some(
quote! { .dyn_bindings(#[allow(unused_brace)] {#end}) },
),
_ => None,
}
} else {
None
}
});
let props = attrs
.clone()
.enumerate()
@ -208,6 +181,8 @@ pub(crate) fn component_to_tokens(
None,
);
// TODO view marker for hot-reloading
/*
cfg_if::cfg_if! {
if #[cfg(debug_assertions)] {
let marker = format!("<{component_name}/>-children");
@ -218,6 +193,7 @@ pub(crate) fn component_to_tokens(
let view_marker = quote! {};
}
}
*/
if let Some(children) = children {
let bindables =

View file

@ -13,7 +13,7 @@ use rstml::node::{
};
use std::collections::HashMap;
use syn::{
spanned::Spanned, Expr, ExprPath, ExprRange, Lit, LitStr, RangeLimits, Stmt,
spanned::Spanned, Expr, ExprRange, Lit, LitStr, RangeLimits, Stmt,
};
#[derive(Clone, Copy, PartialEq, Eq)]
@ -369,7 +369,8 @@ fn is_spread_marker(node: &NodeElement) -> bool {
fn attribute_to_tokens(
tag_type: TagType,
node: &NodeAttribute,
global_class: Option<&TokenTree>,
// TODO global_class support
_global_class: Option<&TokenTree>,
) -> TokenStream {
match node {
NodeAttribute::Block(node) => {
@ -979,20 +980,6 @@ pub(crate) fn parse_event_name(name: &str) -> (TokenStream, bool, bool, bool) {
(event_type, is_custom, is_force_undelegated, is_targeted)
}
fn expr_to_ident(expr: &syn::Expr) -> Option<&ExprPath> {
match expr {
syn::Expr::Block(block) => block.block.stmts.last().and_then(|stmt| {
if let syn::Stmt::Expr(expr, ..) = stmt {
expr_to_ident(expr)
} else {
None
}
}),
syn::Expr::Path(path) => Some(path),
_ => None,
}
}
fn convert_to_snake_case(name: String) -> String {
if !name.is_case(Snake) {
name.to_case(Snake)

View file

@ -1,11 +1,8 @@
use reactive_graph::{
actions::{Action, ArcAction},
owner::StoredValue,
signal::{ArcReadSignal, ArcRwSignal, ReadSignal, RwSignal},
traits::DefinedAt,
unwrap_signal,
};
use server_fn::{error::ServerFnUrlError, ServerFn, ServerFnError};
use server_fn::{ServerFn, ServerFnError};
use std::{ops::Deref, panic::Location};
pub struct ArcServerAction<S>

View file

@ -15,10 +15,9 @@ use reactive_graph::{
ArcAsyncDerived, ArcAsyncDerivedFuture, ArcMemo, AsyncDerived,
AsyncDerivedFuture, AsyncDerivedGuard,
},
graph::{Source, ToAnySource, ToAnySubscriber},
graph::{Source, ToAnySubscriber},
owner::Owner,
prelude::*,
signal::guards::{AsyncPlain, Mapped, ReadGuard},
};
use std::{future::IntoFuture, ops::Deref};
@ -176,7 +175,7 @@ where
.unwrap_or_default();
let initial = Self::initial_value(&id);
let is_ready = matches!(initial, Some(_));
let is_ready = initial.is_some();
let source = ArcMemo::new(move |_| source());
let fun = {
@ -186,7 +185,7 @@ where
let data = ArcAsyncDerived::new_with_initial(initial, fun);
if is_ready {
_ = source.with(|_| ());
source.with(|_| ());
source.add_subscriber(data.to_any_subscriber());
}
@ -216,6 +215,7 @@ where
}
#[inline(always)]
#[allow(unused)]
fn initial_value(id: &SerializedDataId) -> Option<T> {
#[cfg(feature = "hydration")]
{
@ -225,6 +225,7 @@ where
if let Some(value) = value {
match T::de(&value) {
Ok(value) => return Some(value),
#[allow(unused)]
Err(e) => {
#[cfg(feature = "tracing")]
tracing::error!(

View file

@ -1,10 +1,7 @@
use crate::ServerMetaContext;
use indexmap::IndexMap;
use leptos::{
component,
error::Result,
oco::Oco,
reactive_graph::{effect::RenderEffect, owner::use_context},
reactive_graph::owner::use_context,
tachys::{
dom::document,
html::{
@ -17,7 +14,6 @@ use leptos::{
class,
},
hydration::Cursor,
reactive_graph::RenderEffectState,
renderer::{dom::Dom, Renderer},
view::{
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
@ -28,14 +24,7 @@ use leptos::{
IntoView,
};
use or_poisoned::OrPoisoned;
use std::{
cell::RefCell,
collections::HashMap,
future::{ready, Ready},
mem,
rc::Rc,
sync::{Arc, RwLock},
};
use std::mem;
use web_sys::HtmlElement;
/// A component to set metadata on the documents `<body>` element from
@ -92,6 +81,7 @@ struct BodyView {
attributes: Vec<AnyAttribute<Dom>>,
}
#[allow(dead_code)] // TODO these should be used to rebuild the attributes, I guess
struct BodyViewState {
el: HtmlElement,
attributes: Vec<AnyAttributeState<Dom>>,
@ -112,8 +102,8 @@ impl Render<Dom> for BodyView {
BodyViewState { el, attributes }
}
fn rebuild(self, state: &mut Self::State) {
// TODO rebuilding dynamic things like this
fn rebuild(self, _state: &mut Self::State) {
todo!()
}
}
@ -121,8 +111,8 @@ impl AddAnyAttr<Dom> for BodyView {
type Output<SomeNewAttr: Attribute<Dom>> = BodyView;
fn add_any_attr<NewAttr: Attribute<Dom>>(
mut self,
attr: NewAttr,
self,
_attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<Dom>,
@ -142,12 +132,12 @@ impl RenderHtml<Dom> for BodyView {
self
}
fn to_html_with_buf(self, buf: &mut String, position: &mut Position) {}
fn to_html_with_buf(self, _buf: &mut String, _position: &mut Position) {}
fn hydrate<const FROM_SERVER: bool>(
self,
cursor: &Cursor<Dom>,
position: &PositionState,
_cursor: &Cursor<Dom>,
_position: &PositionState,
) -> Self::State {
let el = document().body().expect("there to be a <body> element");
@ -166,15 +156,15 @@ impl Mountable<Dom> for BodyViewState {
fn mount(
&mut self,
parent: &<Dom as Renderer>::Element,
marker: Option<&<Dom as Renderer>::Node>,
_parent: &<Dom as Renderer>::Element,
_marker: Option<&<Dom as Renderer>::Node>,
) {
}
fn insert_before_this(
&self,
parent: &<Dom as Renderer>::Element,
child: &mut dyn Mountable<Dom>,
_parent: &<Dom as Renderer>::Element,
_child: &mut dyn Mountable<Dom>,
) -> bool {
true
}

View file

@ -1,10 +1,7 @@
use crate::ServerMetaContext;
use indexmap::IndexMap;
use leptos::{
component,
error::Result,
oco::Oco,
reactive_graph::{effect::RenderEffect, owner::use_context},
reactive_graph::owner::use_context,
tachys::{
dom::document,
html::{
@ -18,7 +15,6 @@ use leptos::{
class,
},
hydration::Cursor,
reactive_graph::RenderEffectState,
renderer::{dom::Dom, Renderer},
view::{
add_attr::AddAnyAttr, Mountable, Position, PositionState, Render,
@ -29,15 +25,8 @@ use leptos::{
IntoView,
};
use or_poisoned::OrPoisoned;
use std::{
cell::RefCell,
collections::HashMap,
future::{ready, Ready},
mem,
rc::Rc,
sync::{Arc, RwLock},
};
use web_sys::{Element, HtmlElement};
use std::mem;
use web_sys::Element;
/// A component to set metadata on the documents `<html>` element from
/// within the application.
@ -103,6 +92,7 @@ struct HtmlView {
attributes: Vec<AnyAttribute<Dom>>,
}
#[allow(dead_code)] // TODO these should be used to rebuild the attributes, I guess
struct HtmlViewState {
el: Element,
attributes: Vec<AnyAttributeState<Dom>>,
@ -125,8 +115,8 @@ impl Render<Dom> for HtmlView {
HtmlViewState { el, attributes }
}
fn rebuild(self, state: &mut Self::State) {
// TODO rebuilding dynamic things like this
fn rebuild(self, _state: &mut Self::State) {
todo!()
}
}
@ -134,8 +124,8 @@ impl AddAnyAttr<Dom> for HtmlView {
type Output<SomeNewAttr: Attribute<Dom>> = HtmlView;
fn add_any_attr<NewAttr: Attribute<Dom>>(
mut self,
attr: NewAttr,
self,
_attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<Dom>,

View file

@ -73,8 +73,6 @@ use or_poisoned::OrPoisoned;
use send_wrapper::SendWrapper;
use std::{
fmt::Debug,
future::{ready, Ready},
pin::Pin,
sync::{Arc, RwLock},
};
use wasm_bindgen::JsCast;
@ -321,7 +319,7 @@ fn document_head() -> HtmlHeadElement {
document.head().unwrap_or_else(|| {
let el = document.create_element("head").unwrap();
let document = document.document_element().unwrap();
document.append_child(&el);
_ = document.append_child(&el);
el.unchecked_into()
})
}
@ -357,7 +355,7 @@ where
>;
fn add_any_attr<NewAttr: Attribute<Dom>>(
mut self,
self,
attr: NewAttr,
) -> Self::Output<NewAttr>
where
@ -435,7 +433,7 @@ where
fn insert_before_this(
&self,
parent: &<Dom as Renderer>::Element,
_parent: &<Dom as Renderer>::Element,
child: &mut dyn Mountable<Dom>,
) -> bool {
self.state.insert_before_this(&document_head(), child)
@ -447,18 +445,11 @@ where
/// being used during server rendering.
#[component]
pub fn MetaTags() -> impl IntoView {
MetaTagsView {
context: use_context::<ServerMetaContext>().expect(
"before using the <MetaTags/> component, you should make sure to \
provide ServerMetaContext via context",
),
}
MetaTagsView
}
#[derive(Debug)]
struct MetaTagsView {
context: ServerMetaContext,
}
struct MetaTagsView;
// this implementation doesn't do anything during client-side rendering, it's just for server-side
// rendering HTML for all the tags that will be injected into the `<head>`
@ -469,7 +460,7 @@ impl Render<Dom> for MetaTagsView {
fn build(self) -> Self::State {}
fn rebuild(self, state: &mut Self::State) {}
fn rebuild(self, _state: &mut Self::State) {}
}
impl AddAnyAttr<Dom> for MetaTagsView {
@ -497,14 +488,14 @@ impl RenderHtml<Dom> for MetaTagsView {
self
}
fn to_html_with_buf(self, buf: &mut String, position: &mut Position) {
fn to_html_with_buf(self, buf: &mut String, _position: &mut Position) {
buf.push_str("<!--HEAD-->");
}
fn hydrate<const FROM_SERVER: bool>(
self,
cursor: &Cursor<Dom>,
position: &PositionState,
_cursor: &Cursor<Dom>,
_position: &PositionState,
) -> Self::State {
}
}

View file

@ -1,13 +1,7 @@
use crate::register;
use leptos::{
component,
oco::Oco,
prelude::GlobalAttributes,
tachys::{
html::{attribute::any_attribute::AnyAttribute, element::link},
renderer::dom::Dom,
},
IntoView,
component, oco::Oco, prelude::GlobalAttributes,
tachys::html::element::link, IntoView,
};
/// Injects an [`HTMLLinkElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLinkElement) into the document
@ -83,9 +77,6 @@ pub fn Link(
/// The [`blocking`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link#attr-blocking) attribute.
#[prop(optional, into)]
blocking: Option<Oco<'static, str>>,
/// Custom attributes.
#[prop(attrs, optional)]
attrs: Vec<AnyAttribute<Dom>>,
) -> impl IntoView {
// TODO additional attributes
register(

View file

@ -2,10 +2,7 @@ use crate::register;
use leptos::{
component,
prelude::{CustomAttribute, GlobalAttributes},
tachys::{
html::{attribute::any_attribute::AnyAttribute, element::meta},
renderer::dom::Dom,
},
tachys::html::element::meta,
text_prop::TextProp,
IntoView,
};
@ -50,11 +47,7 @@ pub fn Meta(
/// The [`content`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta#attr-content) attribute.
#[prop(optional, into)]
content: Option<TextProp>,
/// Custom attributes.
#[prop(attrs, optional)]
attrs: Vec<AnyAttribute<Dom>>,
) -> impl IntoView {
// TODO other attrs
register(
meta()
.charset(charset.map(|v| move || v.get()))

View file

@ -1,14 +1,6 @@
use crate::register;
use leptos::{
component,
oco::Oco,
prelude::*,
tachys::{
html::{attribute::any_attribute::AnyAttribute, element::script},
renderer::dom::Dom,
view::any_view::AnyView,
},
IntoView,
component, oco::Oco, prelude::*, tachys::html::element::script, IntoView,
};
/// Injects an [`HTMLScriptElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLScriptElement) into the document
@ -72,11 +64,7 @@ pub fn Script(
/// The content of the `<script>` tag.
#[prop(optional)]
children: Option<Children>,
/// Custom attributes.
#[prop(attrs, optional)]
attrs: Vec<AnyAttribute<Dom>>,
) -> impl IntoView {
// TODO other attrs
register(
script()
.id(id)

View file

@ -1,14 +1,6 @@
use crate::register;
use leptos::{
component,
oco::Oco,
prelude::*,
tachys::{
html::{attribute::any_attribute::AnyAttribute, element::style},
renderer::dom::Dom,
view::any_view::AnyView,
},
IntoView,
component, oco::Oco, prelude::*, tachys::html::element::style, IntoView,
};
/// Injects an [`HTMLStyleElement`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLStyleElement) into the document
@ -50,12 +42,8 @@ pub fn Style(
blocking: Option<Oco<'static, str>>,
/// The content of the `<style>` tag.
#[prop(optional)]
children: Option<Box<dyn FnOnce() -> AnyView<Dom>>>,
/// Custom attributes.
#[prop(attrs, optional)]
attrs: Vec<AnyAttribute<Dom>>,
children: Option<Children>,
) -> impl IntoView {
// TODO other attributes
register(
style()
.id(id)

View file

@ -1,10 +1,6 @@
use crate::register;
use leptos::{
component,
tachys::{
html::{attribute::any_attribute::AnyAttribute, element::link},
renderer::dom::Dom,
},
attr::global::GlobalAttributes, component, tachys::html::element::link,
IntoView,
};
@ -34,10 +30,7 @@ pub fn Stylesheet(
/// An ID for the stylesheet.
#[prop(optional, into)]
id: Option<String>,
/// Custom attributes.
#[prop(attrs, optional)]
attrs: Vec<AnyAttribute<Dom>>,
) -> impl IntoView {
// TODO additional attributes
register(link().rel("stylesheet").href(href))
register(link().id(id).rel("stylesheet").href(href))
}

View file

@ -2,7 +2,6 @@ use crate::{use_head, MetaContext, ServerMetaContext};
use leptos::{
attr::Attribute,
component,
error::Result,
oco::Oco,
reactive_graph::{
effect::RenderEffect,
@ -22,15 +21,9 @@ use leptos::{
};
use or_poisoned::OrPoisoned;
use send_wrapper::SendWrapper;
use std::{
cell::RefCell,
future::{ready, Ready},
ops::Deref,
rc::Rc,
sync::{Arc, RwLock},
};
use std::sync::{Arc, RwLock};
use wasm_bindgen::{JsCast, UnwrapThrowExt};
use web_sys::{Element, HtmlTitleElement};
use web_sys::HtmlTitleElement;
/// Contains the current state of the document's `<title>`.
#[derive(Clone, Default)]
@ -188,6 +181,7 @@ impl TitleView {
}
}
#[allow(dead_code)] // TODO these should be used to rebuild the attributes, I guess
struct TitleViewState {
el: HtmlTitleElement,
formatter: Option<Formatter>,
@ -231,7 +225,7 @@ impl AddAnyAttr<Dom> for TitleView {
fn add_any_attr<NewAttr: Attribute<Dom>>(
self,
attr: NewAttr,
_attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<Dom>,
@ -251,7 +245,7 @@ impl RenderHtml<Dom> for TitleView {
self
}
fn to_html_with_buf(self, buf: &mut String, position: &mut Position) {
fn to_html_with_buf(self, _buf: &mut String, _position: &mut Position) {
// meta tags are rendered into the buffer stored into the context
// the value has already been taken out, when we're on the server
}
@ -290,8 +284,8 @@ impl Mountable<Dom> for TitleViewState {
fn mount(
&mut self,
parent: &<Dom as Renderer>::Element,
marker: Option<&<Dom as Renderer>::Node>,
_parent: &<Dom as Renderer>::Element,
_marker: Option<&<Dom as Renderer>::Node>,
) {
// <title> doesn't need to be mounted
// TitleView::el() guarantees that there is a <title> in the <head>

View file

@ -12,7 +12,7 @@ use crate::{
SubscriberSet, ToAnySource, ToAnySubscriber,
},
owner::{use_context, Owner},
signal::guards::{AsyncPlain, Plain, ReadGuard},
signal::guards::{AsyncPlain, ReadGuard},
traits::{DefinedAt, ReadUntracked},
transition::AsyncTransition,
};
@ -131,9 +131,9 @@ impl<T> DefinedAt for ArcAsyncDerived<T> {
// as far as I can tell, require repeating most of the function body.
macro_rules! spawn_derived {
($spawner:expr, $initial:ident, $fun:ident) => {{
let (mut notifier, mut rx) = channel();
let (notifier, mut rx) = channel();
let is_ready = matches!($initial, Some(_));
let is_ready = $initial.is_some();
let owner = Owner::new();
let inner = Arc::new(RwLock::new(ArcAsyncDerivedInner {
@ -234,7 +234,12 @@ macro_rules! spawn_derived {
loading.store(false, Ordering::Relaxed);
*value.write().await = Some(new_value);
inner.write().or_poisoned().dirty = true;
ready_tx.send(());
// if it's an Err, that just means the Receiver was dropped
// we don't particularly care about that: the point is to notify if
// it still exists, but we don't need to know if Suspense is no
// longer listening
_ = ready_tx.send(());
// notify reactive subscribers that we're not loading any more
for sub in (&inner.read().or_poisoned().subscribers).into_iter() {

View file

@ -1,21 +1,16 @@
use super::{
ArcAsyncDerived, ArcAsyncDerivedFuture, ArcAsyncDerivedReadyFuture,
};
use super::{ArcAsyncDerived, ArcAsyncDerivedReadyFuture};
use crate::{
graph::{
AnySource, AnySubscriber, ReactiveNode, Source, Subscriber,
ToAnySource, ToAnySubscriber,
},
owner::StoredValue,
signal::guards::{AsyncPlain, Plain, ReadGuard},
signal::guards::{AsyncPlain, ReadGuard},
traits::{DefinedAt, Dispose, ReadUntracked},
unwrap_signal,
};
use core::fmt::Debug;
use std::{
future::{Future, IntoFuture},
panic::Location,
};
use std::{future::Future, panic::Location};
pub struct AsyncDerived<T> {
#[cfg(debug_assertions)]

View file

@ -1,8 +1,7 @@
use super::{suspense::SuspenseContext, ArcAsyncDerived, AsyncDerived};
use super::{ArcAsyncDerived, AsyncDerived};
use crate::{
graph::{AnySource, ToAnySource},
owner::use_context,
signal::guards::{AsyncPlain, Mapped, Plain, ReadGuard},
signal::guards::{AsyncPlain, Mapped, ReadGuard},
traits::{DefinedAt, Track},
unwrap_signal,
};

View file

@ -35,7 +35,7 @@ impl SpecialNonReactiveZone {
SpecialNonReactiveZoneGuard
}
#[cfg(debug_assertions)]
#[cfg(all(debug_assertions, feature = "effects"))]
#[inline(always)]
pub(crate) fn is_inside() -> bool {
if cfg!(debug_assertions) {

View file

@ -56,30 +56,32 @@ impl Effect {
let value = Arc::new(RwLock::new(None::<T>));
let mut first_run = true;
#[cfg(feature = "effects")]
Executor::spawn_local({
let value = Arc::clone(&value);
let subscriber = inner.to_any_subscriber();
if cfg!(feature = "effects") {
Executor::spawn_local({
let value = Arc::clone(&value);
let subscriber = inner.to_any_subscriber();
async move {
while rx.next().await.is_some() {
if first_run
|| subscriber
.with_observer(|| subscriber.update_if_necessary())
{
first_run = false;
subscriber.clear_sources(&subscriber);
async move {
while rx.next().await.is_some() {
if first_run
|| subscriber.with_observer(|| {
subscriber.update_if_necessary()
})
{
first_run = false;
subscriber.clear_sources(&subscriber);
let old_value =
mem::take(&mut *value.write().or_poisoned());
let new_value = owner.with_cleanup(|| {
subscriber.with_observer(|| fun(old_value))
});
*value.write().or_poisoned() = Some(new_value);
let old_value =
mem::take(&mut *value.write().or_poisoned());
let new_value = owner.with_cleanup(|| {
subscriber.with_observer(|| fun(old_value))
});
*value.write().or_poisoned() = Some(new_value);
}
}
}
}
});
});
}
Self {
inner: StoredValue::new(Some(inner)),
@ -96,30 +98,33 @@ impl Effect {
let mut first_run = true;
let value = Arc::new(RwLock::new(None::<T>));
#[cfg(feature = "effects")]
Executor::spawn({
let value = Arc::clone(&value);
let subscriber = inner.to_any_subscriber();
if cfg!(feature = "effects") {
Executor::spawn({
let value = Arc::clone(&value);
let subscriber = inner.to_any_subscriber();
async move {
while rx.next().await.is_some() {
if first_run
|| subscriber
.with_observer(|| subscriber.update_if_necessary())
{
first_run = false;
subscriber.clear_sources(&subscriber);
async move {
while rx.next().await.is_some() {
if first_run
|| subscriber.with_observer(|| {
subscriber.update_if_necessary()
})
{
first_run = false;
subscriber.clear_sources(&subscriber);
let old_value =
mem::take(&mut *value.write().or_poisoned());
let new_value = owner.with_cleanup(|| {
subscriber.with_observer(|| fun(old_value))
});
*value.write().or_poisoned() = Some(new_value);
let old_value =
mem::take(&mut *value.write().or_poisoned());
let new_value = owner.with_cleanup(|| {
subscriber.with_observer(|| fun(old_value))
});
*value.write().or_poisoned() = Some(new_value);
}
}
}
}
});
});
}
Self {
inner: StoredValue::new(Some(inner)),
}

View file

@ -101,6 +101,8 @@ pub mod prelude {
pub use crate::traits::*;
}
// TODO remove this, it's just useful while developing
#[allow(unused)]
fn log_warning(text: Arguments) {
#[cfg(feature = "tracing")]
{

View file

@ -20,13 +20,18 @@ thread_local! {
}
impl Arena {
#[cfg(feature = "hydration")]
#[inline(always)]
pub fn enter_new() {
#[cfg(feature = "sandboxed-arenas")]
MAP.with_borrow_mut(|arena| {
*arena =
Some(Arc::new(RwLock::new(SlotMap::with_capacity_and_key(32))))
})
{
use std::sync::Arc;
MAP.with_borrow_mut(|arena| {
*arena = Some(Arc::new(RwLock::new(
SlotMap::with_capacity_and_key(32),
)))
})
}
}
#[track_caller]

View file

@ -51,7 +51,10 @@ impl AsyncTransition {
.as_ref()
.map(|n| &n.tx)
{
tx.send(rx);
// if it's an Err, that just means the Receiver was dropped
// i.e., the transition is no longer listening, in which case it doesn't matter if we
// successfully register with it or not
_ = tx.send(rx);
}
}
}

View file

@ -1,29 +1,27 @@
pub use super::link::*;
#[cfg(feature = "ssr")]
use crate::location::RequestUrl;
use crate::{
hooks::use_navigate,
location::{
BrowserUrl, Location, LocationChange, LocationProvider, RequestUrl,
State, Url,
BrowserUrl, Location, LocationChange, LocationProvider, State, Url,
},
navigate::{NavigateOptions, UseNavigate},
params::ParamsMap,
navigate::NavigateOptions,
resolve_path::resolve_path,
ChooseView, FlatRoutesView, MatchNestedRoutes, NestedRoute,
NestedRoutesView, Routes, SsrMode,
};
use leptos::prelude::*;
use reactive_graph::{
computed::ArcMemo,
owner::{provide_context, use_context, Owner},
signal::{ArcRwSignal, RwSignal},
traits::{GetUntracked, Read, ReadUntracked, Set},
untrack,
signal::ArcRwSignal,
traits::{GetUntracked, ReadUntracked, Set},
wrappers::write::SignalSetter,
};
use std::{
borrow::Cow, fmt::Debug, marker::PhantomData, sync::Arc, time::Duration,
};
use tachys::renderer::{dom::Dom, Renderer};
use tachys::renderer::dom::Dom;
#[derive(Debug)]
pub struct RouteChildren<Children>(Children);
@ -62,10 +60,6 @@ pub fn Router<Chil>(
/// any elements, and should include a [`Routes`](crate::Routes) component somewhere
/// to define and display [`Route`](crate::Route)s.
children: TypedChildren<Chil>,
/// A unique identifier for this router, allowing you to mount multiple Leptos apps with
/// different routes from the same server.
#[prop(optional)]
id: usize,
) -> impl IntoView
where
Chil: IntoView,
@ -235,7 +229,7 @@ where
base: base.clone(),
fallback: fallback(),
rndr: PhantomData,
set_is_routing: set_is_routing.clone(),
set_is_routing,
}
}
}
@ -258,6 +252,9 @@ where
..
} = use_context()
.expect("<FlatRoutes> should be used inside a <Router> component");
// TODO base
#[allow(unused)]
let base = base.map(|base| {
let mut base = Oco::from(base);
base.upgrade_inplace();

View file

@ -1,34 +1,26 @@
use crate::{
location::{Location, LocationProvider, RequestUrl, Url},
location::{LocationProvider, Url},
matching::Routes,
params::ParamsMap,
resolve_path::resolve_path,
ChooseView, MatchInterface, MatchNestedRoutes, MatchParams, Method,
PathSegment, RouteList, RouteListing, RouteMatchId,
};
use any_spawner::Executor;
use either_of::{Either, EitherFuture, EitherOf3};
use either_of::{Either, EitherOf3};
use futures::FutureExt;
use leptos::{component, oco::Oco, IntoView};
use or_poisoned::OrPoisoned;
use reactive_graph::{
computed::{ArcMemo, Memo, ScopedFuture},
owner::{provide_context, use_context, Owner},
signal::{ArcRwSignal, ArcTrigger},
traits::{Get, GetUntracked, Read, ReadUntracked, Set, Track, Trigger}, transition::AsyncTransition, wrappers::write::SignalSetter,
computed::{ScopedFuture},
owner::{provide_context, Owner},
signal::{ArcRwSignal},
traits::{ReadUntracked, Set},
transition::AsyncTransition,
wrappers::write::SignalSetter,
};
use std::{
borrow::Cow,
cell::RefCell,
future::Future,
iter,
marker::PhantomData,
mem,
rc::Rc,
sync::{
mpsc::{self, Receiver, Sender},
Arc, Mutex,
},
};
use tachys::{
hydration::Cursor,
@ -36,8 +28,6 @@ use tachys::{
ssr::StreamBuilder,
view::{
add_attr::AddAnyAttr,
any_view::{AnyView, AnyViewState, IntoAny},
either::EitherState,
Mountable, Position, PositionState, Render, RenderHtml,
},
};
@ -149,6 +139,7 @@ where
Fal: Render<R> + 'static,
R: Renderer + 'static
{
#[allow(clippy::type_complexity)]
view: <EitherOf3<(), Fal, <Defs::Match as MatchInterface<R>>::View> as Render<R>>::State,
id: Option<RouteMatchId>,
owner: Owner,
@ -204,7 +195,7 @@ where
let current_url = current_url.read_untracked();
// we always need to match the new route
let new_match = routes.match_route(&current_url.path());
let new_match = routes.match_route(current_url.path());
let id = new_match.as_ref().map(|n| n.as_id());
// create default starting points for owner, url, path, and params
@ -364,7 +355,7 @@ where
Executor::spawn_local(owner.with(|| {
ScopedFuture::new({
let state = Rc::clone(&state);
let state = Rc::clone(state);
async move {
provide_context(url);
provide_context(params);
@ -413,7 +404,7 @@ where
fn add_any_attr<NewAttr: leptos::attr::Attribute<R>>(
self,
attr: NewAttr,
_attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<R>,
@ -433,7 +424,7 @@ where
self,
) -> Either<Fal, <Defs::Match as MatchInterface<R>>::View> {
let current_url = self.current_url.read_untracked();
let new_match = self.routes.match_route(&current_url.path());
let new_match = self.routes.match_route(current_url.path());
let owner = self.outer_owner.child();
let url = ArcRwSignal::new(current_url.to_owned());
let params = ArcRwSignal::new(
@ -487,7 +478,7 @@ where
if RouteList::is_generating() {
// add routes
let (base, routes) = self.routes.generate_routes();
let mut routes = routes
let routes = routes
.into_iter()
.map(|data| {
let path = base
@ -557,7 +548,6 @@ where
// client-side route component code is not yet loaded
let FlatRoutesView {
current_url,
location,
routes,
fallback,
outer_owner,
@ -566,7 +556,7 @@ where
let current_url = current_url.read_untracked();
// we always need to match the new route
let new_match = routes.match_route(&current_url.path());
let new_match = routes.match_route(current_url.path());
let id = new_match.as_ref().map(|n| n.as_id());
// create default starting points for owner, url, path, and params

View file

@ -1,18 +1,16 @@
use crate::{
components::RouterContext,
location::{Location, Url},
navigate::{NavigateOptions, UseNavigate},
navigate::NavigateOptions,
params::{Params, ParamsError, ParamsMap},
RouteContext,
};
use leptos::{leptos_dom::helpers::window, oco::Oco};
use reactive_graph::{
computed::{ArcMemo, Memo},
owner::use_context,
signal::{ArcReadSignal, ArcRwSignal, ReadSignal},
traits::{Get, Read, With},
signal::{ArcRwSignal, ReadSignal},
traits::{Get, With},
};
use std::{rc::Rc, str::FromStr};
use tachys::renderer::Renderer;
/*
/// Constructs a signal synchronized with a specific URL query parameter.
@ -239,6 +237,7 @@ pub(crate) fn use_is_back_navigation() -> ReadSignal<bool> {
}
*/
/* TODO check how this is used in 0.6 and use it
/// Resolves a redirect location to an (absolute) URL.
pub(crate) fn resolve_redirect_url(loc: &str) -> Option<web_sys::Url> {
let origin = match window().location().origin() {
@ -263,3 +262,4 @@ pub(crate) fn resolve_redirect_url(loc: &str) -> Option<web_sys::Url> {
}
}
}
*/

View file

@ -1,16 +1,8 @@
use crate::{
components::RouterContext,
hooks::{use_location, use_resolved_path},
location::State,
components::RouterContext, hooks::use_resolved_path, location::State,
};
use either_of::Either;
use leptos::{
children::{Children, TypedChildren},
oco::Oco,
prelude::*,
*,
};
use reactive_graph::{computed::ArcMemo, effect::Effect, owner::use_context};
use leptos::{children::Children, oco::Oco, prelude::*, *};
use reactive_graph::{computed::ArcMemo, owner::use_context};
use std::borrow::Cow;
/// Describes a value that is either a static or a reactive URL, i.e.,
@ -80,16 +72,6 @@ pub fn A<H>(
/// if false, link is marked active if the current route starts with it.
#[prop(optional)]
exact: bool,
/// Provides a class to be added when the link is active. If provided, it will
/// be added at the same time that the `aria-current` attribute is set.
///
/// This supports multiple space-separated class names.
///
/// **Performance**: If its possible to style the link using the CSS with the
/// `[aria-current=page]` selector, you should prefer that, as it enables significant
/// SSR optimizations.
#[prop(optional, into)]
active_class: Option<Oco<'static, str>>,
/// An object of any type that will be pushed to router state
#[prop(optional)]
state: Option<State>,
@ -97,17 +79,6 @@ pub fn A<H>(
/// will skip this page.)
#[prop(optional)]
replace: bool,
// TODO arbitrary attributes
/*/// Sets the `class` attribute on the underlying `<a>` tag, making it easier to style.
#[prop(optional, into)]
class: Option<AttributeValue>,
/// Sets the `id` attribute on the underlying `<a>` tag, making it easier to target.
#[prop(optional, into)]
id: Option<Oco<'static, str>>,
/// Arbitrary attributes to add to the `<a>`. Attributes can be added with the
/// `attr:` syntax in the `view` macro.
#[prop(attrs)]
attributes: Vec<(&'static str, Attribute)>,*/
/// The nodes or elements to be shown inside the link.
children: Children,
) -> impl IntoView
@ -120,7 +91,6 @@ where
exact: bool,
#[allow(unused)] state: Option<State>,
#[allow(unused)] replace: bool,
#[allow(unused)] active_class: Option<Oco<'static, str>>,
children: Children,
) -> impl IntoView {
let RouterContext { current_url, .. } =
@ -143,7 +113,7 @@ where
}
});
let mut a = view! {
view! {
<a
href=move || href.get().unwrap_or_default()
target=target
@ -155,31 +125,11 @@ where
}
>
// TODO attributes
// class=class
// id=id
{children()}
</a>
};
/*if let Some(active_class) = active_class {
let classes = active_class
.split_ascii_whitespace()
.map(|class| Cow::Owned(class.to_string()))
.collect::<Vec<_>>();
Either::Left(a.class((classes, move || is_active.get())))
} else {
Either::Right(a)
}*/
a
// TODO attributes
/*for (attr_name, attr_value) in attributes {
a = a.attr(attr_name, attr_value);
}*/
}
}
let href = use_resolved_path::<Dom>(move || href.to_href()());
inner(href, target, exact, state, replace, active_class, children)
inner(href, target, exact, state, replace, children)
}

View file

@ -1,10 +1,8 @@
use super::{
handle_anchor_click, LocationChange, LocationProvider, State, Url, BASE,
};
use crate::{navigate::UseNavigate, params::ParamsMap};
use super::{handle_anchor_click, LocationChange, LocationProvider, Url};
use crate::params::ParamsMap;
use core::fmt;
use futures::channel::oneshot;
use js_sys::{try_iter, Array, JsString, Reflect};
use js_sys::{try_iter, Array, JsString};
use or_poisoned::OrPoisoned;
use reactive_graph::{
signal::ArcRwSignal,
@ -13,14 +11,12 @@ use reactive_graph::{
use std::{
borrow::Cow,
boxed::Box,
cell::RefCell,
rc::Rc,
string::String,
sync::{Arc, Mutex},
};
use tachys::dom::{document, window};
use wasm_bindgen::{closure::Closure, JsCast, JsValue};
use web_sys::{Event, HtmlAnchorElement, MouseEvent, UrlSearchParams};
use web_sys::{Event, UrlSearchParams};
#[derive(Clone)]
pub struct BrowserUrl {
@ -183,7 +179,7 @@ impl LocationProvider for BrowserUrl {
fn ready_to_complete(&self) {
if let Some(tx) = self.pending_navigation.lock().or_poisoned().take() {
tx.send(());
_ = tx.send(());
}
}

View file

@ -3,11 +3,11 @@ use core::fmt::Debug;
use js_sys::Reflect;
use reactive_graph::{
computed::Memo,
signal::{ArcReadSignal, ArcRwSignal, ReadSignal, RwSignal},
signal::{ArcRwSignal, ReadSignal},
traits::With,
};
use send_wrapper::SendWrapper;
use std::{borrow::Cow, future::Future, sync::Arc};
use std::{borrow::Cow, future::Future};
use tachys::dom::window;
use wasm_bindgen::{JsCast, JsValue};
use web_sys::{Event, HtmlAnchorElement, MouseEvent};
@ -140,7 +140,7 @@ pub trait LocationProvider: Clone + 'static {
fn parse_with_base(url: &str, base: &str) -> Result<Url, Self::Error>;
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Default)]
pub struct State(Option<SendWrapper<JsValue>>);
impl State {
@ -156,12 +156,6 @@ impl State {
}
}
impl Default for State {
fn default() -> Self {
Self(None)
}
}
impl PartialEq for State {
fn eq(&self, other: &Self) -> bool {
self.0.as_ref().map(|n| n.as_ref())

View file

@ -6,13 +6,13 @@ pub use path_segment::*;
mod horizontal;
mod nested;
mod vertical;
use crate::{Method, SsrMode};
use crate::SsrMode;
pub use horizontal::*;
pub use nested::*;
use std::{borrow::Cow, marker::PhantomData};
use tachys::{
renderer::Renderer,
view::{any_view::IntoAny, Render, RenderHtml},
view::{Render, RenderHtml},
};
pub use vertical::*;
@ -142,7 +142,7 @@ where
}
#[derive(Default)]
pub(crate) struct GeneratedRouteData {
pub struct GeneratedRouteData {
pub segments: Vec<PathSegment>,
pub ssr_mode: SsrMode,
}

View file

@ -200,7 +200,7 @@ where
params,
matched,
}| {
let (id, inner, remaining) = match &self.children {
let (_, inner, remaining) = match &self.children {
None => (None, None, remaining),
Some(children) => {
let (inner, remaining) = children.match_nested(remaining);

View file

@ -2,7 +2,7 @@ use super::{MatchInterface, MatchNestedRoutes, PathSegment, RouteMatchId};
use crate::{ChooseView, GeneratedRouteData, MatchParams};
use core::iter;
use either_of::*;
use std::{any::Any, borrow::Cow};
use std::borrow::Cow;
use tachys::renderer::Renderer;
impl MatchParams for () {

View file

@ -60,16 +60,17 @@ fn normalize(path: &str, omit_slash: bool) -> Cow<'_, str> {
}
}
fn begins_with_query_or_hash(text: &str) -> bool {
matches!(text.chars().next(), Some('#') | Some('?'))
}
/* TODO can remove?
#[doc(hidden)]
pub fn join_paths<'a>(from: &'a str, to: &'a str) -> String {
let from = remove_wildcard(&normalize(from, false));
from + normalize(to, false).as_ref()
}
fn begins_with_query_or_hash(text: &str) -> bool {
matches!(text.chars().next(), Some('#') | Some('?'))
}
fn remove_wildcard(text: &str) -> String {
text.rsplit_once('*')
.map(|(prefix, _)| prefix)
@ -77,6 +78,7 @@ fn remove_wildcard(text: &str) -> String {
.trim_end_matches('/')
.to_string()
}
*/
#[cfg(test)]
mod tests {

View file

@ -1,5 +1,4 @@
use crate::location::State;
use std::sync::Arc;
/// Options that can be used to configure a navigation. Used with [use_navigate](crate::use_navigate).
#[derive(Clone, Debug)]
@ -27,16 +26,3 @@ impl Default for NavigateOptions {
}
}
}
#[derive(Clone)]
pub(crate) struct UseNavigate(
pub Arc<dyn Fn(&str, NavigateOptions) + Send + Sync>,
);
impl UseNavigate {
pub fn new(
fun: impl Fn(&str, NavigateOptions) + Send + Sync + 'static,
) -> Self {
Self(Arc::new(fun))
}
}

View file

@ -1,21 +1,20 @@
use crate::{
location::{Location, LocationProvider, RequestUrl, Url},
location::{LocationProvider, Url},
matching::Routes,
params::ParamsMap,
resolve_path::resolve_path,
ChooseView, MatchInterface, MatchNestedRoutes, MatchParams, Method,
PathSegment, RouteList, RouteListing, RouteMatchId,
};
use any_spawner::Executor;
use either_of::{Either, EitherOf3};
use futures::future::join_all;
use leptos::{component, oco::Oco, IntoView};
use leptos::{component, oco::Oco};
use or_poisoned::OrPoisoned;
use reactive_graph::{
computed::{ArcMemo, Memo, ScopedFuture},
computed::ScopedFuture,
owner::{provide_context, use_context, Owner},
signal::{ArcRwSignal, ArcTrigger},
traits::{Get, Read, ReadUntracked, Set, Track, Trigger},
traits::{ReadUntracked, Set, Track, Trigger},
wrappers::write::SignalSetter,
};
use std::{
@ -37,8 +36,8 @@ use tachys::{
ssr::StreamBuilder,
view::{
add_attr::AddAnyAttr,
any_view::{AnyView, AnyViewState, IntoAny},
either::{EitherOf3State, EitherState},
any_view::{AnyView, IntoAny},
either::EitherOf3State,
Mountable, Position, PositionState, Render, RenderHtml,
},
};
@ -54,6 +53,7 @@ pub(crate) struct NestedRoutesView<Loc, Defs, Fal, R> {
pub current_url: ArcRwSignal<Url>,
pub base: Option<Oco<'static, str>>,
pub fallback: Fal,
#[allow(unused)] // TODO
pub set_is_routing: Option<SignalSetter<bool>>,
pub rndr: PhantomData<R>,
}
@ -65,9 +65,9 @@ where
{
path: String,
current_url: ArcRwSignal<Url>,
outer_owner: Owner,
outlets: Vec<RouteContext<R>>,
// TODO loading fallback
#[allow(clippy::type_complexity)]
view: Rc<RefCell<EitherOf3State<(), Fal, AnyView<R>, R>>>,
}
@ -88,7 +88,6 @@ where
current_url,
fallback,
base,
set_is_routing,
..
} = self;
@ -97,8 +96,7 @@ where
let url = current_url.read_untracked();
// match the route
let new_match = routes.match_route(&url.path());
let id = new_match.as_ref().map(|n| n.as_id());
let new_match = routes.match_route(url.path());
// start with an empty view because we'll be loading routes async
let view = EitherOf3::A(()).build();
@ -107,7 +105,7 @@ where
None => EitherOf3::B(fallback),
Some(route) => {
route.build_nested_route(
&*url,
&url,
base,
&mut loaders,
&mut outlets,
@ -138,7 +136,6 @@ where
current_url,
outlets,
view,
outer_owner,
}
}
@ -157,7 +154,9 @@ where
state.path.clear();
state.path.push_str(url_snapshot.path());
let new_match = self.routes.match_route(&url_snapshot.path());
state.current_url.set(url_snapshot.to_owned());
let new_match = self.routes.match_route(url_snapshot.path());
match new_match {
None => {
@ -168,7 +167,7 @@ where
Some(route) => {
let mut loaders = Vec::new();
route.rebuild_nested_route(
&*self.current_url.read_untracked(),
&self.current_url.read_untracked(),
self.base,
&mut 0,
&mut loaders,
@ -214,7 +213,7 @@ where
fn add_any_attr<NewAttr: leptos::attr::Attribute<R>>(
self,
attr: NewAttr,
_attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<R>,
@ -245,7 +244,7 @@ where
if RouteList::is_generating() {
// add routes
let (base, routes) = self.routes.generate_routes();
let mut routes = routes
let routes = routes
.into_iter()
.map(|data| {
let path = base
@ -303,7 +302,7 @@ where
None => Either::Left(fallback),
Some(route) => {
route.build_nested_route(
&*current_url,
&current_url,
base,
&mut Vec::new(),
&mut outlets,
@ -338,12 +337,12 @@ where
let current_url = current_url.read_untracked();
let mut outlets = Vec::new();
let new_match = routes.match_route(&current_url.path());
let new_match = routes.match_route(current_url.path());
let view = match new_match {
None => Either::Left(fallback),
Some(route) => {
route.build_nested_route(
&*current_url,
&current_url,
base,
&mut Vec::new(),
&mut outlets,
@ -370,7 +369,6 @@ where
current_url,
fallback,
base,
set_is_routing,
..
} = self;
@ -379,8 +377,7 @@ where
let url = current_url.read_untracked();
// match the route
let new_match = routes.match_route(&url.path());
let id = new_match.as_ref().map(|n| n.as_id());
let new_match = routes.match_route(url.path());
// start with an empty view because we'll be loading routes async
let view = Rc::new(RefCell::new(
@ -388,7 +385,7 @@ where
None => EitherOf3::B(fallback),
Some(route) => {
route.build_nested_route(
&*url,
&url,
base,
&mut loaders,
&mut outlets,
@ -409,7 +406,6 @@ where
current_url,
outlets,
view,
outer_owner,
}
}
}
@ -448,7 +444,7 @@ where
fn clone(&self) -> Self {
Self {
url: self.url.clone(),
id: self.id.clone(),
id: self.id,
trigger: self.trigger.clone(),
params: self.params.clone(),
owner: self.owner.clone(),
@ -555,7 +551,8 @@ where
provide_context(url);
let view =
owner.with(|| ScopedFuture::new(view.choose())).await;
tx.send(Box::new(move || owner.with(|| view.into_any())));
tx.send(Box::new(move || owner.with(|| view.into_any())))
.unwrap();
trigger
}
})
@ -651,7 +648,8 @@ where
.await;
tx.send(Box::new(move || {
owner.with(|| view.into_any())
}));
}))
.unwrap();
drop(old_owner);
drop(old_params);
drop(old_url);
@ -728,15 +726,7 @@ where
_ = rndr;
let ctx = use_context::<RouteContext<R>>()
.expect("<Outlet/> used without RouteContext being provided.");
let RouteContext {
id,
trigger,
params,
owner,
tx,
rx,
..
} = ctx;
let RouteContext { trigger, rx, .. } = ctx;
let rx = rx.lock().or_poisoned().take().expect(
"Tried to render <Outlet/> but could not find the view receiver. Are \
you using the same <Outlet/> twice?",

View file

@ -138,6 +138,9 @@ where
// TODO can we support Option<T> and T in a non-nightly way?
#[cfg(feature = "nightly")]
mod option_param {
use super::{IntoParam, ParamsError};
use std::{str::FromStr, sync::Arc};
auto trait NotOption {}
impl<T> !NotOption for Option<T> {}

View file

@ -14,6 +14,7 @@ pub enum StaticMode {
pub struct StaticDataMap;
impl StaticDataMap {
#[allow(clippy::new_without_default)] // TODO
pub fn new() -> Self {
Self
}

View file

@ -1,10 +1,8 @@
use serde::{Deserialize, Serialize};
use std::{
error, fmt,
fmt,
fmt::{Display, Write},
ops,
str::FromStr,
sync::Arc,
};
use thiserror::Error;
use throw_error::Error;

View file

@ -6,11 +6,10 @@ pub use gloo_net::http::Request;
use js_sys::{Reflect, Uint8Array};
use send_wrapper::SendWrapper;
use std::ops::{Deref, DerefMut};
use thiserror::Error;
use wasm_bindgen::{JsCast, JsValue};
use wasm_bindgen::JsValue;
use wasm_streams::ReadableStream;
use web_sys::{
AbortController, AbortSignal, Event, FormData, Headers, RequestInit,
AbortController, AbortSignal, FormData, Headers, RequestInit,
UrlSearchParams,
};
@ -215,11 +214,12 @@ impl<CustErr> ClientReq<CustErr> for BrowserRequest {
body: impl Stream<Item = Bytes> + 'static,
) -> Result<Self, ServerFnError<CustErr>> {
// TODO abort signal
let req = streaming_request(path, accepts, content_type, body)
.map_err(|e| ServerFnError::Request(format!("{e:?}")))?;
let (request, abort_ctrl) =
streaming_request(path, accepts, content_type, body)
.map_err(|e| ServerFnError::Request(format!("{e:?}")))?;
Ok(Self(SendWrapper::new(RequestInner {
request: req,
abort_ctrl: None,
request,
abort_ctrl,
})))
}
}
@ -229,7 +229,7 @@ fn streaming_request(
accepts: &str,
content_type: &str,
body: impl Stream<Item = Bytes> + 'static,
) -> Result<Request, JsValue> {
) -> Result<(Request, Option<AbortOnDrop>), JsValue> {
let (abort_ctrl, abort_signal) = abort_signal();
let stream = ReadableStream::from_stream(body.map(|bytes| {
let data = Uint8Array::from(bytes.as_ref());
@ -241,7 +241,10 @@ fn streaming_request(
headers.append("Content-Type", content_type)?;
headers.append("Accept", accepts)?;
let mut init = RequestInit::new();
init.headers(&headers).method("POST").body(Some(&stream));
init.headers(&headers)
.method("POST")
.signal(abort_signal.as_ref())
.body(Some(&stream));
// Chrome requires setting `duplex: "half"` on streaming requests
Reflect::set(
@ -250,5 +253,5 @@ fn streaming_request(
&JsValue::from_str("half"),
)?;
let req = web_sys::Request::new_with_str_and_init(path, &init)?;
Ok(Request::from(req))
Ok((Request::from(req), abort_ctrl))
}

View file

@ -12,29 +12,7 @@ use any_spawner::Executor;
use either_of::Either;
use futures::FutureExt;
use parking_lot::RwLock;
use std::{cell::RefCell, fmt::Debug, future::Future, rc::Rc, sync::Arc};
pub struct SuspenseBoundary<const TRANSITION: bool, Fal, Chil> {
in_fallback: bool,
fallback: Option<Fal>,
children: Chil,
}
impl<const TRANSITION: bool, Fal, Chil>
SuspenseBoundary<TRANSITION, Fal, Chil>
{
pub fn new(
in_fallback: bool,
fallback: Option<Fal>,
children: Chil,
) -> Self {
Self {
in_fallback,
fallback,
children,
}
}
}
use std::{fmt::Debug, future::Future, sync::Arc};
pub trait FutureViewExt: Sized {
fn suspend(self) -> Suspend<false, (), Self>

View file

@ -42,7 +42,7 @@ where
Self {
key: self.key.clone(),
value: self.value.clone(),
rndr: self.rndr.clone(),
rndr: self.rndr,
}
}
}

View file

@ -3,7 +3,7 @@ use crate::{
renderer::DomRenderer,
view::{Position, ToTemplate},
};
use std::{marker::PhantomData, rc::Rc, sync::Arc};
use std::{marker::PhantomData, sync::Arc};
#[inline(always)]
pub fn class<C, R>(class: C) -> Class<C, R>

View file

@ -108,6 +108,7 @@ where
}
}
#[allow(clippy::type_complexity)]
pub fn on_target<E, T, R, F>(
event: E,
mut cb: F,

View file

@ -1,8 +1,7 @@
use self::attribute::Attribute;
use crate::{
no_attrs,
renderer::Renderer,
view::{add_attr::AddAnyAttr, Position, Render, RenderHtml},
view::{Position, Render, RenderHtml},
};
use std::marker::PhantomData;

View file

@ -4,10 +4,7 @@ use crate::{
no_attrs,
prelude::{Mountable, Render, RenderHtml},
renderer::{DomRenderer, Renderer},
view::{
add_attr::AddAnyAttr, strings::StrState, Position, PositionState,
ToTemplate,
},
view::{strings::StrState, Position, PositionState, ToTemplate},
};
use oco_ref::Oco;

View file

@ -8,7 +8,6 @@ use crate::{
RenderHtml, ToTemplate,
},
};
use or_poisoned::OrPoisoned;
use reactive_graph::effect::RenderEffect;
use std::sync::{Arc, Mutex};
@ -454,8 +453,8 @@ mod stable {
type Output<SomeNewAttr: Attribute<R>> = $sig<V>;
fn add_any_attr<NewAttr: Attribute<R>>(
mut self,
attr: NewAttr,
self,
_attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<R>,
@ -598,8 +597,8 @@ mod stable {
type Output<SomeNewAttr: Attribute<R>> = $sig<V>;
fn add_any_attr<NewAttr: Attribute<R>>(
mut self,
attr: NewAttr,
self,
_attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<R>,

View file

@ -1,11 +1,7 @@
use super::{ReactiveFunction, SharedReactiveFunction};
use crate::{html::style::IntoStyle, renderer::DomRenderer};
use or_poisoned::OrPoisoned;
use reactive_graph::effect::RenderEffect;
use std::{
borrow::Cow,
sync::{Arc, Mutex},
};
use std::borrow::Cow;
impl<F, S, R> IntoStyle<R> for (&'static str, F)
where

View file

@ -211,7 +211,7 @@ impl SNode {
Self(Rc::new(SNodeInner(id)))
}
fn to_node(&self) -> Node {
pub fn to_node(&self) -> Node {
CHANNEL.with_borrow(|channel| get_node(channel.js_channel(), self.0 .0))
}
}
@ -255,6 +255,7 @@ fn with(fun: impl FnOnce(&mut Channel)) {
flush();
}
#[allow(unused)] // might be handy at some point!
fn flush_sync() {
FLUSH_PENDING.set(false);
CHANNEL.with_borrow_mut(|channel| channel.flush());
@ -327,9 +328,8 @@ impl Renderer for Sledgehammer {
with(|channel| channel.remove(node.0 .0));
}
fn get_parent(node: &Self::Node) -> Option<Self::Node> {
todo!()
//node.parent_node()
fn get_parent(_node: &Self::Node) -> Option<Self::Node> {
todo!() // node.parent_node()
}
fn first_child(node: &Self::Node) -> Option<Self::Node> {
@ -344,7 +344,7 @@ impl Renderer for Sledgehammer {
Some(sibling)
}
fn log_node(node: &Self::Node) {
fn log_node(_node: &Self::Node) {
todo!()
}
@ -357,6 +357,7 @@ impl Renderer for Sledgehammer {
pub struct ClassList(SNode);
#[derive(Debug, Clone)]
#[allow(dead_code)] // this will be used, it's just all unimplemented
pub struct CssStyle(SNode);
impl DomRenderer for Sledgehammer {
@ -365,16 +366,7 @@ impl DomRenderer for Sledgehammer {
type CssStyleDeclaration = CssStyle;
type TemplateElement = SNode;
fn set_property(el: &Self::Element, key: &str, value: &JsValue) {
/* or_debug!(
js_sys::Reflect::set(
el,
&wasm_bindgen::JsValue::from_str(key),
value,
),
el,
"setProperty"
);*/
fn set_property(_el: &Self::Element, _key: &str, _value: &JsValue) {
todo!()
}
@ -391,10 +383,10 @@ impl DomRenderer for Sledgehammer {
});
// return the remover
Box::new(move |el| todo!())
Box::new(move |_el| todo!())
}
fn event_target<T>(ev: &Self::Event) -> T
fn event_target<T>(_ev: &Self::Event) -> T
where
T: CastFrom<Self::Element>,
{
@ -489,7 +481,7 @@ impl DomRenderer for Sledgehammer {
});
// return the remover
Box::new(move |el| todo!())
Box::new(move |_el| todo!())
}
fn class_list(el: &Self::Element) -> Self::ClassList {
@ -506,15 +498,15 @@ impl DomRenderer for Sledgehammer {
with(|channel| channel.remove_class(list.0 .0 .0, name));
}
fn style(el: &Self::Element) -> Self::CssStyleDeclaration {
fn style(_el: &Self::Element) -> Self::CssStyleDeclaration {
todo!()
//el.unchecked_ref::<HtmlElement>().style()
}
fn set_css_property(
style: &Self::CssStyleDeclaration,
name: &str,
value: &str,
_style: &Self::CssStyleDeclaration,
_name: &str,
_value: &str,
) {
todo!()
/*or_debug!(

View file

@ -25,14 +25,14 @@ where
#[macro_export]
macro_rules! no_attrs {
($ty_name:ty) => {
impl<'a, R> crate::view::add_attr::AddAnyAttr<R> for $ty_name
impl<'a, R> $crate::view::add_attr::AddAnyAttr<R> for $ty_name
where
R: Renderer,
{
type Output<SomeNewAttr: crate::html::attribute::Attribute<R>> =
type Output<SomeNewAttr: $crate::html::attribute::Attribute<R>> =
$ty_name;
fn add_any_attr<NewAttr: crate::html::attribute::Attribute<R>>(
fn add_any_attr<NewAttr: $crate::html::attribute::Attribute<R>>(
self,
_attr: NewAttr,
) -> Self::Output<NewAttr> {

View file

@ -288,7 +288,7 @@ where
fn add_any_attr<NewAttr: Attribute<R>>(
self,
attr: NewAttr,
_attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<R>,
@ -391,6 +391,17 @@ where
);
}
}
fn html_len(&self) -> usize {
#[cfg(feature = "ssr")]
{
self.html_len
}
#[cfg(not(feature = "ssr"))]
{
0
}
}
}
impl<R> Mountable<R> for AnyViewState<R>

View file

@ -306,8 +306,8 @@ where
Rndr: Renderer,
{
type Output<SomeNewAttr: Attribute<Rndr>> = EitherKeepAlive<
<A as AddAnyAttr<Rndr>>::Output<SomeNewAttr>,
<B as AddAnyAttr<Rndr>>::Output<SomeNewAttr>,
<A as AddAnyAttr<Rndr>>::Output<SomeNewAttr::Cloneable>,
<B as AddAnyAttr<Rndr>>::Output<SomeNewAttr::Cloneable>,
>;
fn add_any_attr<NewAttr: Attribute<Rndr>>(
@ -317,7 +317,13 @@ where
where
Self::Output<NewAttr>: RenderHtml<Rndr>,
{
todo!()
let EitherKeepAlive { a, b, show_b } = self;
let attr = attr.into_cloneable();
EitherKeepAlive {
a: a.map(|a| a.add_any_attr(attr.clone())),
b: b.map(|b| b.add_any_attr(attr.clone())),
show_b,
}
}
}

View file

@ -129,7 +129,7 @@ where
where
Self::Output<NewAttr>: RenderHtml<R>,
{
todo!()
self.map(|inner| inner.add_any_attr(attr))
}
}
@ -144,9 +144,8 @@ where
const MIN_LENGTH: usize = T::MIN_LENGTH;
fn dry_resolve(&mut self) {
match self.as_mut() {
Ok(inner) => inner.dry_resolve(),
_ => {}
if let Ok(inner) = self.as_mut() {
inner.dry_resolve()
}
}

View file

@ -1,4 +1,4 @@
use self::{add_attr::AddAnyAttr, fragment::Fragment};
use self::add_attr::AddAnyAttr;
use crate::{hydration::Cursor, renderer::Renderer, ssr::StreamBuilder};
use parking_lot::RwLock;
use std::{cell::RefCell, future::Future, rc::Rc, sync::Arc};

View file

@ -168,8 +168,12 @@ where
fn dry_resolve(&mut self) {}
fn resolve(self) -> futures::future::Ready<Self::AsyncOutput> {
futures::future::ready(self)
// this won't actually compile because if a weird interaction because the const &'static str and
// the RPITIT, so we just refine it to a concrete future type; this will never change in any
// case
#[allow(refining_impl_trait)]
fn resolve(self) -> std::future::Ready<Self> {
std::future::ready(self)
}
fn to_html_with_buf(self, buf: &mut String, position: &mut Position) {
@ -209,7 +213,7 @@ where
fn add_any_attr<NewAttr: Attribute<R>>(
self,
attr: NewAttr,
_attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<R>,

View file

@ -61,7 +61,7 @@ where
fn add_any_attr<NewAttr: Attribute<R>>(
self,
attr: NewAttr,
_attr: NewAttr,
) -> Self::Output<NewAttr>
where
Self::Output<NewAttr>: RenderHtml<R>,