README.md

# LiveStyle

Atomic CSS-in-Elixir for Phoenix LiveView, inspired by [Meta's StyleX](https://stylexjs.com/).

LiveStyle provides a type-safe, composable styling system with:

- **Atomic CSS**: Each property-value pair becomes a single class
- **Deterministic hashing**: Same styles always produce same class names
- **CSS Variables**: Type-safe design tokens with `css_vars/2`
- **Constants**: Static values inlined at compile time with `css_consts/2`
- **Theming**: Override variables with `css_theme/3`
- **@layer support**: CSS cascade layers for predictable specificity
- **Last-wins merging**: Like StyleX, later styles override earlier ones

## Installation

Add `live_style` to your dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:live_style, "~> 0.9.0"}
  ]
end
```

See the [Getting Started](guides/getting-started.md) guide for complete setup instructions.

## Quick Example

```elixir
defmodule MyAppWeb.Components.Button do
  use Phoenix.Component
  use LiveStyle.Sheet

  css_class :base,
    display: "inline-flex",
    align_items: "center",
    padding: "8px 16px",
    border_radius: "6px"

  css_class :primary,
    background_color: "#4f46e5",
    color: "white",
    ":hover": [background_color: "#4338ca"]

  def button(assigns) do
    ~H"""
    <button class={css_class([:base, :primary])}>
      <%= render_slot(@inner_block) %>
    </button>
    """
  end
end
```

## Guides

- [Getting Started](guides/getting-started.md) - Installation and setup
- [Design Tokens](guides/design-tokens.md) - CSS variables, constants, and keyframes
- [Styling Components](guides/styling-components.md) - Defining and composing styles
- [Theming](guides/theming.md) - Creating and applying themes
- [Advanced Features](guides/advanced-features.md) - Contextual selectors, view transitions, anchor positioning
- [Configuration](guides/configuration.md) - Shorthand behaviors and options

## Key Concepts

### Design Tokens

Use `css_vars` for values that change (colors, themed tokens) and `css_consts` for static values:

```elixir
defmodule MyApp.Tokens do
  use LiveStyle.Tokens

  # Colors use css_vars (for theming)
  css_vars :colors,
    primary: "#4f46e5",
    gray_900: "#111827"

  # Static values use css_consts
  css_consts :space,
    sm: "8px",
    md: "16px"

  css_consts :radius,
    md: "8px",
    lg: "12px"

  css_keyframes :fade_in,
    from: [opacity: "0"],
    to: [opacity: "1"]
end
```

### Component Styles

Reference tokens with `css_var` for colors and `css_const` for static values:

```elixir
defmodule MyApp.Card do
  use LiveStyle.Sheet

  css_class :card,
    padding: css_const({MyApp.Tokens, :space, :md}),
    border_radius: css_const({MyApp.Tokens, :radius, :lg}),
    color: css_var({MyApp.Tokens, :colors, :gray_900})
end
```

### Theming

Create theme variations (only works with `css_vars`):

```elixir
# In your tokens
css_theme :semantic, :dark,
  text_primary: css_var({:colors, :white}),
  fill_page: css_var({:colors, :gray_900})

# In your template
<html class={@theme == :dark && css_theme({MyApp.Tokens, :semantic, :dark})}>
```

### Pseudo-classes & Media Queries

```elixir
css_class :link,
  color: [
    default: "blue",
    ":hover": "darkblue"
  ]

css_class :container,
  padding: [
    default: css_const({MyApp.Tokens, :space, :md}),
    "@media (min-width: 768px)": css_const({MyApp.Tokens, :space, :lg})
  ]
```

## Why LiveStyle?

### vs Tailwind CSS

- **Type-safe tokens**: Design tokens are Elixir values, not magic strings
- **No purging complexity**: Only styles you use are generated
- **Elixir-native**: Conditional logic uses `&&` and `||`, not string concatenation
- **Scoped theming**: Override tokens for subtrees without global CSS

### vs Inline Styles

- **Pseudo-classes**: `:hover`, `:focus`, etc. work naturally
- **Media queries**: Responsive design without JavaScript
- **Performance**: Atomic classes are cached and deduplicated
- **DevTools**: Inspect class names instead of inline style blobs

### Inspired by StyleX

LiveStyle brings Meta's StyleX philosophy to Phoenix LiveView:

- Atomic CSS for minimal bundle size
- Last-wins merging for predictable composition
- Deterministic class names for caching
- CSS variables for theming

## Optional Integrations

```elixir
def deps do
  [
    {:live_style, "~> 0.9.0"},
    # Automatic vendor prefixing
    {:autoprefixer_ex, "~> 0.1.0"},
    # Deprecation warnings for CSS properties
    {:css_compat_data_ex, "~> 0.1.0"}
  ]
end
```

## License

MIT License - see [LICENSE](LICENSE) for details.