Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preserve spacing around text nodes and braces #97

Merged
merged 15 commits into from
Mar 7, 2019
16 changes: 8 additions & 8 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ jobs:
keys:
# Checksum ensures that when we update versions for our `html-macro` dependencies we clear our cache, otherwise
# compiletest-rs can error when the target directory has multiple versions of a crate.
- v4-cargo-cache-test-{{ arch }}-{{ .Branch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
- v4-cargo-cache-test-{{ arch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
- v5-cargo-cache-test-{{ arch }}-{{ .Branch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
- v5-cargo-cache-test-{{ arch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}

# Install nightly & wasm
- run:
Expand Down Expand Up @@ -65,12 +65,12 @@ jobs:

# Save cache
- save_cache:
key: v4-cargo-cache-test-{{ arch }}-{{ .Branch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
key: v5-cargo-cache-test-{{ arch }}-{{ .Branch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
paths:
- target
- /usr/local/cargo
- save_cache:
key: v4-cargo-cache-test-{{ arch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
key: v5-cargo-cache-test-{{ arch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
paths:
- target
- /usr/local/cargo
Expand All @@ -84,8 +84,8 @@ jobs:
# Multiple caches are used to increase the chance of a cache hit.
- restore_cache:
keys:
- v4-cargo-cache-docs-{{ arch }}-{{ .Branch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
- v4-cargo-cache-docs-{{ arch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
- v5-cargo-cache-docs-{{ arch }}-{{ .Branch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
- v5-cargo-cache-docs-{{ arch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}

# Install nightly
- run:
Expand Down Expand Up @@ -120,12 +120,12 @@ jobs:

# Save cache
- save_cache:
key: v4-cargo-cache-docs-{{ arch }}-{{ .Branch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
key: v5-cargo-cache-docs-{{ arch }}-{{ .Branch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
paths:
- target
- /usr/local/cargo
- save_cache:
key: v4-cargo-cache-docs-{{ arch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
key: v5-cargo-cache-docs-{{ arch }}-{{ checksum "./crates/html-macro/Cargo.toml" }}-{{ checksum "./crates/virtual-dom-rs/Cargo.toml" }}
paths:
- target
- /usr/local/cargo
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,11 @@ pub fn start() {

let mut dom_updater = DomUpdater::new_append_to_mount(start_view, &body);

let greetings = "Hello, World!";

let end_view = html! {
<div class="big blue">
<strong>Hello, World!</strong>
<strong>{ greetings }</strong>

<button
class=MY_COMPONENT_CSS
Expand All @@ -119,7 +121,6 @@ pub fn start() {
</div>
};


dom_updater.update(end_view);
}

Expand Down
1 change: 1 addition & 0 deletions book/src/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- [Writing html!](./html-macro/README.md)
- [Writing html!](./html-macro/html-macro.md)
- [Compile Time Errors](./html-macro/compile-time-errors.md)
- [Working with Text](./html-macro/text/README.md)
- [Virtual DOM](./virtual-dom/README.md)
- [Unit Testing your Views](./virtual-dom/unit-testing-views.md)
- [Server Side Rendering (SSR)](./views/server-side-rendering/README.md)
Expand Down
49 changes: 49 additions & 0 deletions book/src/html-macro/text/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Working with Text

One of the most popular types of nodes in the DOM is the [Text] node, and the `html! macro
focuses heavily on making them as easy to create as possible.

You can just type unquoted text into the `html!` macro and neighboring text will get combined into a single `Text` node, much
like the way that web browsers handle text from html documents.

```rust
fn main () {
let interpolated_text = "interpolate text variables.";

let example = html! {
<div>
Text can be typed directly into your HTML.
<div>Or you can also {interpolated_text}</div>
</div>
};
}
```

## Preserving Space Between Blocks

You should always get the same spacing (or lack there of) between text and other elements as you would
if you were working in a regular old `.html` file.

We'll preserve newline characters so that `white-space: pre-wrap` etc will work as expected.

When it comes to interpolated variables, we base spacing on the spacing outside of the braces, not the
inside.

Let's illustrate:

```rust
fn main () {
let text = "hello";

html! { <div>{ hello }</div> }; // <div>hello</div>
html! { <div>{hello}</div> }; // <div>hello</div>

html! { <div> { hello } </div> }; // <div> hello </div>
html! { <div> {hello} </div> }; // <div> hello </div>

html! { <div>{hello} </div> }; // <div>hello </div>
html! { <div> {hello}</div> }; // <div> hello</div>
}
```

[Text]: https://developer.mozilla.org/en-US/docs/Web/API/Text
135 changes: 23 additions & 112 deletions crates/html-macro-test/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#![feature(proc_macro_hygiene)]
#![cfg(test)]

use html_macro::html;
use std::collections::HashMap;
use virtual_node::{IterableNodes, VElement, VirtualNode};

mod text;

struct HtmlMacroTest<'a> {
desc: &'a str,
generated: VirtualNode,
Expand All @@ -14,7 +15,7 @@ struct HtmlMacroTest<'a> {
impl<'a> HtmlMacroTest<'a> {
/// Ensure that the generated and the expected virtual node are equal.
fn test(self) {
assert_eq!(self.generated, self.expected, "{}", self.desc);
assert_eq!(self.expected, self.generated, "{}", self.desc);
}
}

Expand Down Expand Up @@ -115,7 +116,13 @@ fn nested_macro() {
let child_2 = html! { <b></b> };

let mut expected = VElement::new("div");
expected.children = vec![VirtualNode::element("span"), VirtualNode::element("b")];
expected.children = vec![
VirtualNode::text(" "),
VirtualNode::element("span"),
VirtualNode::text(" "),
VirtualNode::element("b"),
VirtualNode::text(" "),
];

HtmlMacroTest {
desc: "Nested macros",
Expand Down Expand Up @@ -152,8 +159,9 @@ fn text_next_to_block() {

let mut expected = VElement::new("div");
expected.children = vec![
VirtualNode::text("A bit of text"),
VirtualNode::text(" A bit of text "),
VirtualNode::element("ul"),
VirtualNode::text(" "),
];

HtmlMacroTest {
Expand All @@ -169,37 +177,15 @@ fn text_next_to_block() {
.test();
}

/// Ensure that we maintain the correct spacing around punctuation tokens, since
/// they resolve into a separate TokenStream during parsing.
#[test]
fn punctuation_comma() {
fn punctuation_token() {
let text = "Hello, World";

HtmlMacroTest {
desc: "Comma",
generated: html! { Hello, World},
expected: VirtualNode::text(text),
}
.test()
}

#[test]
fn punctuation_exclamation() {
let text = "Hello World!";

HtmlMacroTest {
desc: "Exclamation point",
generated: html! { Hello World! },
expected: VirtualNode::text(text),
}
.test()
}

#[test]
fn punctuation_period() {
let text = "Hello.";

HtmlMacroTest {
desc: "Period",
generated: html! { Hello. },
desc: "Punctuation token spacing",
generated: html! { Hello, World },
expected: VirtualNode::text(text),
}
.test()
Expand All @@ -210,7 +196,12 @@ fn vec_of_nodes() {
let children = vec![html! { <div> </div>}, html! { <strong> </strong>}];

let mut expected = VElement::new("div");
expected.children = vec![VirtualNode::element("div"), VirtualNode::element("strong")];
expected.children = vec![
VirtualNode::text(" "),
VirtualNode::element("div"),
VirtualNode::element("strong"),
VirtualNode::text(" "),
];

HtmlMacroTest {
desc: "Vec of nodes",
Expand All @@ -220,92 +211,12 @@ fn vec_of_nodes() {
.test();
}

#[test]
fn text_root_node() {
HtmlMacroTest {
desc: "Text as root node",
generated: html! { some text },
expected: VirtualNode::text("some text"),
}
.test()
}

/// Just make sure that this compiles since type is a keyword
#[test]
fn type_attribute() {
html! { <link rel="stylesheet" type="text/css" href="/app.css" /> };
}

#[test]
fn text_variable_root() {
let text = "hello world";

HtmlMacroTest {
desc: "Text variable root",
generated: html! { { text } },
expected: VirtualNode::text("hello world"),
}
.test()
}

#[test]
fn text_variable_child() {
let text = "world";

HtmlMacroTest {
desc: "Text variable child",
generated: html! { <div> { text } </div> },
expected: html! { <div> world </div> },
}
.test()
}

//#[test]
//fn text_space_after_start_tag () {
// assert_eq!(
// &html! { <div> Hello</div> }.to_string(),
// "<div> Hello</div>"
// )
//}
//
//#[test]
//fn text_space_beore_end_tag () {
// assert_eq!(
// &html! { <div>Hello </div> }.to_string(),
// "<div>Hello </div>"
// )
//}
//
//#[test]
//fn text_space_before_block() {
// let text = "Hello";
//
// assert_eq!(
// &html! { <div> {text}</div> }.to_string(),
// "<div>Hello </div>"
// )
//}
//
//#[test]
//fn text_space_after_block() {
// let text = "Hello";
//
// assert_eq!(
// &html! { <div>{text} </div> }.to_string(),
// "<div> Hello</div>"
// )
//}
//
//#[test]
//fn text_space_in_block_ignored() {
// let text = "Hello";
//
// assert_eq!(
// &html! { <div>{ text }</div> }.to_string(),
// "<div>Hello</div>"
// )
//}

// Verify that all of our self closing tags work as both.
// Self closing tags can be written as either <tag> and <tag />
#[test]
Expand Down
Loading