A pure Elixir library for structured document representation with rich text support, similar to ProseMirror/Tiptap/Slate in the JavaScript ecosystem.

Core Concepts

AST Structure

Documents are trees of nodes represented as tuples:

{type, attrs, children}

# Example
{:paragraph, %{}, [{:text, %{text: "Hello", marks: [:bold]}, []}]}

Element Types

TypeExamplesDescription
Blockparagraph, heading, image, table, formVertical stacking elements
InlinetextText nodes with marks, flow within blocks

Marks System

Marks apply formatting to text nodes. Not markdown - structured data:

# Simple marks (atoms)
:bold, :italic, :underline, :strike, :code, :subscript, :superscript

# Marks with attributes (tuples)
{:link, %{href: "https://example.com"}}
{:highlight, %{color: "yellow"}}
{:mention, %{id: "user_123", type: :user}}

Mark Configuration

OptionPurpose
inclusiveNew text at mark boundary inherits mark
keep_on_splitMark persists when Enter splits node
excludesMutually exclusive marks (e.g., code excludes bold)

Key Algorithms

  1. Text Splitting - Split at END offset first, then START (preserves positions)
  2. Normalization - Merge adjacent text nodes with identical marks
  3. Loose Equality - Compare marks only, ignore text content when merging
  4. Schema Validation - Content expressions like "block+", "inline*"

Architecture Decisions

DecisionRationale
No Grove dependencySync is separate concern; users may not need CRDT
No LiveView dependencyKeep core pure Elixir; framework-agnostic
Extensible schemaSupport future extensions (markdown, math, custom blocks)

Installation

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

Package Structure

quillon/           # Core - pure Elixir (this library)
quillon_live/      # LiveView components/hooks
quillon_grove/     # Grove CRDT integration

Documentation

License

MIT