Skip to main content

lib/pdf/component/divider.ex

defmodule Pdf.Component.Divider do
  @moduledoc """
  Divider component for PDF documents.

  Renders a horizontal or vertical line separator with configurable
  color, width, style (solid/dashed), and margin.

  Inspired by Material UI's Divider component.

  ## Examples

      # Simple horizontal divider
      doc |> Pdf.Component.Divider.render({50, 400}, %{width: 200})

      # Dashed divider with color
      doc |> Pdf.Component.Divider.render({50, 400}, %{
        width: 200,
        color: {0.8, 0.8, 0.8},
        style: :dashed,
        thickness: 0.5
      })

      # Vertical divider
      doc |> Pdf.Component.Divider.render({250, 700}, %{
        height: 100,
        orientation: :vertical
      })
  """

  @default_color {0.85, 0.85, 0.85}
  @default_thickness 0.5
  @default_dash_pattern {3, 3}

  @doc """
  Render a divider at `{x, y}`.

  ## Style options

  - `:width` — length for horizontal dividers (default `0`, required for horizontal)
  - `:height` — length for vertical dividers (default `0`, required for vertical)
  - `:orientation` — `:horizontal` (default) or `:vertical`
  - `:color` — line color (default light gray)
  - `:thickness` — line width in points (default `0.5`)
  - `:style` — `:solid` (default) or `:dashed`
  - `:dash` — custom dash pattern `{on, off}` (default `{3, 3}`)
  - `:margin_top` — space above (default `0`)
  - `:margin_bottom` — space below (default `0`)
  """
  def render(doc, {x, y}, style \\ %{}) do
    orientation = Map.get(style, :orientation, :horizontal)
    color = Map.get(style, :color, @default_color)
    thickness = Map.get(style, :thickness, @default_thickness)
    line_style = Map.get(style, :style, :solid)
    margin_top = Map.get(style, :margin_top, 0)
    margin_bottom = Map.get(style, :margin_bottom, 0)

    y = y - margin_top

    doc = doc
    |> Pdf.save_state()
    |> Pdf.set_stroke_color(color)
    |> Pdf.set_line_width(thickness)

    doc = apply_dash(doc, line_style, Map.get(style, :dash, @default_dash_pattern))

    doc = case orientation do
      :vertical ->
        h = Map.get(style, :height, 0)
        Pdf.line(doc, {x, y}, {x, y - h})

      _horizontal ->
        w = Map.get(style, :width, 0)
        Pdf.line(doc, {x, y}, {x + w, y})
    end

    doc = Pdf.restore_state(doc)

    if margin_bottom > 0 do
      Pdf.spacer(doc, margin_bottom)
    else
      doc
    end
  end

  defp apply_dash(doc, :solid, _pattern), do: doc

  defp apply_dash(doc, :dashed, {on, off}) do
    Pdf.set_dash(doc, [on, off])
  end
end