# `Yog.Render.Mermaid`
[🔗](https://github.com/code-shoily/yog_ex/blob/v0.98.5/lib/yog/render/mermaid.ex#L1)

Mermaid.js format export for embedding diagrams in web pages and documents.

This module exports graphs to [Mermaid](https://mermaid.js.org/) syntax,
a JavaScript-based diagramming tool that renders diagrams from text definitions.
Mermaid is supported natively in GitHub, GitLab, Notion, and many other platforms.

## Quick Start

    # Export to Mermaid syntax
    mermaid = Yog.Render.Mermaid.to_mermaid(my_graph, Yog.Render.Mermaid.default_options())

    # Use in Markdown:
    # ```mermaid
    # graph TD
    #     A[Node 1] --> B[Node 2]
    # ```

## Supported Diagram Types

This module generates flowchart-style diagrams:
- **Graph TD**: Top-down (vertical) layout
- **Graph LR**: Left-to-right (horizontal) layout
- **Graph BT**: Bottom-to-top layout
- **Graph RL**: Right-to-left layout

## Customization

Control styling via `t:options/0`:
- Node shapes (rounded, rectangular, circular, rhombus, hexagon, etc.)
- Labels and edge annotations
- Highlight specific nodes or edges
- **Per-node and per-edge styling** (custom colors, stroke widths, etc.)
- **Subgraphs** for visual grouping
- Direction and orientation
- CSS-based styling with custom lengths

## Per-Element Styling

Provide custom attribute functions for fine-grained control:

    options = %{
      Yog.Render.Mermaid.default_options() |
      node_attributes: fn id, data ->
        case id do
          1 -> [{:fill, "#e1f5fe"}, {:stroke, "#0288d1"}]
          _ -> []
        end
      end,
      edge_attributes: fn from, to, weight ->
        if weight > 10 do
          [{:stroke, "#d32f2f"}, {:stroke_width, "3px"}]
        else
          []
        end
      end
    }

## Subgraphs

Group nodes visually using subgraphs:

    options = %{
      Yog.Render.Mermaid.default_options() |
      subgraphs: [
        %{
          name: "Group A",
          label: "Cluster A",
          node_ids: [1, 2, 3]
        }
      ]
    }

## Embedding Options

| Platform | Method |
|----------|--------|
| GitHub/GitLab | Native Markdown support |
| Notion | Mermaid code block |
| VS Code | Mermaid extension |
| Static site | Mermaid.js library |
| Jupyter | Mermaid magic commands |

## Live Editor

Test and refine diagrams at [Mermaid Live Editor](https://mermaid.live/).

## References

- [Mermaid Syntax](https://mermaid.js.org/syntax/flowchart.html)
- [GitHub Mermaid Docs](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-diagrams)

# `css_length`

```elixir
@type css_length() ::
  {:px, integer()}
  | {:em, float()}
  | {:rem, float()}
  | {:percent, float()}
  | {:custom, String.t()}
```

CSS length unit for styling.

Mermaid supports various CSS length units:
- `:px` - Pixels (most common)
- `:em` - Ems (relative to font size)
- `:rem` - Rems (relative to root font size)
- `:percent` - Percentage
- `{:custom, string}` - Custom CSS value (for advanced users)

# `direction`

```elixir
@type direction() :: :td | :lr | :bt | :rl
```

Direction for graph layout

# `node_shape`

```elixir
@type node_shape() ::
  :rounded_rect
  | :stadium
  | :subroutine
  | :cylinder
  | :circle
  | :asymmetric
  | :rhombus
  | :hexagon
  | :parallelogram
  | :parallelogram_alt
  | :trapezoid
  | :trapezoid_alt
```

Node shape options for Mermaid diagrams.

Each shape has a specific Mermaid syntax:
- `:rounded_rect` - `[label]` - Rectangle with rounded corners
- `:stadium` - `([label])` - Stadium shape (pill)
- `:subroutine` - `[[label]]` - Subroutine shape (rectangle with side lines)
- `:cylinder` - `[(label)]` - Cylindrical shape (database)
- `:circle` - `((label))` - Circle
- `:asymmetric` - `>label]` - Asymmetric shape (flag)
- `:rhombus` - `{label}` - Rhombus (decision)
- `:hexagon` - `{{label}}` - Hexagon
- `:parallelogram` - `[/label/]` - Parallelogram
- `:parallelogram_alt` - `[\label\]` - Parallelogram alt
- `:trapezoid` - `[/label\]` - Trapezoid
- `:trapezoid_alt` - `[\label/]` - Trapezoid alt

# `options`

```elixir
@type options() :: %{
  node_label: (Yog.node_id(), any() -&gt; String.t()),
  edge_label: (any() -&gt; String.t()),
  highlighted_nodes: [Yog.node_id()] | nil,
  highlighted_edges: [{Yog.node_id(), Yog.node_id()}] | nil,
  node_attributes: (Yog.node_id(), any() -&gt; [{atom(), String.t()}]),
  edge_attributes: (Yog.node_id(), Yog.node_id(), any() -&gt;
                      [{atom(), String.t()}]),
  subgraphs: [subgraph()] | nil,
  direction: direction(),
  node_shape: node_shape() | (Yog.node_id(), any() -&gt; node_shape()),
  default_fill: String.t() | nil,
  default_stroke: String.t() | nil,
  default_stroke_width: css_length() | nil,
  default_font_color: String.t() | nil,
  default_link_stroke: String.t() | nil,
  highlight_fill: String.t(),
  highlight_stroke: String.t(),
  highlight_stroke_width: css_length(),
  link_thickness: css_length(),
  highlight_link_stroke: String.t(),
  highlight_link_stroke_width: css_length()
}
```

Options for customizing Mermaid diagram rendering

# `subgraph`

```elixir
@type subgraph() :: %{
  name: String.t(),
  label: String.t() | nil,
  node_ids: [Yog.node_id()] | nil
}
```

A subgraph for grouping nodes visually in the diagram.

# `community_to_options`

```elixir
@spec community_to_options(Yog.Community.Result.t(), options()) :: options()
```

Creates Mermaid options that color nodes by community assignment.

Each community gets a distinct color from a generated palette. The palette
cycles through visually distinct hues using inline node styles.

## Example

    result = Yog.Community.Louvain.detect(graph)
    options = Yog.Render.Mermaid.community_to_options(result)
    mermaid = Yog.Render.Mermaid.to_mermaid(graph, options)

# `cut_to_options`

```elixir
@spec cut_to_options(Yog.Flow.MinCutResult.t(), options()) :: options()
```

Creates Mermaid options that color the source and sink sides of a min-cut.

Source-side nodes are colored with `source_color` (default: light blue),
sink-side nodes with `sink_color` (default: light coral).

Requires the `MinCutResult` to have `source_side` and `sink_side` populated
(use `track_partitions: true` or `extract_min_cut/1`).

## Example

    result = Yog.Flow.MinCut.global_min_cut(graph, track_partitions: true)
    options = Yog.Render.Mermaid.cut_to_options(result)
    mermaid = Yog.Render.Mermaid.to_mermaid(graph, options)

# `default_options`

```elixir
@spec default_options() :: options()
```

Creates default Mermaid options with simple labeling.

Uses node ID as label and edge weight as-is.
Default configuration:
- Direction: Top-to-bottom (TD)
- Node shape: Rounded rectangle
- Highlight: Yellow fill with orange stroke

## Examples

    iex> opts = Yog.Render.Mermaid.default_options()
    iex> opts.direction
    :td
    iex> opts.node_shape
    :rounded_rect
    iex> opts.highlight_fill
    "#ffeb3b"

# `default_options_with`

```elixir
@spec default_options_with(
  node_label: (Yog.node_id(), any() -&gt; String.t()),
  edge_label: (any() -&gt; String.t())
) :: options()
```

Creates default Mermaid options with custom label formatters for both nodes and edges.

## Example

    options = Yog.Render.Mermaid.default_options_with(
      node_label: fn id, data -> "#{data} (#{id})" end,
      edge_label: fn weight -> "#{weight} ms" end
    )

# `default_options_with_edge_formatter`

```elixir
@spec default_options_with_edge_formatter((any() -&gt; String.t())) :: options()
```

Creates default Mermaid options with a custom edge formatter.

Use this when your graph has non-String edge data (e.g., Int, Float, custom types).

## Example

    # For a graph with Int edge weights
    options = Yog.Render.Mermaid.default_options_with_edge_formatter(fn weight ->
      Integer.to_string(weight)
    end)

# `default_options_without_labels`

```elixir
@spec default_options_without_labels() :: options()
```

Creates default Mermaid options with all edge labels hidden.

Use this when you want a clean diagram without edge annotations.

## Example

    mermaid = Yog.Render.Mermaid.to_mermaid(graph,
      Yog.Render.Mermaid.default_options_without_labels()
    )

# `matching_to_options`

```elixir
@spec matching_to_options(%{required(Yog.node_id()) =&gt; Yog.node_id()}, options()) ::
  options()
```

Creates Mermaid options that highlight matched edges from a matching result.

Works with results from both `Yog.Matching.hopcroft_karp/1` and
`Yog.Matching.hungarian/2` (the matching map component).

## Example

    matching = Yog.Matching.hopcroft_karp(graph)
    options = Yog.Render.Mermaid.matching_to_options(matching)
    mermaid = Yog.Render.Mermaid.to_mermaid(graph, options)

# `mst_to_options`

```elixir
@spec mst_to_options(Yog.MST.Result.t(), options()) :: options()
```

Creates Mermaid options that highlight an MST result.

MST edges are highlighted and MST nodes use default styling.

## Example

    result = Yog.MST.kruskal(graph)
    options = Yog.Render.Mermaid.mst_to_options(result)
    mermaid = Yog.Render.Mermaid.to_mermaid(graph, options)

# `path_to_options`

```elixir
@spec path_to_options(map(), options()) :: options()
```

Converts a shortest path result to highlighted Mermaid options.

Creates a copy of the base options with the path's nodes and edges
set to be highlighted.

## Example

    case Yog.Pathfinding.Dijkstra.shortest_path(...) do
      {:ok, path} ->
        options = Yog.Render.Mermaid.path_to_options(path, Yog.Render.Mermaid.default_options())
        mermaid = Yog.Render.Mermaid.to_mermaid(graph, options)
      :error ->
        ""
    end

# `theme`

```elixir
@spec theme(atom()) :: options()
```

Returns a pre-configured theme as Mermaid options.

Available themes:
- `:default` — Yellow highlight, orange stroke (same as `default_options/0`)
- `:dark` — Dark-friendly colors with neon accent colors
- `:minimal` — Clean wireframe look with no fills and thin lines
- `:presentation` — Large strokes and bold colors for slides and demos

## Examples

    iex> opts = Yog.Render.Mermaid.theme(:dark)
    iex> opts.highlight_fill
    "#16213e"
    iex> opts.highlight_stroke
    "#e94560"

    iex> opts = Yog.Render.Mermaid.theme(:minimal)
    iex> opts.link_thickness
    {:px, 1}

    iex> opts = Yog.Render.Mermaid.theme(:presentation)
    iex> opts.highlight_stroke_width
    {:px, 4}

# `to_mermaid`

```elixir
@spec to_mermaid(Yog.graph(), options()) :: String.t()
```

Converts a graph to Mermaid diagram syntax.

The graph's node data and edge data must be convertible to strings.
Use the options to customize labels, styling, and to define subgraphs.

**Time Complexity:** O(V + E + S) where S is the total number of nodes
across all subgraphs.

## Example

    graph =
      Yog.directed()
      |> Yog.add_node(1, "Start")
      |> Yog.add_node(2, "Process")
      |> Yog.add_node(3, "End")
      |> Yog.add_edge_ensure(from: 1, to: 2, with: "5")
      |> Yog.add_edge_ensure(from: 2, to: 3, with: "3")

    # Basic rendering
    diagram = Yog.Render.Mermaid.to_mermaid(graph, default_options())

    # Highlight a path
    options = %{
      default_options() |
      highlighted_nodes: [1, 2, 3],
      highlighted_edges: [{1, 2}, {2, 3}]
    }
    highlighted = Yog.Render.Mermaid.to_mermaid(graph, options)

The output can be embedded in markdown:
````markdown
```mermaid
graph TD
  1["Start"]
  2["Process"]
  3["End"]
  1 -->|5| 2
  2 -->|3| 3
```
````

---

*Consult [api-reference.md](api-reference.md) for complete listing*
