07c82e21d3
* Move directories for ast tests to match convention * feat!: Rename `:let` to `:let!` We use the "bang" style as the reserved keyword to differentiate it from other possible attributes. * feat: use Phoenix.HTML as the default engine I am choosing to leverage this library in order to quickly get dynamic attributes (see #183) up and running. This also ensures that folks who wish to use Temple outside of a Phoenix project with get some nice HTML functions as well as properly escaped HTML out of the box. This can be made optional if Temple becomes decoupled from the render and it including HTML specific packages becomes a strange. * feat: Allow user to make their own Component module The component module is essentially to defer compiling functions that the user might not need. The component, render_slot, and inner_block functions are only mean to be used when there isn't another implementation. In the case of a LiveView application, LiveView is providing the component runtime implementation. This was causing some compile time warnings for temple, because it was using the LiveView engine at compile time (for Temple, not the user's application) and LiveView hadn't been compiled or loaded. So, now we defer this to the user to make their own module and import it where necessary. * feat: Pass dynamic attributes with the :rest! attribute The :rest! attribute can be used to pass in a dynamic list of attributes to be mixed into the static ones at runtime. Since this cannot be properly escaped by any engine, we have to mark it as safe and then allow the function to escape it for us. I decided to leverage the `attributes_escape/1` function from `phoenix_html`. There isn't really any point in making my own version of this or vendoring it. Now you can also pass a variable as the attributes as well if you only want to pass through attributes from a calling component. The :rest! attribute also works with components, allowing you to pass a dynamic list of args into them. Fixes #183 * Move test components to their own file. * docs(components): Update documentation on Temple.Components * docs(guides): Mention attributes_escape/1 function in the guides * chore(test): Move helper to it's own module * feat: rest! support for slots * docs(guides): Dynamic attributes * ci: downgrade runs-on to support OTP 23 |
||
---|---|---|
.github | ||
bin | ||
config | ||
guides | ||
integration_test/temple_plug_demo | ||
lib | ||
test | ||
.formatter.exs | ||
.gitignore | ||
.tool-versions | ||
CHANGELOG.md | ||
LICENSE | ||
mix.exs | ||
mix.lock | ||
README.md | ||
temple-github-image.png | ||
temple.png |
You are looking at the README for the main branch. The README for the latest stable release is located here.
Temple is an Elixir DSL for writing HTML and SVG.
Installation
Add temple
to your list of dependencies in mix.exs
:
def deps do
[
{:temple, "~> 0.10.0"}
]
end
Goals
Currently Temple has the following things on which it won't compromise.
- Will only work with valid Elixir syntax.
- Should work in all web environments such as Plug, Aino, Phoenix, and Phoenix LiveView.
Usage
Using Temple is as simple as using the DSL inside of an temple/1
block. The runtime result of the macro is your HTML.
See the guides for more details.
import Temple
temple do
h2 do: "todos"
ul class: "list" do
for item <- @items do
li class: "item" do
div class: "checkbox" do
div class: "bullet hidden"
end
div do: item
end
end
end
script do: """
function toggleCheck({currentTarget}) {
currentTarget.children[0].children[0].classList.toggle("hidden");
}
let items = document.querySelectorAll("li");
Array.from(items).forEach(checkbox => checkbox.addEventListener("click", toggleCheck));
"""
end
Components
Temple components are simple to write and easy to use.
Unlike normal partials, Temple components have the concept of "slots", which are similar Vue. You can also refer to HEEx and Surface for examples of templates that have the "slot" concept.
Temple components are compatible with HEEx and Surface components and can be shared.
Please see the guides for more details.
defmodule MyAppWeb.Component do
import Temple
def card(assigns) do
temple do
section do
div do
slot @header
end
div do
slot @inner_block
end
div do
slot @footer
end
end
end
end
end
Using components is as simple as passing a reference to your component function to the c
keyword.
import MyAppWeb.Component
c &card/1 do
slot :header do
@user.full_name
end
@user.bio
slot :footer do
a href: "https://twitter.com/#{@user.twitter}" do
"@#{@user.twitter}"
end
a href: "https://github.com/#{@user.github}" do
"@#{@user.github}"
end
end
end
Engine
By default, Temple will use the EEx.SmartEngine
that is built into the Elixir standard library. If you are a web framework that uses it's own template engine (such as Aino and Phoenix/LiveView, you can configure Temple to it!
# config/config.exs
config :temple,
engine: Aino.View.Engine # or Phoenix.HTML.Engine or Phoenix.LiveView.Engine
Formatter
To include Temple's formatter configuration, add :temple
to your .formatter.exs
.
[
import_deps: [:temple],
inputs: ["*.{ex,exs}", "priv/*/seeds.exs", "{config,lib,test}/**/*.{ex,exs,lexs}"],
]
Phoenix
To use with Phoenix, please use the temple_phoenix package! This bundles up some useful helpers as well as the Phoenix Template engine.