Skip to content

Commit

Permalink
Class object syntax (#140)
Browse files Browse the repository at this point in the history
* Class object syntax

Allows for conditionally setting classes on an element.

* Docs for class bindings
  • Loading branch information
mhanberg authored Jun 27, 2021
1 parent 9d05f74 commit d9f00e5
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Enhancements

- [breaking] Attributes who values are boolean expressions will be emitted as boolean attributes.
- Class "object" syntax. Conditionally add classes by passing a keyword list to the `class` attribute.

## 0.6.2

Expand Down
8 changes: 8 additions & 0 deletions lib/temple.ex
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ defmodule Temple do
input type: "text", disabled: false
# <input type="text">
# The class attribute also can take a keyword list of classes to conditionally render, based on the boolean result of the value.
div class: ["text-red-500": false, "text-green-500": true ] do
"Alert!"
end
# <div class="text-green-500">Alert!</div>
# if and unless expressions can be used to conditionally render content
if 5 > 0 do
p do
Expand Down
17 changes: 12 additions & 5 deletions lib/temple/parser/utils.ex
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,13 @@ defmodule Temple.Parser.Utils do
for {name, value} <- attrs, into: "" do
name = snake_to_kebab(name)

cond do
(not is_binary(value) && Macro.quoted_literal?(value)) || match?({_, _, _}, value) ->
~s|<%= {:safe, Temple.Parser.Utils.build_attr("#{name}", #{Macro.to_string(value)})} %>|

with false <- not is_binary(value) && Macro.quoted_literal?(value),
false <- match?({_, _, _}, value),
false <- is_list(value) do
" " <> name <> "=\"" <> to_string(value) <> "\""
else
true ->
" " <> name <> "=\"" <> to_string(value) <> "\""
~s|<%= {:safe, Temple.Parser.Utils.build_attr("#{name}", #{Macro.to_string(value)})} %>|
end
end
else
Expand All @@ -49,6 +50,12 @@ defmodule Temple.Parser.Utils do
""
end

def build_attr("class", classes) when is_list(classes) do
value = String.trim_leading(for {class, true} <- classes, into: "", do: " #{class}")

" class" <> "=\"" <> value <> "\""
end

def build_attr(name, value) do
" " <> name <> "=\"" <> to_string(value) <> "\""
end
Expand Down
6 changes: 6 additions & 0 deletions test/parser/utils_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,11 @@ defmodule Temple.Parser.UtilsTest do
assert {:safe, ~s| class="text-red" id="form1"|} == Utils.runtime_attrs(attrs_map)
assert {:safe, ~s| class="text-red" id="form1" disabled|} == Utils.runtime_attrs(attrs_kw)
end

test "class accepts a keyword list which conditionally emits classes" do
attrs = [class: ["text-red": false, "text-blue": true], id: "form1"]

assert {:safe, ~s| class="text-blue" id="form1"|} == Utils.runtime_attrs(attrs)
end
end
end
13 changes: 13 additions & 0 deletions test/temple_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -352,4 +352,17 @@ defmodule TempleTest do
assert evaluate_template(result, assigns) ==
~s{<input type="text" disabled>\n<input type="text">\n<input type="text" disabled>\n<input type="text">}
end

test "class attribute can be pass a keyword list of class/boolean pairs" do
assigns = %{is_true: true, is_false: false}

result =
temple do
div class: ["text-blue": @is_false, "text-red": true] do
"foo"
end
end

assert evaluate_template(result, assigns) == ~s{<div class="text-red">\nfoo\n\n</div>}
end
end

0 comments on commit d9f00e5

Please sign in to comment.