Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 5 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,12 @@ end

## Setup

`TailwindFormatter` is most likely to be used alongside `Phoenix.LiveView.HTMLFormatter`,
so it should be installed in a way that allows the HTML formatter to
run after the Tailwind formatter.

Update your `.formatter.exs` to include `TailwindFormatter`.
Add `TailwindFormatter` as a class attribute formatter of `Phoenix.LiveView.HTMLFormatter` in `.formatter.exs`.

```elixir
[
plugins: [TailwindFormatter, Phoenix.LiveView.HTMLFormatter],
plugins: [Phoenix.LiveView.HTMLFormatter],
attribute_formatters: %{class: TailwindFormatter},
inputs: [
"*.{heex,ex,exs}",
"priv/*/seeds.exs",
Expand All @@ -54,8 +51,8 @@ let { extract } = require("../deps/tailwind_formatter/assets/js")
extract(module.exports, "../_build")
```

This will write a `classes.txt` and `variants.txt` to your `_build/` directory.
The second argument within `extract` may vary depending on the value of `cd:` in your `:tailwind` config.
This will write a `classes.txt` and `variants.txt` to your `_build/` directory.
The second argument within `extract` may vary depending on the value of `cd:` in your `:tailwind` config.

The above will work with this configuration, for example:

Expand Down
75 changes: 39 additions & 36 deletions lib/tailwind_formatter.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,48 +5,51 @@ defmodule TailwindFormatter do
|> String.split("<!-- MDOC !-->")
|> Enum.fetch!(1)

alias TailwindFormatter.{Order, HEExTokenizer}

@behaviour Mix.Tasks.Format
alias TailwindFormatter.Order

@placeholder "💧"

def features(_opts) do
[sigils: [:H], extensions: [".heex"]]
raise """
TailwindFormatter is now an attribute formatter for Phoenix.LiveView.HTMLFormatter.

In your .formatter.exs file, make sure to:
1. remove TailwindFormatter from the :plugins list
2. add `attribute_formatters: %{class: TailwindFormatter}`

# .formatter.exs
[
...,
plugins: [Phoenix.LiveView.HTMLFormatter],
attribute_formatters: %{class: TailwindFormatter},
]
"""
end

def format(contents, _opts) do
contents
|> HEExTokenizer.tokenize()
|> Enum.reduce([contents], fn
{elt, _name, attrs, _meta}, contents
when elt in [:tag, :local_component, :remote_component] ->
Enum.reduce(attrs, contents, fn
{"class", class_attr, _meta}, [remainder | acc] ->
[attr, remainder] = String.split(remainder, old_classes(class_attr), parts: 2)
[remainder, sort_classes(class_attr), attr | acc]

_, contents ->
contents
end)

_, contents ->
contents
end)
|> Enum.reverse()
|> Enum.join()
end

defp old_classes({_type, classes, _meta}), do: classes
defp sort_classes({:string, classes, _meta}), do: sort(classes)

defp sort_classes({:expr, expr_class, _meta}) do
expr_class
|> Code.string_to_quoted!(literal_encoder: &{:ok, {:__block__, &2, [&1]}})
|> sort_expr()
|> Code.quoted_to_algebra()
|> Inspect.Algebra.format(:infinity)
|> IO.iodata_to_binary()
def render_attribute({"class", class, meta}, _opts) do
{
"class",
case class do
{:string, string, meta} ->
{:string, sort(string), meta}

{:expr, expr, meta} ->
{
:expr,
expr
|> Code.string_to_quoted!(literal_encoder: &{:ok, {:__block__, &2, [&1]}})
|> sort_expr()
|> Code.quoted_to_algebra()
|> Inspect.Algebra.format(:infinity)
|> IO.iodata_to_binary(),
meta
}

nil ->
nil
end,
meta
}
end

defp sort_expr({:<<>>, meta, children}), do: {:<<>>, meta, handle_interpolation(children)}
Expand Down
34 changes: 0 additions & 34 deletions lib/tailwind_formatter/heex_tokenizer.ex

This file was deleted.

21 changes: 0 additions & 21 deletions lib/tailwind_formatter/phoenix_live_view_html_engine.ex

This file was deleted.

Loading