ThemeEx

Hex.pmDocumentationCILicense

An Elixir package that implements data structures for the Theme UI theme specification and provides utilities for parsing, validation, and CSS variable generation.

Features

Installation

Add theme_ex to your list of dependencies in mix.exs:

def deps do
  [
    {:theme_ex, "~> 0.1.0"}
  ]
end

Data Structures

ThemeEx implements the complete Theme UI specification with the following core structures:

Usage

Creating Themes

# Create a complete theme
theme = %ThemeEx.Theme{
  colors: %ThemeEx.Colors{
    text: "#000000",
    background: "#ffffff", 
    primary: "#0066cc",
    secondary: "#ff6600",
    modes: %{
      "dark" => %{
        "text" => "#ffffff",
        "background" => "#000000",
        "primary" => "#66ccff"
      }
    }
  },
  fonts: %ThemeEx.Fonts{
    body: "system-ui, -apple-system, sans-serif",
    heading: "Georgia, serif",
    monospace: "Menlo, Monaco, monospace"
  },
  fontWeights: %ThemeEx.FontWeights{
    body: 400,
    heading: 700,
    bold: 600
  },
  fontSizes: [12, 14, 16, 20, 24, 32, 48, 64, 96],
  space: [0, 4, 8, 16, 32, 64, 128, 256],
  breakpoints: ["40em", "52em", "64em"]
}

JSON Parsing

# Parse from JSON string
json_theme = """
{
  "colors": {
    "text": "#000000",
    "background": "#ffffff",
    "primary": "#0066cc",
    "modes": {
      "dark": {
        "text": "#ffffff",
        "background": "#000000"
      }
    }
  },
  "fonts": {
    "body": ["system-ui", "sans-serif"],
    "heading": "Georgia, serif"
  },
  "fontSizes": [12, 14, 16, 20, 24, 32]
}
"""

{:ok, theme} = ThemeEx.from_json(json_theme)

# Or from a map
theme_map = %{
  "colors" => %{"primary" => "#0066cc"},
  "fontSizes" => [14, 16, 18, 24]
}

{:ok, theme} = ThemeEx.from_map(theme_map)

CSS Variables Generation

theme = %ThemeEx.Theme{
  colors: %ThemeEx.Colors{
    primary: "#0066cc",
    secondary: "#ff6600"
  },
  fonts: %ThemeEx.Fonts{
    body: "system-ui, sans-serif"
  },
  fontSizes: [12, 14, 16, 20]
}

css = ThemeEx.to_css_variables(theme)

# Output:
# :root {
#   --theme-colors-primary: #0066cc;
#   --theme-colors-secondary: #ff6600;
#   --theme-fonts-body: system-ui, sans-serif;
#   --theme-fontSizes-0: 12;
#   --theme-fontSizes-1: 14;
#   --theme-fontSizes-2: 16;
#   --theme-fontSizes-3: 20;
# }

Theme Validation

# Validate theme structure and types
case ThemeEx.validate(theme) do
  {:ok, validated_theme} -> 
    IO.puts("Theme is valid!")
    validated_theme
  {:error, errors} -> 
    IO.puts("Validation failed: #{inspect(errors)}")
end

JSON Schema Generation

# Generate JSON Schema for external validation
schema = ThemeEx.json_schema()

# Returns a complete JSON Schema following draft/2020-12 specification
%{
  "$schema" => "https://json-schema.org/draft/2020-12/schema",
  "title" => "Theme UI Theme",
  "type" => "object",
  "properties" => %{
    "colors" => %{...},
    "fonts" => %{...},
    # ... complete schema definition
  }
}

Advanced Features

Font Arrays and Stacks

# Fonts can be defined as strings or arrays
fonts = %ThemeEx.Fonts{
  body: ["Helvetica Neue", "Arial", "sans-serif"],
  heading: "Georgia, serif"
}

Color Arrays and Scales

# Colors support both single values and scales
colors = %ThemeEx.Colors{
  primary: ["#e3f2fd", "#bbdefb", "#90caf9", "#64b5f6", "#42a5f5"],
  text: "#000000"
}

Responsive Design Tokens

theme = %ThemeEx.Theme{
  space: [0, 4, 8, 16, 32, 64, 128],        # Spacing scale
  sizes: [16, 32, 64, 128, 256, 512, 768],  # Size scale  
  radii: [0, 2, 4, 8, 16],                  # Border radius scale
  shadows: [                                # Box shadow definitions
    "none",
    "0 1px 3px rgba(0,0,0,0.12)",
    "0 4px 6px rgba(0,0,0,0.16)"
  ],
  breakpoints: ["40em", "52em", "64em"]     # Media query breakpoints
}

API Reference

Core Functions

Data Structures

All structs include proper type specifications and support for both single values and arrays where appropriate by the Theme UI specification.

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Run tests (mix test)
  4. Commit your changes (git commit -m 'Add amazing feature')
  5. Push to the branch (git push origin feature/amazing-feature)
  6. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.

References