# `PhiaUi.Components.Editor.EditorContent`
[🔗](https://github.com/charlenopires/PhiaUI/blob/v0.1.17/lib/phia_ui/components/editor/editor_content.ex#L1)

Pure Elixir utilities for working with editor JSON content.

Documents are stored as a JSON tree of typed nodes with marks. This module
provides server-side operations — HTML rendering, plain-text extraction,
validation, and sanitization — so you can process editor content without
JavaScript.

## Editor JSON Format

    %{
      "type" => "doc",
      "content" => [
        %{
          "type" => "paragraph",
          "content" => [
            %{"type" => "text", "text" => "Hello ", "marks" => [%{"type" => "bold"}]},
            %{"type" => "text", "text" => "world"}
          ]
        }
      ]
    }

## Usage

    alias PhiaUi.Components.Editor.EditorContent

    # Render JSON to safe HTML
    html = EditorContent.content_to_html(json)

    # Extract plain text for search indexing
    text = EditorContent.content_to_text(json)

    # Validate against allowed schema
    {:ok, json} = EditorContent.validate_content(json, allowed_nodes: ~w(paragraph heading))

    # Count words
    count = EditorContent.word_count(json)

# `content_to_html`

```elixir
@spec content_to_html(map() | nil) :: String.t()
```

Converts an editor JSON document to an HTML string.

The output is *not* marked as safe — use `Phoenix.HTML.raw/1` when rendering
in templates, after sanitizing user content.

## Examples

    iex> doc = %{"type" => "doc", "content" => [
    ...>   %{"type" => "paragraph", "content" => [
    ...>     %{"type" => "text", "text" => "Hello"}
    ...>   ]}
    ...> ]}
    iex> EditorContent.content_to_html(doc)
    "<p>Hello</p>"

# `content_to_text`

```elixir
@spec content_to_text(map() | nil) :: String.t()
```

Extracts plain text from an editor JSON document.

Block-level nodes are separated by newlines. Useful for search indexing,
word counting, and preview generation.

## Examples

    iex> doc = %{"type" => "doc", "content" => [
    ...>   %{"type" => "paragraph", "content" => [
    ...>     %{"type" => "text", "text" => "Hello world"}
    ...>   ]},
    ...>   %{"type" => "paragraph", "content" => [
    ...>     %{"type" => "text", "text" => "Second paragraph"}
    ...>   ]}
    ...> ]}
    iex> EditorContent.content_to_text(doc)
    "Hello world\nSecond paragraph"

# `empty_document`

```elixir
@spec empty_document() :: map()
```

Returns the canonical empty document.

## Example

    iex> EditorContent.empty_document()
    %{"type" => "doc", "content" => [%{"type" => "paragraph"}]}

# `sanitize_content`

```elixir
@spec sanitize_content(
  map(),
  keyword()
) :: map()
```

Strips disallowed nodes and marks from an editor JSON document.

Nodes with disallowed types are removed entirely. Marks with disallowed types
are stripped from text nodes (text is kept). Returns the cleaned document.

## Options

  * `:allowed_nodes` — list of allowed node type strings
  * `:allowed_marks` — list of allowed mark type strings

## Examples

    iex> doc = %{"type" => "doc", "content" => [
    ...>   %{"type" => "paragraph", "content" => [%{"type" => "text", "text" => "ok"}]},
    ...>   %{"type" => "script", "content" => []}
    ...> ]}
    iex> EditorContent.sanitize_content(doc)
    %{"type" => "doc", "content" => [
      %{"type" => "paragraph", "content" => [%{"type" => "text", "text" => "ok"}]}
    ]}

# `validate_content`

```elixir
@spec validate_content(
  map(),
  keyword()
) :: {:ok, map()} | {:error, [String.t()]}
```

Validates an editor JSON document against allowed node and mark types.

Returns `{:ok, doc}` if valid, or `{:error, reasons}` with a list of issues.

## Options

  * `:allowed_nodes` — list of allowed node type strings (default: standard set)
  * `:allowed_marks` — list of allowed mark type strings (default: standard set)

## Examples

    iex> doc = %{"type" => "doc", "content" => [%{"type" => "paragraph"}]}
    iex> EditorContent.validate_content(doc)
    {:ok, doc}

    iex> doc = %{"type" => "doc", "content" => [%{"type" => "script"}]}
    iex> EditorContent.validate_content(doc)
    {:error, ["disallowed node type: script"]}

# `word_count`

```elixir
@spec word_count(map() | nil) :: non_neg_integer()
```

Counts words in an editor JSON document.

## Examples

    iex> doc = %{"type" => "doc", "content" => [
    ...>   %{"type" => "paragraph", "content" => [
    ...>     %{"type" => "text", "text" => "Hello beautiful world"}
    ...>   ]}
    ...> ]}
    iex> EditorContent.word_count(doc)
    3

---

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