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 |
|---|---|---|
| Block | paragraph, heading, image, table, form | Vertical stacking elements |
| Inline | text | 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
- Text Splitting - Split at END offset first, then START (preserves positions)
- Normalization - Merge adjacent text nodes with identical marks
- Loose Equality - Compare marks only, ignore text content when merging
- 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"}
]
endPackage Structure
quillon/ # Core - pure Elixir (this library)
quillon_live/ # LiveView components/hooks
quillon_grove/ # Grove CRDT integrationDocumentation
- Document Model - Full architecture spec
- Roadmap - Development phases
License
MIT