typed-html

Type checked JSX for Rust

  • 所有者: bodil/typed-html
  • 平台:
  • 許可證: Mozilla Public License 2.0
  • 分類:
  • 主題:
  • 喜歡:
    0
      比較:

Github星跟蹤圖

Build Status

typed-html

This crate provides the html! macro for building HTML documents inside your
Rust code using roughly JSX compatible syntax.

Quick Preview

let mut doc: DOMTree<String> = html!(
    <html>
        <head>
            <title>"Hello Kitty"</title>
            <meta name=Metadata::Author content="Not Sanrio Co., Ltd"/>
        </head>
        <body>
            <h1>"Hello Kitty"</h1>
            <p class="official">
                "She is not a cat. She is a human girl."
            </p>
            { (0..3).map(, _, html!(
                <p class="emphasis">
                    "Her name is Kitty White."
                </p>
            )) }
            <p class="citation-needed">
                "We still don't know how she eats."
            </p>
        </body>
    </html>
);
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 <p>Hello</p>, you need to
    write <p>"Hello"</p>. (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, type constructors 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<A> 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<A> 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<Class>. 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

let classList: SpacedSet<Class> = ["foo", "bar", "baz"].into();
html!(
    <div>
        <div class="foo bar baz" />         // parses a string literal
        <div class=["foo", "bar", "baz"] /> // uses From<[&str, &str, &str]>
        <div class=classList />             // uses a variable in scope
        <div class={                        // evaluates a code block
            SpacedSet::from(["foo", "bar", "baz"])
        } />
    </div>
)

Generated Nodes

Brace blocks in the child node position are expected to return an
IntoIterator of DOMTrees. 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

html!(
    <ul>
        { (1..=5).map(, i, html!(
            <li>{ text!("{}", i) }</li>
        )) }
    </ul>
)

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, so you can call
to_string() on it to render it to a String. If you
plan to do this, the type of the tree should be DOMTree<String> to
ensure you're not using any event handlers that can't be printed.

let doc: DOMTree<String> = html!(
    <p>"Hello Kitty"</p>
);
let doc_str = doc.to_string();
assert_eq!("<p>Hello Kitty</p>", 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 Nodes, which is a mirror of the generated tree
with every attribute value rendered into Strings. 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.

Licence

Copyright 2018 Bodil Stokke

This software is subject to the terms of the Mozilla Public License, v. 2.0. If
a copy of the MPL was not distributed with this file, You can obtain one at
http://mozilla.org/MPL/2.0/.

Code of Conduct

Please note that this project is released with a Contributor Code of
Conduct
. By participating in this project you agree to abide by its terms.

主要指標

概覽
名稱與所有者bodil/typed-html
主編程語言Rust
編程語言Rust (語言數: 2)
平台
許可證Mozilla Public License 2.0
所有者活动
創建於2018-10-26 21:03:30
推送於2023-03-13 02:04:35
最后一次提交2022-01-27 19:34:04
發布數5
最新版本名稱0.2.2 (發布於 2020-02-07 17:43:56)
第一版名稱0.1.0 (發布於 2018-11-17 22:41:26)
用户参与
星數1.9k
關注者數26
派生數62
提交數132
已啟用問題?
問題數43
打開的問題數22
拉請求數29
打開的拉請求數5
關閉的拉請求數55
项目设置
已啟用Wiki?
已存檔?
是復刻?
已鎖定?
是鏡像?
是私有?