View Source mix compile.surface (surface v0.11.4)

Generate CSS and JS/TS assets for components.

Setup

Update mix.exs, adding the :surface compiler to the list of compilers:

def project do
  [
    ...,
    compilers: [:phoenix] ++ Mix.compilers() ++ [:surface]
  ]
end

Configuration (optional)

The Surface compiler provides some options for custom configuration in your config/dev.exs.

Options

  • hooks_output_dir - defines the folder where the compiler generates the JS hooks files. Default is ./assets/js/_hooks/.

  • css_output_file - defines the css file where the compiler generates the code. Default is ./assets/css/_components.css.

  • enable_variants [experimental] - instructs the compiler to generate tailwind variants based on props/data. Currently, only Tailwind variants are supported. Default is false. See more in the "Enabling CSS variants" section below.

  • variants_output_file [experimental] - if enable_variants is true, defines the config file where the compiler generates the scoped variants. Currently, only Tailwind variants are supported. Default is ./assets/css/_variants.js.

  • variants_prefix [experimental] - defines a prefix for all variants generated by the compiler. Default is @.

Example

config :surface, :compiler,
  hooks_output_dir: "assets/js/surface",
  css_output_file: "assets/css/surface.css",
  enable_variants: true,
  variants_prefix: "s-"

Enabling CSS variants

By setting enable_variants to true, we instruct the compiler to generate tailwind variants based on props/data. All variants are generated in the variants_output_file, which defaults to ./assets/css/_variants.js.

NOTE: This feature is still experimental and available for feedback. Therefore, the API might change in the next Surface minor version. It's also currently only available for Tailwind.

To make the generated variants available in your templates, you need to set up the project's tailwind.config.js to add the variants_output_file as a preset. Example:

module.exports = {
  presets: [
    require('./css/_variants.js')
  ],
  ...
}

Defining CSS variants

In order to define CSS variants for your templates, you can use the css_variant option, which is available for both, prop and data.

Example

prop loading, :boolean, css_variant: true
prop size, :string, values: ["small", "medium", "large"], css_variant: true

Depending on the type of the assign you're defining, a set of default variants will be automatically available in your tamplates and be used directly in any class attribute. By default, all variants names will start with the @ prefix. If needed, you can change it by setting the variants_prefix option.

Example

<button class="@loading:opacity-75 @size-small:text-sm @size-medium:text-base @size-large:text-lg">
  Submit
</button>

Customizing variants' names

As mentioned in the previous section, each variant name generated bu the compiler will start with a prefix (default is @) followed by its base name. Most of the time, you probably want to stick with the default base name, however there are cases when renaming it may be more intuitive. For instance:

# Name it as `@inactive` instead of `@not-active`
prop active, :boolean, css_variant: [false: "inactive"]

# Name it `@valid` and `@invalid` instead of `@has-errors` and `@no-errors`
data errors, :list, css_variant: [has_items: "invalid", no_items: "valid"]

# Name it `@small`, `@medium` and `@large` instead of `@size-small`, `@size-medium` and `@size-large`
prop size, :string, values: ["small", "medium", "large"], css_variant: [prefix: ""]

As you can see, the value of css_variant option can be either a boolean or a keyword list of options.

By passing true, the compiler generates variants according to the default values for each option based to the name and type of the related assign. All available options for each type are listed below.

Options for :boolean

  • :true - the base name of the variant when the value is truthy. Default is the assign name.
  • :false - the base name of the variant when the value is falsy. Default is not-[assign-name].

Options for enumerables, e.g. :list, :map and :mapset

  • :has_items - the base name of the variant when the value list has items. Default is has-[assign-name]
  • :no_items - the base name of the variant when the value is empty or nil. Default is no-[assign-name]

Options for :string, :atom and :integer defining values or values!

  • :prefix - the prefix of the variant's base name generated for each value listed in values or values!. Default is [assign-name]-.

Options for other types

  • :not_nil - the base name of the variant when the value is not nil. Default is the assign name.
  • :nil - the base name of the variant when the value is nil. Default is no-[assign-name].