This repository has been archived on 2023-08-07. You can view files and clone it, but cannot push or open issues or pull requests.
Go to file
Mitchell Hanberg 07c82e21d3
Dynamic Attributes (#190)
* 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
2023-01-21 06:44:29 -05:00
.github Dynamic Attributes (#190) 2023-01-21 06:44:29 -05:00
bin Compile to EEx (#80) 2020-06-16 15:28:21 -04:00
config Utilize the EEx Engine instead of creating an EEx string (#177) 2022-04-19 23:56:46 -04:00
guides Dynamic Attributes (#190) 2023-01-21 06:44:29 -05:00
integration_test/temple_plug_demo Utilize the EEx Engine instead of creating an EEx string (#177) 2022-04-19 23:56:46 -04:00
lib Dynamic Attributes (#190) 2023-01-21 06:44:29 -05:00
test Dynamic Attributes (#190) 2023-01-21 06:44:29 -05:00
.formatter.exs Dynamic Attributes (#190) 2023-01-21 06:44:29 -05:00
.gitignore Compile to EEx (#80) 2020-06-16 15:28:21 -04:00
.tool-versions feat: Mix task to convert HTML into Temple (#180) 2022-09-11 22:39:31 -04:00
CHANGELOG.md Dynamic Attributes (#190) 2023-01-21 06:44:29 -05:00
LICENSE feat: New Component API 2021-01-02 13:22:03 -05:00
README.md Align component model with HEEx/Surface (#182) 2022-10-12 09:17:23 -04:00
mix.exs Dynamic Attributes (#190) 2023-01-21 06:44:29 -05:00
mix.lock Dynamic Attributes (#190) 2023-01-21 06:44:29 -05:00
temple-github-image.png Utilize the EEx Engine instead of creating an EEx string (#177) 2022-04-19 23:56:46 -04:00
temple.png Logo 2019-07-04 00:16:37 -04:00

README.md

Actions Status Hex.pm

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.