Quick reference for Quillon's nodes, marks, and functions.

Node Types

Generic Constructor

Build a node of any type, including a custom type:

new(type, attrs)            # => {:line, %{page: 2}, []}
new(type, attrs, children)  # children list, or a string for text content

Container

TypeFactoryAttrs
:documentdocument(), document(children), document(attrs, children)-

Blocks

TypeFactoryAttrs
:paragraphparagraph(), paragraph(content), paragraph(content, opts)align, spacing, indent, font_size, line_height, color, background, border
:headingheading(level), heading(level, content), heading(level, content, opts)level (required), align, spacing, indent, font_weight, color, background, border
:dividerdivider(), divider(style), divider(style, opts)style (:solid, :dashed, :dotted), spacing, color, opacity
:blockquoteblockquote(), blockquote(children), blockquote(children, citation_or_opts), blockquote(children, citation, opts)citation, spacing, indent, color, background, border, border_color
:calloutcallout(type), callout(type, children), callout(type, children, title_or_opts), callout(type, children, title, opts)type (required), title, spacing, background, border, rounded
:code_blockcode_block(code), code_block(code, language), code_block(code, language, opts)code (required), language, width, spacing, font_size, background, border, rounded
:imageimage(src), image(src, alt), image(src, alt, opts)src (required), alt, caption, width, align, spacing, background, border, rounded, shadow, opacity
:videovideo(src), video(src, opts)src (required), poster, align, width, spacing, background, border, rounded, shadow
:bullet_listbullet_list(), bullet_list(items), bullet_list(items, opts)spacing, indent
:ordered_listordered_list(), ordered_list(items), ordered_list(items, start_or_opts), ordered_list(items, start, opts)start (default: 1), spacing, indent
:tabletable(), table(rows), table(rows, opts)width, spacing, border, rounded, shadow
:rowrow(), row(children), row(children, opts)justify, items, wrap, gap
:gridgrid(), grid(children), grid(children, opts)columns, gap

List Content

TypeFactoryAttrs
:list_itemlist_item(), list_item(children)-

Table Content

TypeFactoryAttrs
:table_rowtable_row(), table_row(cells), table_row(cells, opts)header (default: false)
:table_celltable_cell(), table_cell(children), table_cell(children, opts)colspan, rowspan (default: 1), align, valign, background, border

Inline

TypeFactoryAttrs
:texttext(content), text(content, marks)text (required), marks (default: [])

Marks

Simple Marks (atoms)

MarkDescription
:boldBold text
:italicItalic text
:underlineUnderlined text
:strikeStrikethrough text
:codeInline code
:subscriptSubscript (H₂O)
:superscriptSuperscript (x²)

Attributed Marks (tuples)

MarkAttrsExample
:linkhref (required), title, target{:link, %{href: "https://example.com"}}
:highlightcolor (required){:highlight, %{color: "yellow"}}
:font_colorcolor (required){:font_color, %{color: "#ff0000"}}
:mentionid, type, label (all required){:mention, %{id: "123", type: "user", label: "@alice"}}

Mark Exclusions

  • :subscript and :superscript exclude each other
  • :code excludes :link

Formatting Commands

block here means a :paragraph or :heading — the block types whose children are inline text. Passing any other node raises FunctionClauseError.

Simple Mark Toggles

toggle_bold(block, start, end)
toggle_italic(block, start, end)
toggle_underline(block, start, end)
toggle_strike(block, start, end)
toggle_code(block, start, end)
toggle_subscript(block, start, end)
toggle_superscript(block, start, end)

Attributed Mark Commands

set_link(block, start, end, href_or_attrs)
unset_link(block, start, end)

set_highlight(block, start, end, color)
unset_highlight(block, start, end)

set_font_color(block, start, end, color)
unset_font_color(block, start, end)

set_mention(block, start, end, attrs)
unset_mention(block, start, end)

Utility Commands

clear_formatting(block, start, end)          # clears the default schema's marks
clear_formatting(block, start, end, schema)  # also clears your own mark types
selection_has_mark?(block, start, end, mark_type)

Transform

The primitives the formatting commands are built from. block means a :paragraph or :heading, as above; normalize/1 has the same restriction.

apply_mark(block, start, end, mark)
remove_mark(block, start, end, mark_type)
toggle_mark(block, start, end, mark)
range_has_mark?(block, start, end, mark_type)
normalize(block)                          # merge adjacent text, drop empty

split_at_offset(children, offset)         # => [node, node]
split_range(children, start, end)
offset_to_position(children, offset)      # => {index, offset_in_node}
position_to_offset(children, position)    # => offset
sort_marks(marks)                         # => [:bold, :italic]

Path Operations

Path-based

get(node, path)                    # {:ok, node} | {:error, :invalid_path}
update(node, path, fun)            # {:ok, node} | {:error, :invalid_path}
insert(node, path, new_node)       # {:ok, node} | {:error, :invalid_path}
delete(node, path)                 # {:ok, node} | {:error, :invalid_path}
move(node, from_path, to_path)     # {:ok, node} | {:error, :invalid_path}
reorder(node, path, id_list)       # {:ok, node} | {:error, :invalid_path}

ID-based

find_path(node, id)                # {:ok, path} | {:error, :not_found}
get_by_id(node, id)                # {:ok, node} | {:error, :not_found}
update_by_id(node, id, fun)        # {:ok, node} | {:error, :not_found}

Node Inspection

Accessors

type(node)      # => :paragraph
attrs(node)     # => %{level: 1}
children(node)  # => [...]

Predicates

node?(value)         # Is it a valid node tuple?
block?(node)         # Is it a block type? (default schema)
block?(node, schema) # ...according to your schema
inline?(node)        # Is it an inline type?
inline?(node, schema)
container?(node)     # Is it a container type?
container?(node, schema)

# Specific type checks
document?(node)
paragraph?(node)
heading?(node)
divider?(node)
blockquote?(node)
callout?(node)
code_block?(node)
image?(node)
video?(node)
bullet_list?(node)
ordered_list?(node)
list?(node)          # bullet_list or ordered_list
list_item?(node)
table?(node)
table_row?(node)
table_cell?(node)
text?(node)
row?(node)
grid?(node)

Mark Utilities

mark?(value)              # Is it a valid mark?
simple?(mark)             # Is it a simple mark (atom)?
attributed?(mark)         # Is it an attributed mark (tuple)?
mark_type(mark)           # Get the type (:bold, :link, etc.)
mark_attrs(mark)          # Get attrs (empty map for simple marks)

has_mark?(marks, type)    # Does the list contain this mark type?
get_mark(marks, type)     # Get the mark from the list
add_mark(marks, mark)     # Add mark to list
remove_mark(marks, type)  # Remove mark from list
toggle_mark(marks, mark)  # Toggle mark in list
marks_equal?(m1, m2)      # Compare two mark lists

JSON Serialization

to_json(node)             # => %{"type" => "...", "attrs" => %{}, "children" => [...]}
from_json(json)           # => {:ok, node} | {:error, message}
from_json(json, opts)
from_json!(json)          # => node | raises ArgumentError
from_json!(json, opts)

opts accepts :schema, :extra_types and :extra_marks to decode custom node and mark types:

from_json(json, extra_types: [:line])

Custom Node Types

A custom node type decoded with :extra_types is first-class through the offset and mark layers: it is transparent to offset math, mark commands recurse into its :text descendants, and it is never split. Full rules: Extensibility.

{:ok, para} = from_json(json, extra_types: [:line])
# => {:paragraph, %{}, [{:line, %{page: 2}, [{:text, %{text: "Hello", marks: []}, []}]}]}

toggle_bold(para, 0, 5)
# => {:paragraph, %{}, [{:line, %{page: 2}, [{:text, %{text: "Hello", marks: [:bold]}, []}]}]}

Schema Validation

validate(node)              # {:ok, node} | {:error, errors}
validate(node, schema)      # with custom schema
validate!(node)             # node | raises
validate!(node, schema)     # with custom schema

Table Commands

add_row(table, index)
remove_row(table, index)
add_column(table, index)
remove_column(table, index)

List Commands

toggle_list_type(list)    # bullet_list <-> ordered_list

Type Constants

container_types()         # [:document]
block_types()             # [:paragraph, :heading, ...]
inline_types()            # [:text]
list_content_types()      # [:list_item]
table_content_types()     # [:table_row]
table_row_content_types() # [:table_cell]
node_types()              # All node types

simple_marks()            # [:bold, :italic, ...]
attributed_marks()        # [:link, :highlight, ...]
all_marks()               # All mark types

heading_levels()          # 1..6
divider_styles()          # [:solid, :dashed, :dotted]
callout_types()           # [:info, :warning, :success, :error]
link_attrs()              # [:href, :title, :target]
highlight_attrs()         # [:color]
font_color_attrs()        # [:color]
mention_attrs()           # [:id, :type, :label]

# Layout property values
align_values()            # [:left, :center, :right, :justify]
width_values()            # [:narrow, :default, :wide, :full]
spacing_values()          # [:none, :xs, :sm, :md, :lg, :xl]
indent_range()            # 0..5
valign_values()           # [:top, :middle, :bottom]

# Styling property values
font_size_values()        # [:xs, :sm, :base, :lg, :xl, :"2xl", :"3xl"]
font_weight_values()      # [:light, :normal, :medium, :semibold, :bold]
line_height_values()      # [:tight, :snug, :normal, :relaxed, :loose]
color_values()            # [:default, :muted, :accent, :success, :warning, :danger]
background_values()       # [:none, :subtle, :muted, :accent, :success, :warning, :danger]
border_values()           # [:none, :thin, :medium, :thick]
border_color_values()     # [:default, :muted, :accent]
border_style_values()     # [:solid, :dashed, :dotted]
opacity_values()          # [:full, :high, :medium, :low, :faint]
shadow_values()           # [:none, :sm, :md, :lg]
rounded_values()          # [:none, :sm, :md, :lg, :full]

# Container layout property values
justify_values()          # [:start, :center, :end, :between, :around, :evenly]
items_values()            # [:start, :center, :end, :stretch, :baseline]
wrap_values()             # [:nowrap, :wrap, :reverse]
gap_values()              # [:none, :xs, :sm, :md, :lg, :xl]
columns_range()           # 1..6