Current section
Files
Jump to
Current section
Files
lib/twm.ex
defmodule Twm do
@moduledoc """
TWM - A Tailwind CSS class merger for Elixir.
Merges Tailwind CSS classes without style conflicts by intelligently
handling conflicting utilities.
"""
alias Twm.Cache
alias Twm.Config
# Re-export validators functions
alias Twm.Validators
defdelegate is_any(), to: Validators, as: :any?
defdelegate is_any(value), to: Validators, as: :any?
defdelegate is_any_non_arbitrary(value), to: Validators
defdelegate is_arbitrary_image(value), to: Validators
defdelegate is_arbitrary_length(value), to: Validators
defdelegate is_arbitrary_number(value), to: Validators
defdelegate is_arbitrary_position(value), to: Validators
defdelegate is_arbitrary_shadow(value), to: Validators
defdelegate is_arbitrary_size(value), to: Validators
defdelegate is_arbitrary_value(value), to: Validators
defdelegate is_arbitrary_variable(value), to: Validators
defdelegate is_arbitrary_variable_family_name(value), to: Validators
defdelegate is_arbitrary_variable_image(value), to: Validators
defdelegate is_arbitrary_variable_length(value), to: Validators
defdelegate is_arbitrary_variable_position(value), to: Validators
defdelegate is_arbitrary_variable_shadow(value), to: Validators
defdelegate is_arbitrary_variable_size(value), to: Validators
defdelegate is_fraction(value), to: Validators
defdelegate is_integer(value), to: Validators, as: :is_integer_value
defdelegate is_number(value), to: Validators, as: :is_number_value
defdelegate is_percent(value), to: Validators, as: :percent?
defdelegate is_tshirt_size(value), to: Validators
@doc """
Merges multiple Tailwind CSS classes into a single string, removing conflicting classes.
This function uses an LRU cache to improve performance for repeated calls with the
same input classes.
## Examples
iex> Twm.merge("px-2 px-4")
"px-4"
iex> Twm.merge("pt-2 pt-4 pb-3")
"pt-4 pb-3"
"""
@spec merge(String.t() | [String.t()], Keyword.t() | Config.t() | nil) :: String.t()
def merge(classes, options \\ [])
def merge(classes, opts) when is_binary(classes) and is_list(opts) do
cache_name = Keyword.get(opts, :cache_name, Twm.Cache)
case Cache.get_or_create(cache_name, classes) do
{:ok, result} ->
result
:error ->
result = Twm.Merger.merge_classes(classes, Twm.Config.get_default())
result
end
end
def merge(classes, opts) when is_list(classes) and is_list(opts) do
classes
|> flatten_and_filter_classes()
|> Enum.join(" ")
|> merge(opts)
end
def merge(classes, %Twm.Config{} = config) when is_binary(classes) do
Twm.Merger.merge_classes(classes, config)
end
def merge(classes, %Twm.Config{} = config) when is_list(classes) do
classes
|> flatten_and_filter_classes()
|> Enum.join(" ")
|> merge(config)
end
# Private helper function to flatten nested arrays and filter out nil/false values
defp flatten_and_filter_classes(classes) do
classes
|> List.flatten()
|> Enum.filter(fn
nil -> false
false -> false
"" -> false
class when is_binary(class) -> true
_ -> false
end)
end
end