From bc94387213bd7f3d6daac55218911000e9ae5304 Mon Sep 17 00:00:00 2001 From: Bodil Stokke Date: Sat, 17 Nov 2018 21:49:45 +0000 Subject: [PATCH] Toplevel docs. --- macros/src/lib.rs | 86 +------------------ typed-html/src/lib.rs | 191 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 192 insertions(+), 85 deletions(-) diff --git a/macros/src/lib.rs b/macros/src/lib.rs index adceca7..5330d09 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -20,91 +20,9 @@ mod parser; /// Construct a DOM tree. /// -/// # Syntax +/// See the crate documentation for [`typed_html`][typed_html]. /// -/// This macro largely follows [JSX] syntax, but with some differences: -/// -/// * Text nodes must be quoted, because there's only so much Rust's tokeniser -/// can handle outside string literals. So, instead of `

Hello

`, you -/// need to write `

"Hello"

`. (The parser will throw an error asking you -/// to do this if you forget.) -/// * Element attributes will accept simple Rust expressions, but the parser has -/// its limits, as it's not a full Rust parser. You can use literals, -/// variables, dotted properties and single function or method calls. If you -/// use something the parser isn't currently capable of handling, it will -/// complain. You can put braces or parentheses around the expression if the -/// parser doesn't understand it. You can use any Rust code inside a brace or -/// parenthesis block. -/// -/// # Valid HTML5 -/// -/// The macro will only accept valid HTML5 tags, with no tags or attributes -/// marked experimental or obsolete. If it won't accept something you want it to -/// accept, we can discuss it over a pull request (experimental tags and -/// attributes, in particular, are mostly omitted just for brevity, and you're -/// welcome to implement them). -/// -/// The structure validation is simplistic by necessity, as it defers to the -/// type system: a few elements will have one or more required children, and any -/// element which accepts children will have a restriction on the type of the -/// children, usually a broad group as defined by the HTML spec. Many elements -/// have restrictions on children of children, or require a particular ordering -/// of optional elements, which isn't currently validated. -/// -/// # Attribute Values -/// -/// Brace blocks in the attribute value position should return the expected type -/// for the attribute. The type checker will complain if you return an -/// unsupported type. You can also use literals or a few simple Rust expressions -/// as attribute values (see the Syntax section above). -/// -/// The `html!` macro will add an `.into()` call to the value expression, so -/// that you can use any type that has an `Into` trait defined for the actual -/// attribute type `A`. -/// -/// As a special case, if you use a string literal, the macro will instead use -/// the `FromStr` trait to try and parse the string literal into the expected -/// type. This is extremely useful for eg. CSS classes, letting you type -/// `class="css-class-1 css-class-2"` instead of going to the trouble of -/// constructing a `SpacedSet`. The big caveat for this: currently, the -/// macro is not able to validate the string at compile time, and the conversion -/// will panic at runtime if the string is invalid. -/// -/// ## Example -/// -/// ```no_compile -/// let classList: SpacedSet = ["foo", "bar", "baz"].into(); -/// html!( -///
// parses a string literal -///
// uses From<[&str, &str, &str]> -///
// uses a variable in scope -///
-/// ) -/// ``` -/// -/// # Generated Nodes -/// -/// Brace blocks in the child node position are expected to return an -/// `IntoIterator` of `DOMTree`s. You can return single elements or text nodes, -/// as they both implement `IntoIterator` for themselves. The macro will consume -/// this iterator at runtime and insert the generated nodes as children in the -/// expected position. -/// -/// ## Example -/// -/// ```no_compile -/// html!( -///
    -/// { (1..=5).map(|i| html!( -///
  • { text!("{}", i) }
  • -/// )) } -///
-/// ) -/// ``` -/// -/// [JSX]: https://reactjs.org/docs/introducing-jsx.html +/// [typed_html]: ../typed_html/index.html #[proc_macro] pub fn html(input: TokenStream) -> TokenStream { let stream = lexer::unroll_stream(input, false); diff --git a/typed-html/src/lib.rs b/typed-html/src/lib.rs index 6c92cc5..7fd42d3 100644 --- a/typed-html/src/lib.rs +++ b/typed-html/src/lib.rs @@ -1,4 +1,193 @@ -#![feature(try_from)] +//! # Typed HTML +//! +//! This crate provides the `html!` macro for building HTML documents inside +//! your Rust code using roughly [JSX] compatible syntax. +//! +//! # Nightly Warning! +//! +//! This crate currently needs nightly rustc, and in order to use it you'll need +//! to add `#![feature(proc_macro_hygiene)]` to the top of your crate. The +//! compiler will tell you to do this if you forget. When this feature +//! stabilises, the crate should work on stable rustc without issues. +//! +//! # Quick Preview +//! +//! ``` +//! # #![feature(proc_macro_hygiene)] +//! # use typed_html::{html, for_events}; +//! # use typed_html::dom::{DOMTree, VNode}; +//! # use typed_html::types::Metadata; +//! # fn main() { +//! let mut doc: DOMTree = html!( +//! +//! +//! "Hello Kitty" +//! +//! +//! +//!

"Hello Kitty"

+//!

+//! "She is not a cat. She is a human girl." +//!

+//! { (0..3).map(|_| html!( +//!

+//! "Her name is Kitty White." +//!

+//! )) } +//!

+//! "We still don't know how she eats." +//!

+//! +//! +//! ); +//! let doc_str = doc.to_string(); +//! # } +//! ``` +//! +//! # Syntax +//! +//! This macro largely follows [JSX] syntax, but with some differences: +//! +//! * Text nodes must be quoted, because there's only so much Rust's tokeniser +//! can handle outside string literals. So, instead of `

Hello

`, you +//! need to write `

"Hello"

`. (The parser will throw an error asking you +//! to do this if you forget.) +//! * Element attributes will accept simple Rust expressions, but the parser has +//! its limits, as it's not a full Rust parser. You can use literals, +//! variables, dotted properties and single function or method calls. If you +//! use something the parser isn't currently capable of handling, it will +//! complain. You can put braces or parentheses around the expression if the +//! parser doesn't understand it. You can use any Rust code inside a brace or +//! parenthesis block. +//! +//! # Valid HTML5 +//! +//! The macro will only accept valid HTML5 tags, with no tags or attributes +//! marked experimental or obsolete. If it won't accept something you want it to +//! accept, we can discuss it over a pull request (experimental tags and +//! attributes, in particular, are mostly omitted just for brevity, and you're +//! welcome to implement them). +//! +//! The structure validation is simplistic by necessity, as it defers to the +//! type system: a few elements will have one or more required children, and any +//! element which accepts children will have a restriction on the type of the +//! children, usually a broad group as defined by the HTML spec. Many elements +//! have restrictions on children of children, or require a particular ordering +//! of optional elements, which isn't currently validated. +//! +//! # Attribute Values +//! +//! Brace blocks in the attribute value position should return the expected type +//! for the attribute. The type checker will complain if you return an +//! unsupported type. You can also use literals or a few simple Rust expressions +//! as attribute values (see the Syntax section above). +//! +//! The `html!` macro will add an [`.into()`][Into::into] call to the value +//! expression, so that you can use any type that has an [`Into
`][Into] trait +//! defined for the actual attribute type `A`. +//! +//! As a special case, if you use a string literal, the macro will instead use +//! the [`FromStr`][FromStr] trait to try and parse the string literal into +//! the expected type. This is extremely useful for eg. CSS classes, letting you +//! type `class="css-class-1 css-class-2"` instead of going to the trouble of +//! constructing a [`SpacedSet`][SpacedSet]. The big caveat for this: +//! currently, the macro is not able to validate the string at compile time, and +//! the conversion will panic at runtime if the string is invalid. +//! +//! ## Example +//! +//! ``` +//! # #![feature(proc_macro_hygiene)] +//! # use typed_html::html; +//! # use typed_html::dom::DOMTree; +//! # use typed_html::types::{Class, SpacedSet}; +//! # fn main() { +//! let classList: SpacedSet = ["foo", "bar", "baz"].into(); +//! # let doc: DOMTree = +//! html!( +//!
+//!
// parses a string literal +//!
// uses From<[&str, &str, &str]> +//!
// uses a variable in scope +//!
+//!
+//! ) +//! # ;} +//! ``` +//! +//! # Generated Nodes +//! +//! Brace blocks in the child node position are expected to return an +//! [`IntoIterator`][IntoIterator] of [`DOMTree`][DOMTree]s. You can return +//! single elements or text nodes, as they both implement `IntoIterator` for +//! themselves. The macro will consume this iterator at runtime and insert the +//! generated nodes as children in the expected position. +//! +//! ## Example +//! +//! ``` +//! # #![feature(proc_macro_hygiene)] +//! # use typed_html::{html, text}; +//! # use typed_html::dom::DOMTree; +//! # fn main() { +//! # let doc: DOMTree = +//! html!( +//!
    +//! { (1..=5).map(|i| html!( +//!
  • { text!("{}", i) }
  • +//! )) } +//!
+//! ) +//! # ;} +//! ``` +//! +//! # Rendering +//! +//! You have two options for actually producing something useful from the DOM +//! tree that comes out of the macro. +//! +//! ## Render to a string +//! +//! The DOM tree data structure implements [`Display`][Display], so you can call +//! [`to_string()`][to_string] on it to render it to a [`String`][String]. If +//! you plan to do this, the type of the tree should be +//! [`DOMTree`][DOMTree] to ensure you're not using any event handlers +//! that can't be printed. +//! +//! ``` +//! # #![feature(proc_macro_hygiene)] +//! # use typed_html::html; +//! # use typed_html::dom::DOMTree; +//! # fn main() { +//! let doc: DOMTree = html!( +//!

"Hello Kitty"

+//! ); +//! let doc_str = doc.to_string(); +//! assert_eq!("

Hello Kitty

", doc_str); +//! # } +//! ``` +//! +//! ## Render to a virtual DOM +//! +//! The DOM tree structure also implements a method called `vnode()`, which +//! renders the tree to a tree of [`Node`][Node]s, which is a mirror of the +//! generated tree with every attribute value rendered into `String`s. You can +//! walk this virtual DOM tree and use it to build an actual DOM tree with +//! `stdweb` or pass it on to your favourite virtual DOM system. +//! +//! [JSX]: https://reactjs.org/docs/introducing-jsx.html +//! [Display]: https://doc.rust-lang.org/std/fmt/trait.Display.html +//! [String]: https://doc.rust-lang.org/std/string/struct.String.html +//! [to_string]: https://doc.rust-lang.org/std/string/trait.ToString.html#tymethod.to_string +//! [Node]: dom/trait.Node.html +//! [FromStr]: https://doc.rust-lang.org/std/str/trait.FromStr.html +//! [SpacedSet]: types/struct.SpacedSet.html +//! [IntoIterator]: https://doc.rust-lang.org/std/iter/trait.IntoIterator.html +//! [Into]: https://doc.rust-lang.org/std/convert/trait.Into.html +//! [Into::into]: https://doc.rust-lang.org/std/convert/trait.Into.html#method.into +//! [DOMTree]: dom/type.DOMTree.html #[macro_use] extern crate strum_macros;