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

Extract Classes to a separate macro #1601

Merged
merged 109 commits into from
Nov 25, 2020
Merged
Changes from all commits
Commits
Show all changes
109 commits
Select commit Hold shift + click to select a range
873935a
Initial commit
cecton Oct 4, 2020
d8c480c
Add feature flag for now
cecton Oct 4, 2020
3234c41
WIP
cecton Oct 4, 2020
46c0978
Add macro classes!()
cecton Oct 4, 2020
d25c6d6
WIP
cecton Oct 4, 2020
cb54f9a
rustfmt
cecton Oct 4, 2020
8957f25
WIP
cecton Oct 4, 2020
8f2c684
CLEANUP
cecton Oct 4, 2020
5f0e487
CLEANUP
cecton Oct 4, 2020
81c60ac
CLEANUP
cecton Oct 4, 2020
3ca20a8
rustfmt
cecton Oct 4, 2020
57f734a
WIP
cecton Oct 4, 2020
4651812
WIP
cecton Oct 4, 2020
83ee4b3
WIP
cecton Oct 4, 2020
df82683
WIP
cecton Oct 4, 2020
e2717ae
Not sure why there is a prelude.rs file here...
cecton Oct 5, 2020
0ae0503
WIP
cecton Oct 5, 2020
a89d64f
CLEANUP
cecton Oct 5, 2020
4ac2543
CLEANUP
cecton Oct 5, 2020
5c97979
WIP
cecton Oct 5, 2020
79861d4
WIP
cecton Oct 5, 2020
c3a52c8
Revert example changes
cecton Oct 5, 2020
a34fdb6
WIP
cecton Oct 5, 2020
dbe83ef
CLEANUP
cecton Oct 5, 2020
243925e
WIP
cecton Oct 5, 2020
1bc03f2
CLEANUP
cecton Oct 5, 2020
f0da2e4
CLEANUP
cecton Oct 5, 2020
fa8c059
CLEANUP
cecton Oct 5, 2020
e6a5926
CLEANUP
cecton Oct 5, 2020
c3bf0b2
Revert back to e2717ae6281691f9563079ef07b56b24b6431ff1
cecton Oct 9, 2020
3a552b1
Put back original class behavior in html!
cecton Oct 9, 2020
27ba4e2
Store span and use quote_spanned!
cecton Oct 10, 2020
3916dca
Deprecation warning
cecton Oct 10, 2020
a032d2b
Better error message
cecton Oct 10, 2020
83c580a
Merge commit 724ac1d4813b8e74b94602c0875d6f18ff81ad3e (no conflict)
cecton Oct 24, 2020
8612538
Merge commit fa2ab5abe78def557733081d9c4f34e626e1d338 (conflicts)
cecton Oct 24, 2020
9cb2d19
Merge commit 8052e56232376cc54897305e97518a0d65371b59 (no conflict)
cecton Oct 24, 2020
d0c4d8f
cargo fmt & fix conflict leftover oops
cecton Oct 24, 2020
9e0553d
Fix clippy: missing import
cecton Oct 24, 2020
18b6389
What have I done
cecton Oct 24, 2020
e4a70a5
Use Token! instead of Comma
cecton Nov 8, 2020
823befe
Apply suggestion
cecton Nov 8, 2020
808ec09
Renamed HtmlClasses to Classes
cecton Nov 8, 2020
af582f4
Remove clippy attribute & add dedicated tests
cecton Nov 8, 2020
ea02f37
Remove span from Single variant
cecton Nov 8, 2020
4adbf6b
Spacing stuff with quote_spanned!
cecton Nov 8, 2020
cb94ee8
Removed "use" and use path to Classes
cecton Nov 8, 2020
9092665
Some doc
cecton Nov 8, 2020
e439e6e
Replace Vec<Expr> with ExprTuple
cecton Nov 8, 2020
28f73bf
rustfmt
cecton Nov 8, 2020
3e9750a
Move classes to its own module
cecton Nov 8, 2020
84d3aa4
Move tests from vtag to classes
cecton Nov 8, 2020
73f70fa
Update classes-fail.stderr
cecton Nov 8, 2020
e748001
Check for spaces in string literals
cecton Nov 8, 2020
c30ee6c
Use unchecked_push for string literals
cecton Nov 8, 2020
83b873b
Fixed tests
cecton Nov 8, 2020
b0c3558
More doc
cecton Nov 8, 2020
709003e
Tested doc in browser and make boolinator import visible
cecton Nov 8, 2020
b27365a
Improve doc a tad bit
cecton Nov 8, 2020
05b32c6
Stuff
cecton Nov 8, 2020
4fa0c70
Fix due to change with string literal
cecton Nov 8, 2020
7e1ab45
Typo
cecton Nov 8, 2020
2477620
Moved classes to html
cecton Nov 8, 2020
9144e2a
Update macro new path for Classes
cecton Nov 8, 2020
207d0aa
Test fix
cecton Nov 8, 2020
249d9f3
Example fix
cecton Nov 8, 2020
7e60fdf
Update classes-fail.stderr
cecton Nov 8, 2020
bba508f
Fixed weird error
cecton Nov 8, 2020
eb0fd83
Update yew/src/lib.rs
cecton Nov 10, 2020
7ee45f5
Update yew/Cargo.toml
cecton Nov 10, 2020
04a79a1
Update yew/src/html/classes.rs
cecton Nov 10, 2020
952e17b
Update docs/concepts/html/classes.md
cecton Nov 10, 2020
e179111
I blame GitHub
cecton Nov 10, 2020
c9e1ff9
Use syn::Result
cecton Nov 10, 2020
e7dd571
Apply suggestions
cecton Nov 10, 2020
90758d5
Update yew-macro/src/classes/mod.rs
cecton Nov 10, 2020
0ca613f
Update yew-macro/tests/macro_test.rs
cecton Nov 10, 2020
d6488eb
Replaced html! by classes!
cecton Nov 10, 2020
1609cc7
Moved classes tests
cecton Nov 10, 2020
f500883
Renamed doc title
cecton Nov 10, 2020
8fc5b88
Apply suggestion
cecton Nov 10, 2020
1281b06
Update yew-macro/src/html_tree/html_element.rs
cecton Nov 10, 2020
b90c6d5
Fixed span badly handled in macro
cecton Nov 10, 2020
ce08d7a
no implicit prelude
cecton Nov 10, 2020
11e1e5e
Update yew/src/lib.rs
cecton Nov 10, 2020
8871072
Improve documentation
cecton Nov 10, 2020
2a342c3
Yeah... OK
cecton Nov 10, 2020
4972c8f
OMG clippy
cecton Nov 10, 2020
73623ea
Please squash merge and don't keep my commit messages
cecton Nov 10, 2020
592fd16
Safety notice
cecton Nov 10, 2020
e600f0c
Change "Yew's macros" to "HTML"
cecton Nov 11, 2020
3482bf8
Unneeded closure
cecton Nov 11, 2020
2dfe09a
Boxing stuff :boxing_glove:
cecton Nov 11, 2020
002103c
Indentation issue
cecton Nov 11, 2020
f8e1e5d
Removed unneeded block & removed duplicated code
cecton Nov 11, 2020
ee491cd
Renamed "macros" to "html_macro"
cecton Nov 11, 2020
e1a6480
Better span
cecton Nov 11, 2020
c91407d
Doc: advice to use `classes!`
cecton Nov 11, 2020
42da556
Doc: fix error and remove one "and"
cecton Nov 11, 2020
7da9ea7
Removed interpolated example
cecton Nov 11, 2020
eb7b457
Remove unnecessary tests and add test for deprecated syntax
cecton Nov 11, 2020
76db907
Link to classes!
cecton Nov 11, 2020
087d1b8
Update yew-macro/tests/html_macro_test.rs
cecton Nov 11, 2020
277efd8
Renamed fail test
cecton Nov 11, 2020
e10467f
Apply suggestion
cecton Nov 11, 2020
49ab10c
WIP
cecton Nov 11, 2020
9119e6e
WIP
cecton Nov 22, 2020
5b93916
cargo make pr-flow passes locally, let's try again
cecton Nov 22, 2020
b19b0ef
Merge commit c72d990bcb77a4672cdd7bab5e46bc8bc0b63610 (no conflict)
cecton Nov 22, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/concepts/html.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
title: html!
title: HTML
sidebar_label: Introduction
description: The procedural macro for generating HTML and SVG
---
122 changes: 122 additions & 0 deletions docs/concepts/html/classes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
---
title: Classes
description: A handy macro to handle classes
---

## Classes

The struct `Classes` can be used to deal with HTML classes.

When pushing a string to the set, `Classes` ensures that there is one element
for every class even if a single string might contain multiple classes.

`Classes` can also be merged by using `Extend` (i.e.
`classes1.extend(classes2)`) or `push()` (i.e. `classes1.push(classes2)`). In
fact, anything that implements `Into<Classes>` can be used to push new classes
to the set.

The macro `classes!` is a convenient macro that creates one single `Classes`.
Its input accepts a comma separated list of expressions. The only requirement
is that every expression implements `Into<Classes>`.

<!--DOCUSAURUS_CODE_TABS-->
<!--Literal-->

```rust
html! {
<div class=classes!("container")></div>
}
```

<!--Multiple-->

```rust
html! {
<div class=classes!("class-1", "class-2")></div>
}
```

<!--String-->

```rust
let my_classes = String::from("class-1 class-2");

html! {
<div class=classes!(my_classes)></div>
}
```

<!--Optional-->

```rust
html! {
<div class=classes!(Some("class")) />
}
```

<!--Vector-->

```rust
html! {
<div class=classes!(vec!["class-1", "class-2"])></div>
}
```

<!--Array-->

```rust
let my_classes = ["class-1", "class-2"];

html! {
<div class=classes!(&my_classes)></div>
}
```

<!--END_DOCUSAURUS_CODE_TABS-->

## Components that accept classes

```rust
use boolinator::Boolinator;

#[derive(Clone, Properties)]
struct Props {
#[prop_or_default]
class: Classes,
fill: bool,
children: Children,
}

struct MyComponent {
props: Props,
}

impl Component for MyComponent {
type Properties = Props;

// ...

fn view(&self) -> Html {
let Props {
class,
fill,
children,
} = &self.props;
html! {
<div
class=classes!(
"my-container-class",
fill.as_some("my-fill-class"),
class.clone(),
)
>
{ children.clone() }
</div>
}
}
}
```

The example makes use of the [boolinator](https://crates.io/crates/boolinator)
crate to conditionally add the "my-fill-class" class based on the `fill`
boolean attribute.
47 changes: 0 additions & 47 deletions docs/concepts/html/elements.md
Original file line number Diff line number Diff line change
@@ -35,53 +35,6 @@ html! {

If the attribute is set to `None`, the attribute won't be set in the DOM.

## Classes

There are a number of convenient ways to specify classes for an element:

<!--DOCUSAURUS_CODE_TABS-->
<!--Literal-->

```rust
html! {
<div class="container"></div>
}
```

<!--Multiple-->

```rust
html! {
<div class=("class-1", "class-2")></div>
}
```

<!--Optional-->

```rust
html! {
<div class=if condition { Some("class") } else { None } />
}
```

<!--Interpolated-->

```rust
html! {
<div class=format!("{}-container", size) />
}
```

<!--Vector-->

```rust
html! {
<div class=vec!["class-1", "class-2"]></div>
}
```

<!--END_DOCUSAURUS_CODE_TABS-->

## Listeners

Listener attributes need to be passed a `Callback` which is a wrapper around a closure. How you create your callback depends on how you wish your app to react to a listener event:
10 changes: 6 additions & 4 deletions examples/crm/src/add_client.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use crate::Client;
use yew::{html, Callback, Component, ComponentLink, Html, InputData, Properties, ShouldRender};
use yew::{
classes, html, Callback, Component, ComponentLink, Html, InputData, Properties, ShouldRender,
};

#[derive(Debug)]
pub enum Msg {
@@ -74,19 +76,19 @@ impl Component for AddClientForm {
<>
<div class="names">
<input
class=("new-client", "firstname")
class=classes!("new-client", "firstname")
placeholder="First name"
value=&client.first_name
oninput=link.callback(|e: InputData| Msg::UpdateFirstName(e.value))
/>
<input
class=("new-client", "lastname")
class=classes!("new-client", "lastname")
placeholder="Last name"
value=&client.last_name
oninput=link.callback(|e: InputData| Msg::UpdateLastName(e.value))
/>
<textarea
class=("new-client", "description")
class=classes!("new-client", "description")
placeholder="Description"
value=&client.description
oninput=link.callback(|e: InputData| Msg::UpdateDescription(e.value))
4 changes: 2 additions & 2 deletions examples/futures/src/markdown.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/// Original author of this code is [Nathan Ringo](https://github.com/remexre)
/// Source: https://github.com/acmumn/mentoring/blob/master/web-client/src/view/markdown.rs
use pulldown_cmark::{Alignment, CodeBlockKind, Event, Options, Parser, Tag};
use yew::virtual_dom::{Classes, VNode, VTag, VText};
use yew::{html, Html};
use yew::virtual_dom::{VNode, VTag, VText};
use yew::{html, Classes, Html};

/// Adds a class to the VTag.
/// You can also provide multiple classes separated by ascii whitespaces.
4 changes: 2 additions & 2 deletions examples/game_of_life/src/main.rs
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ use cell::Cellule;
use rand::Rng;
use std::time::Duration;
use yew::services::interval::{IntervalService, IntervalTask};
use yew::{html, Component, ComponentLink, Html, ShouldRender};
use yew::{classes, html, Component, ComponentLink, Html, ShouldRender};

mod cell;

@@ -96,7 +96,7 @@ impl Model {
}
};
html! {
<div key=idx class=("game-cellule", cellule_status)
<div key=idx class=classes!("game-cellule", cellule_status)
onclick=self.link.callback(move |_| Msg::ToggleCellule(idx))>
</div>
}
2 changes: 1 addition & 1 deletion examples/nested_list/src/list.rs
Original file line number Diff line number Diff line change
@@ -103,7 +103,7 @@ impl Component for List {
let onmouseout = self.props.on_hover.reform(|_| Hovered::None);
html! {
<div class="list-container" onmouseout=onmouseout onmouseover=onmouseover>
<div class=("list", inactive)>
<div class=classes!("list", inactive)>
{ self.view_header() }
<div class="items">
{ self.view_items() }
2 changes: 1 addition & 1 deletion examples/router/src/components/pagination.rs
Original file line number Diff line number Diff line change
@@ -53,7 +53,7 @@ impl Pagination {

html! {
<li>
<a class=("pagination-link", is_current_class) aria-label=format!("Goto page {}", to_page) onclick=onclick>
<a class=classes!("pagination-link", is_current_class) aria-label=format!("Goto page {}", to_page) onclick=onclick>
{ to_page }
</a>
</li>
4 changes: 2 additions & 2 deletions examples/router/src/main.rs
Original file line number Diff line number Diff line change
@@ -87,7 +87,7 @@ impl Model {
<h1 class="navbar-item is-size-3">{ "Yew Blog" }</h1>

<a role="button"
class=("navbar-burger", "burger", active_class)
class=classes!("navbar-burger", "burger", active_class)
aria-label="menu" aria-expanded="false"
onclick=link.callback(|_| Msg::ToggleNavbar)
>
@@ -96,7 +96,7 @@ impl Model {
<span aria-hidden="true"></span>
</a>
</div>
<div class=("navbar-menu", active_class)>
<div class=classes!("navbar-menu", active_class)>
<div class="navbar-start">
<AppAnchor classes="navbar-item" route=AppRoute::Home>
{ "Home" }
6 changes: 3 additions & 3 deletions examples/todomvc/src/main.rs
Original file line number Diff line number Diff line change
@@ -3,8 +3,8 @@ use strum::IntoEnumIterator;
use yew::format::Json;
use yew::services::storage::{Area, StorageService};
use yew::web_sys::HtmlInputElement as InputElement;
use yew::{classes, html, Component, ComponentLink, Html, InputData, NodeRef, ShouldRender};
use yew::{events::KeyboardEvent, Classes};
use yew::{html, Component, ComponentLink, Html, InputData, NodeRef, ShouldRender};

mod state;

@@ -134,7 +134,7 @@ impl Component for Model {
<h1>{ "todos" }</h1>
{ self.view_input() }
</header>
<section class=("main", hidden_class)>
<section class=classes!("main", hidden_class)>
<input
type="checkbox"
class="toggle-all"
@@ -147,7 +147,7 @@ impl Component for Model {
{ for self.state.entries.iter().filter(|e| self.state.filter.fits(e)).enumerate().map(|e| self.view_entry(e)) }
</ul>
</section>
<footer class=("footer", hidden_class)>
<footer class=classes!("footer", hidden_class)>
<span class="todo-count">
<strong>{ self.state.total() }</strong>
{ " item(s) left" }
5 changes: 4 additions & 1 deletion website/i18n/en.json
Original file line number Diff line number Diff line change
@@ -41,9 +41,12 @@
"title": "Pre-defined hooks"
},
"concepts/html": {
"title": "html!",
"title": "HTML",
"sidebar_label": "Introduction"
},
"concepts/html/classes": {
"title": "Classes"
},
"concepts/html/components": {
"title": "Components"
},
3 changes: 2 additions & 1 deletion website/sidebars.json
Original file line number Diff line number Diff line change
@@ -31,11 +31,12 @@
},
{
"type": "subcategory",
"label": "The HTML macro",
"label": "HTML",
"ids": [
"concepts/html",
"concepts/html/components",
"concepts/html/elements",
"concepts/html/classes",
"concepts/html/lists",
"concepts/html/literals-and-expressions"
]
Loading