started porting router to #[component]

This commit is contained in:
Jose Quesada 2022-12-15 12:31:53 -06:00
parent 422233eecf
commit ce9aec2520
2 changed files with 45 additions and 71 deletions

View file

@ -5,62 +5,43 @@ use typed_builder::TypedBuilder;
use wasm_bindgen::JsCast;
use wasm_bindgen_futures::JsFuture;
/// Properties that can be passed to the [Form] component, which is an HTML
/// [`form`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form)
/// progressively enhanced to use client-side routing.
#[derive(TypedBuilder)]
pub struct FormProps<A>
where
A: ToHref + 'static,
{
/// An HTML [`form`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form) progressively
/// enhanced to use client-side routing.
#[component]
pub fn Form<A>(
cx: Scope,
/// [`method`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#attr-method)
/// is the HTTP method to submit the form with (`get` or `post`).
#[builder(default, setter(strip_option))]
pub method: Option<&'static str>,
#[prop(optional)]
method: Option<&'static str>,
/// [`action`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#attr-action)
/// is the URL that processes the form submission. Takes a [String], [&str], or a reactive
/// function that returns a [String].
pub action: A,
action: A,
/// [`enctype`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#attr-enctype)
/// is the MIME type of the form submission if `method` is `post`.
#[builder(default, setter(strip_option))]
pub enctype: Option<String>,
#[prop(optional)]
enctype: Option<String>,
/// A signal that will be incremented whenever the form is submitted with `post`. This can useful
/// for reactively updating a [Resource] or another signal whenever the form has been submitted.
#[builder(default, setter(strip_option))]
pub version: Option<RwSignal<usize>>,
#[prop(optional)]
version: Option<RwSignal<usize>>,
/// A signal that will be set if the form submission ends in an error.
#[builder(default, setter(strip_option))]
pub error: Option<RwSignal<Option<Box<dyn Error>>>>,
#[prop(optional)]
error: Option<RwSignal<Option<Box<dyn Error>>>>,
/// A callback will be called with the [FormData](web_sys::FormData) when the form is submitted.
#[builder(default, setter(strip_option))]
pub on_form_data: Option<Rc<dyn Fn(&web_sys::FormData)>>,
#[prop(optional)]
on_form_data: Option<Rc<dyn Fn(&web_sys::FormData)>>,
/// A callback will be called with the [Response](web_sys::Response) the server sends in response
/// to a form submission.
#[builder(default, setter(strip_option))]
pub on_response: Option<Rc<dyn Fn(&web_sys::Response)>>,
#[prop(optional)]
on_response: Option<Rc<dyn Fn(&web_sys::Response)>>,
/// Component children; should include the HTML of the form elements.
pub children: Box<dyn Fn(Scope) -> Fragment>,
}
/// An HTML [`form`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form) progressively
/// enhanced to use client-side routing.
#[allow(non_snake_case)]
pub fn Form<A>(cx: Scope, props: FormProps<A>) -> impl IntoView
children: Box<dyn Fn(Scope) -> Fragment>,
) -> impl IntoView
where
A: ToHref + 'static,
{
let FormProps {
method,
action,
enctype,
children,
version,
error,
on_form_data,
on_response,
} = props;
let action_version = version;
let action = use_resolved_path(cx, move || action.to_href()());
@ -131,18 +112,16 @@ where
let method = method.unwrap_or("get");
Component::new("Form", move |cx| {
view! { cx,
<form
method=method
action=move || action.get()
enctype=enctype
on:submit=on_submit
>
{move || children(cx)}
</form>
}
})
view! { cx,
<form
method=method
action=move || action.get()
enctype=enctype
on:submit=on_submit
>
{move || children(cx)}
</form>
}
}
/// Properties that can be passed to the [ActionForm] component, which

View file

@ -19,32 +19,27 @@ use crate::{
#[cfg(not(feature = "ssr"))]
use crate::{unescape, Url};
/// Props for the [Router] component, which sets up client-side and server-side routing.
#[derive(TypedBuilder)]
pub struct RouterProps {
/// Provides for client-side and server-side routing. This should usually be somewhere near
/// the root of the application.
#[component]
pub fn Router(
cx: Scope,
/// The base URL for the router. Defaults to "".
#[builder(default, setter(strip_option))]
pub base: Option<&'static str>,
#[builder(default, setter(strip_option))]
#[prop(optional)]
base: Option<&'static str>,
/// A fallback that should be shown if no route is matched.
pub fallback: Option<fn() -> View>,
#[prop(optional)]
fallback: Option<fn() -> View>,
/// The `<Router/>` should usually wrap your whole page. It can contain
/// any elements, and should include a [Routes](crate::Routes) component somewhere
/// to define and display [Route](crate::Route)s.
pub children: Box<dyn Fn(Scope) -> Fragment>,
}
children: Box<dyn Fn(Scope) -> Fragment>,
) -> impl IntoView {
// create a new RouterContext and provide it to every component beneath the router
let router = RouterContext::new(cx, base, fallback);
provide_context(cx, router);
/// Provides for client-side and server-side routing. This should usually be somewhere near
/// the root of the application.
#[allow(non_snake_case)]
pub fn Router(cx: Scope, props: RouterProps) -> impl IntoView {
Component::new("Router", move |cx| {
// create a new RouterContext and provide it to every component beneath the router
let router = RouterContext::new(cx, props.base, props.fallback);
provide_context(cx, router);
move || (props.children)(cx)
})
move || children(cx)
}
/// Context type that contains information about the current router state.