Quillon

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

Type Examples Description
Blockparagraph, heading, image, table, form Vertical stacking elements
Inlinetext Text 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

Option Purpose
inclusive New text at mark boundary inherits mark
keep_on_split Mark persists when Enter splits node
excludes Mutually 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

Decision Rationale
No Grove dependency Sync is separate concern; users may not need CRDT
No LiveView dependency Keep core pure Elixir; framework-agnostic
Extensible schema Support 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