wip: updates to router

This commit is contained in:
Jonathan Kelley committed 2021-11-22 15:22:42 -05:00
1 parent a5f05d73ac
commit bab21a0aa1
8 files changed
+208 -217

No files matched your search

+33 -33
View File
@@ -206,43 +206,43 @@ pub fn routable_derive_impl(input: Routable) -> TokenStream {
// static #cache_thread_local_ident: ::std::cell::RefCell<::std::option::Option<#ident>> = ::std::cell::RefCell::new(::std::option::Option::None);
// }
#[automatically_derived]
impl ::dioxus::router::Routable for #ident {
#from_path
#to_path
// #[automatically_derived]
// impl ::dioxus::router::Routable for #ident {
// #from_path
// #to_path
fn routes() -> ::std::vec::Vec<&'static str> {
::std::vec![#(#ats),*]
}
// // fn routes() -> ::std::vec::Vec<&'static str> {
// // ::std::vec![#(#ats),*]
// // }
fn not_found_route() -> ::std::option::Option<Self> {
#not_found_route
}
// fn not_found_route() -> ::std::option::Option<Self> {
// #not_found_route
// }
// fn current_route() -> ::std::option::Option<Self> {
// #cache_thread_local_ident.with(|val| ::std::clone::Clone::clone(&*val.borrow()))
// }
// // fn current_route() -> ::std::option::Option<Self> {
// // #cache_thread_local_ident.with(|val| ::std::clone::Clone::clone(&*val.borrow()))
// // }
fn recognize(pathname: &str) -> ::std::option::Option<Self> {
todo!()
// ::std::thread_local! {
// static ROUTER: ::dioxus::router::__macro::Router = ::dioxus::router::__macro::build_router::<#ident>();
// }
// let route = ROUTER.with(|router| ::dioxus::router::__macro::recognize_with_router(router, pathname));
// {
// let route = ::std::clone::Clone::clone(&route);
// #cache_thread_local_ident.with(move |val| {
// *val.borrow_mut() = route;
// });
// }
// route
}
// fn recognize(pathname: &str) -> ::std::option::Option<Self> {
// todo!()
// // ::std::thread_local! {
// // static ROUTER: ::dioxus::router::__macro::Router = ::dioxus::router::__macro::build_router::<#ident>();
// // }
// // let route = ROUTER.with(|router| ::dioxus::router::__macro::recognize_with_router(router, pathname));
// // {
// // let route = ::std::clone::Clone::clone(&route);
// // #cache_thread_local_ident.with(move |val| {
// // *val.borrow_mut() = route;
// // });
// // }
// // route
// }
// fn cleanup() {
// #cache_thread_local_ident.with(move |val| {
// *val.borrow_mut() = ::std::option::Option::None;
// });
// }
}
// // fn cleanup() {
// // #cache_thread_local_ident.with(move |val| {
// // *val.borrow_mut() = ::std::option::Option::None;
// // });
// // }
// }
}
}
-26
View File
@@ -74,7 +74,6 @@ pub struct SelfReferentialItems<'a> {
pub(crate) borrowed_props: Vec<&'a VComponent<'a>>,
pub(crate) suspended_nodes: FxHashMap<u64, &'a VSuspended>,
pub(crate) tasks: Vec<BumpBox<'a, dyn Future<Output = ()>>>,
pub(crate) pending_effects: Vec<BumpBox<'a, dyn FnMut()>>,
}
/// A component's unique identifier.
@@ -284,24 +283,6 @@ impl Scope {
}
}
/// Push an effect to be ran after the component has been successfully mounted to the dom
/// Returns the effect's position in the stack
pub fn push_effect<'src>(&'src self, effect: impl FnOnce() + 'src) -> usize {
// this is some tricker to get around not being able to actually call fnonces
let mut slot = Some(effect);
let fut: &mut dyn FnMut() = self.bump().alloc(move || slot.take().unwrap()());
// wrap it in a type that will actually drop the contents
let boxed_fut = unsafe { BumpBox::from_raw(fut) };
// erase the 'src lifetime for self-referential storage
let self_ref_fut = unsafe { std::mem::transmute(boxed_fut) };
let mut items = self.items.borrow_mut();
items.pending_effects.push(self_ref_fut);
items.pending_effects.len() - 1
}
/// Pushes the future onto the poll queue to be polled
/// The future is forcibly dropped if the component is not ready by the next render
pub fn push_task<'src, F: Future<Output = ()>>(
@@ -483,13 +464,6 @@ impl Scope {
}
}
// run the list of effects
pub(crate) fn run_effects(&mut self) {
for mut effect in self.items.get_mut().pending_effects.drain(..) {
effect();
}
}
pub fn root_node(&self) -> &VNode {
let node = *self.wip_frame().nodes.borrow().get(0).unwrap();
unsafe { std::mem::transmute(&*node) }
-5
View File
@@ -188,7 +188,6 @@ impl ScopeArena {
borrowed_props: Default::default(),
suspended_nodes: Default::default(),
tasks: Default::default(),
pending_effects: Default::default(),
}),
});
@@ -226,14 +225,12 @@ impl ScopeArena {
let SelfReferentialItems {
borrowed_props,
listeners,
pending_effects,
suspended_nodes,
tasks,
} = scope.items.get_mut();
borrowed_props.clear();
listeners.clear();
pending_effects.clear();
suspended_nodes.clear();
tasks.clear();
@@ -328,14 +325,12 @@ impl ScopeArena {
// just forget about our suspended nodes while we're at it
items.suspended_nodes.clear();
items.tasks.clear();
items.pending_effects.clear();
// guarantee that we haven't screwed up - there should be no latent references anywhere
debug_assert!(items.listeners.is_empty());
debug_assert!(items.borrowed_props.is_empty());
debug_assert!(items.suspended_nodes.is_empty());
debug_assert!(items.tasks.is_empty());
debug_assert!(items.pending_effects.is_empty());
// Todo: see if we can add stronger guarantees around internal bookkeeping and failed component renders.
scope.wip_frame().nodes.borrow_mut().clear();
+1 -1
View File
@@ -409,7 +409,7 @@ class Interpreter {
}
function main() {
let root = window.document.getElementById("_dioxusroot");
let root = window.document.getElementById("main");
window.interpreter = new Interpreter(root);
console.log(window.interpreter);
+26 -32
View File
@@ -5,41 +5,35 @@ use dioxus_router::*;
fn main() {
console_error_panic_hook::set_once();
wasm_logger::init(wasm_logger::Config::new(log::Level::Debug));
dioxus_web::launch(App, |c| c);
}
#[derive(Clone, Debug, PartialEq)]
enum Route {
Home,
About,
NotFound,
}
static App: FC<()> = |cx, props| {
let route = use_router(cx, Route::parse);
match route {
Route::Home => rsx!(cx, div { "Home" }),
Route::About => rsx!(cx, div { "About" }),
Route::NotFound => rsx!(cx, div { "NotFound" }),
#[derive(Clone, Debug, PartialEq)]
enum Route {
Home,
About,
NotFound,
}
let route = use_router(cx, |s| match s {
"/" => Route::Home,
"/about" => Route::About,
_ => Route::NotFound,
});
cx.render(rsx! {
div {
{match route {
Route::Home => rsx!(h1 { "Home" }),
Route::About => rsx!(h1 { "About" }),
Route::NotFound => rsx!(h1 { "NotFound" }),
}}
nav {
Link { to: Route::Home, href: |_| "/".to_string() }
Link { to: Route::About, href: |_| "/about".to_string() }
}
}
})
};
impl ToString for Route {
fn to_string(&self) -> String {
match self {
Route::Home => "/".to_string(),
Route::About => "/about".to_string(),
Route::NotFound => "/404".to_string(),
}
}
}
impl Route {
fn parse(s: &str) -> Self {
match s {
"/" => Route::Home,
"/about" => Route::About,
_ => Route::NotFound,
}
}
}
+72 -22
View File
@@ -6,23 +6,24 @@ use dioxus_core as dioxus;
use dioxus_core::prelude::*;
use dioxus_core_macro::{format_args_f, rsx, Props};
use dioxus_html as dioxus_elements;
use wasm_bindgen::JsValue;
use web_sys::Event;
use wasm_bindgen::{JsCast, JsValue};
use web_sys::{window, Event};
use crate::utils::fetch_base_url;
use crate::utils::strip_slash_suffix;
pub trait Routable: 'static + Send + Clone + ToString + PartialEq {}
impl<T> Routable for T where T: 'static + Send + Clone + ToString + PartialEq {}
pub trait Routable: 'static + Send + Clone + PartialEq {}
impl<T> Routable for T where T: 'static + Send + Clone + PartialEq {}
pub struct RouterService<R: Routable> {
historic_routes: RefCell<Vec<R>>,
history_service: web_sys::History,
historic_routes: Vec<R>,
history_service: RefCell<web_sys::History>,
base_ur: RefCell<Option<String>>,
}
impl<R: Routable> RouterService<R> {
fn push_route(&self, r: R) {
self.historic_routes.borrow_mut().push(r);
todo!()
// self.historic_routes.borrow_mut().push(r);
}
fn get_current_route(&self) -> &str {
@@ -65,41 +66,73 @@ impl<R: Routable> RouterService<R> {
/// This hould only be used once per app
///
/// You can manually parse the route if you want, but the derived `parse` method on `Routable` will also work just fine
pub fn use_router<R: Routable>(cx: Context, parse: impl FnMut(&str) -> R) -> &R {
pub fn use_router<R: Routable>(cx: Context, mut parse: impl FnMut(&str) -> R + 'static) -> &R {
// for the web, attach to the history api
cx.use_hook(
|f| {
//
use gloo::events::EventListener;
let base_url = fetch_base_url();
let base = window()
.unwrap()
.document()
.unwrap()
.query_selector("base[href]")
.ok()
.flatten()
.and_then(|base| {
let base = JsCast::unchecked_into::<web_sys::HtmlBaseElement>(base).href();
let url = web_sys::Url::new(&base).unwrap();
if url.pathname() != "/" {
Some(strip_slash_suffix(&base).to_string())
} else {
None
}
});
let location = window().unwrap().location();
let pathname = location.pathname().unwrap();
let initial_route = parse(&pathname);
let service: RouterService<R> = RouterService {
historic_routes: RefCell::new(vec![]),
history_service: web_sys::window().unwrap().history().expect("no history"),
base_ur: RefCell::new(base_url),
historic_routes: vec![initial_route],
history_service: RefCell::new(
web_sys::window().unwrap().history().expect("no history"),
),
base_ur: RefCell::new(base),
};
// let base = base_url();
// let url = route.to_path();
// pending_routes: RefCell::new(vec![]),
// service.history_service.push_state(data, title);
cx.provide_state(service);
// cx.provide_state(service);
let regenerate = cx.schedule_update();
// when "back" is called by the user, we want to to re-render the component
// // when "back" is called by the user, we want to to re-render the component
let listener = EventListener::new(&web_sys::window().unwrap(), "popstate", move |_| {
//
regenerate();
});
service
},
|f| {
|state| {
let base = state.base_ur.borrow();
if let Some(base) = base.as_ref() {
//
let path = format!("{}{}", base, state.get_current_route());
}
let history = state.history_service.borrow();
todo!()
// history.state.historic_routes.last().unwrap()
//
},
);
todo!()
// let router = use_router_service::<R>(cx)?;
// Some(cfg(router.get_current_route()))
)
}
pub fn use_router_service<R: Routable>(cx: Context) -> Option<&Rc<RouterService<R>>> {
@@ -109,6 +142,23 @@ pub fn use_router_service<R: Routable>(cx: Context) -> Option<&Rc<RouterService<
#[derive(Props)]
pub struct LinkProps<R: Routable> {
to: R,
/// The url that gets pushed to the history stack
///
/// You can either put it your own inline method or just autoderive the route using `derive(Routable)`
///
/// ```rust
///
/// Link { to: Route::Home, href: |_| "home".to_string() }
///
/// // or
///
/// Link { to: Route::Home, href: Route::as_url }
///
/// ```
href: fn(&R) -> String,
#[builder(default)]
children: Element,
}
@@ -116,7 +166,7 @@ pub fn Link<R: Routable>(cx: Context, props: &LinkProps<R>) -> Element {
let service = use_router_service::<R>(cx)?;
cx.render(rsx! {
a {
href: format_args!("{}", props.to.to_string()),
href: format_args!("{}", (props.href)(&props.to)),
onclick: move |_| service.push_route(props.to.clone()),
{&props.children},
}
-25
View File
@@ -1,31 +1,6 @@
use wasm_bindgen::JsCast;
use web_sys::window;
pub fn fetch_base_url() -> Option<String> {
match window()
.unwrap()
.document()
.unwrap()
.query_selector("base[href]")
{
Ok(Some(base)) => {
let base = JsCast::unchecked_into::<web_sys::HtmlBaseElement>(base).href();
let url = web_sys::Url::new(&base).unwrap();
let base = url.pathname();
let base = if base != "/" {
strip_slash_suffix(&base)
} else {
return None;
};
Some(base.to_string())
}
_ => None,
}
}
pub(crate) fn strip_slash_suffix(path: &str) -> &str {
path.strip_suffix('/').unwrap_or(path)
}