Skip to content

Commit

Permalink
Create generic html struct
Browse files Browse the repository at this point in the history
  • Loading branch information
matthunz committed Nov 25, 2023
1 parent 6464d28 commit 1ffcd2d
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 52 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ members = [

[features]
html = ["dep:js-sys", "dep:wasm-bindgen", "dep:web-sys"]
full = ["html"]
web = ["html"]
full = ["web"]

[dependencies]
futures = "0.3.29"
Expand Down
74 changes: 27 additions & 47 deletions src/html/mod.rs
Original file line number Diff line number Diff line change
@@ -1,64 +1,44 @@
use std::{cell::RefCell, rc::Rc};
use web_sys::{Document, HtmlElement};
use crate::{Composable, IntoComposable};
use std::borrow::Cow;

use crate::{Composable, Composition, IntoComposable};

thread_local! {
static HTML_CONTEXT: RefCell<Option<HtmlContext>> = RefCell::default();
pub trait Platform: Sized {
fn html(&mut self, html: &mut Builder) -> impl IntoComposable;
}

struct Inner {
document: Document,
body: HtmlElement,
#[derive(Default, PartialEq, Eq)]
pub struct Builder {
pub attrs: Vec<(Cow<'static, str>, Cow<'static, str>)>,
}

#[derive(Clone)]
pub struct HtmlContext {
inner: Rc<RefCell<Inner>>,
#[derive(PartialEq, Eq)]
pub struct Html<P> {
platform: P,
builder: Builder,
}

impl HtmlContext {
pub fn new() -> Self {
let window = web_sys::window().unwrap();
let document = window.document().unwrap();
let body = document.body().unwrap();
impl<P> Html<P> {
pub fn new(platform: P) -> Self {
Self {
inner: Rc::new(RefCell::new(Inner { document, body })),
platform,
builder: Builder::default(),
}
}

pub fn current() -> Self {
HTML_CONTEXT
.try_with(|cx| cx.borrow().as_ref().unwrap().clone())
.unwrap()
}

pub fn enter(self) {
HTML_CONTEXT
.try_with(|cx| *cx.borrow_mut() = Some(self))
.unwrap()
pub fn attr(
mut self,
name: impl Into<Cow<'static, str>>,
value: impl Into<Cow<'static, str>>,
) -> Self {
self.builder.attrs.push((name.into(), value.into()));
self
}
}

#[derive(PartialEq, Eq)]
pub struct Html {}

impl Composable for Html {
fn compose(&mut self) -> impl IntoComposable {
let cx = HtmlContext::current();
let inner = cx.inner.borrow_mut();
let element = inner.document.create_element("div").unwrap();
inner.body.append_child(&element).unwrap();
}
}

pub fn run<C>(content: fn() -> C)
impl<P> Composable for Html<P>
where
C: IntoComposable + 'static,
P: Platform + PartialEq + 'static,
{
let cx = HtmlContext::new();
cx.enter();

let mut composition = Composition::new(content);
composition.build()
fn compose(&mut self) -> impl IntoComposable {
self.platform.html(&mut self.builder)
}
}
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ pub use use_state::{use_state, UseState};
#[cfg(feature = "html")]
pub mod html;

#[cfg(feature = "web")]
pub mod web;

#[derive(Default)]
struct GlobalContext {
values: SlotMap<DefaultKey, Rc<RefCell<dyn Any>>>,
Expand Down
76 changes: 76 additions & 0 deletions src/web/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use std::{cell::RefCell, rc::Rc};
use web_sys::{Document, HtmlElement};

use crate::{
html::{Builder, Html, Platform},
Composition, IntoComposable,
};

thread_local! {
static HTML_CONTEXT: RefCell<Option<WebContext>> = RefCell::default();
}

struct Inner {
document: Document,
body: HtmlElement,
}

#[derive(Clone)]
pub struct WebContext {
inner: Rc<RefCell<Inner>>,
}

impl WebContext {
pub fn new() -> Self {
let window = web_sys::window().unwrap();
let document = window.document().unwrap();
let body = document.body().unwrap();
Self {
inner: Rc::new(RefCell::new(Inner { document, body })),
}
}

pub fn current() -> Self {
HTML_CONTEXT
.try_with(|cx| cx.borrow().as_ref().unwrap().clone())
.unwrap()
}

pub fn enter(self) {
HTML_CONTEXT
.try_with(|cx| *cx.borrow_mut() = Some(self))
.unwrap()
}
}

pub fn html() -> Html<WebHtml> {
Html::new(WebHtml {})
}

#[derive(PartialEq, Eq)]
pub struct WebHtml {}

impl Platform for WebHtml {
fn html(&mut self, html: &mut Builder) -> impl IntoComposable {
let cx = WebContext::current();
let inner = cx.inner.borrow_mut();
let element = inner.document.create_element("div").unwrap();

for (name, value) in &html.attrs {
element.set_attribute(&name, &value).unwrap();
}

inner.body.append_child(&element).unwrap();
}
}

pub fn run<C>(content: fn() -> C)
where
C: IntoComposable + 'static,
{
let cx = WebContext::new();
cx.enter();

let mut composition = Composition::new(content);
composition.build()
}
2 changes: 1 addition & 1 deletion web_examples/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ version = "0.1.0"
edition = "2021"

[dependencies]
concoct = { path = "../", features = ["html"] }
concoct = { path = "../", features = ["web"] }
6 changes: 3 additions & 3 deletions web_examples/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use concoct::{html::Html, IntoComposable};
use concoct::{web::html, IntoComposable};

fn app() -> impl IntoComposable {
Html {}
html().attr("class", "main")
}

fn main() {
concoct::html::run(app)
concoct::web::run(app)
}

0 comments on commit 1ffcd2d

Please sign in to comment.