lexical-yjs-html
Renders a Lexical document to HTML from its Yjs representation, using yrs. It covers core Lexical: paragraphs, headings, quotes, code blocks, lists, tables, links, and the full text-format model. The tests pin the output byte-for-byte to fixtures captured from a live editor.
Usage
[]
= "0.1"
= { = "0.27", = ["sync"] }
The input is a Yjs update: bytes from a durable store, from a provider, or
from Y.encodeStateAsUpdate in the browser.
use Decode;
use ;
let update_bytes: = read.unwrap;
let doc = new;
doc.transact_mut
.apply_update
.unwrap;
let txn = doc.transact;
let fragment = txn.get_xml_fragment.expect;
let html = render;
// => Some("<h1>Heading One</h1><p>…</p>") — or None if the fragment
// isn't Lexical-shaped (e.g. a ProseMirror document).
One doc can hold several fragments. Pass the root name your editor binds.
render returns None when the fragment is not Lexical-shaped.
Declarative rules
A rule tells the renderer how to draw a node type the built-in schema does not know. A rule is a tag, attribute templates, and a content slot. Declarative rules render inside the document transaction. Nothing calls back into your code.
use ;
use ;
let rules = parse.unwrap;
let doc = new;
let txn = doc.transact;
let fragment = txn.get_xml_fragment.expect;
let segments = render_segments.expect;
let html = flatten.into_html.expect;
// A stored <callout kind="warning"> renders as
// <aside class="callout callout--warning">…</aside>
An attribute template joins literal parts (lit) and stored-attribute
references (ref). An attribute that resolves empty is omitted. content
is "inline" for formatted text, "blocks" for child block nodes, or
"none" for a leaf. "inline" is the default. "void": true skips the
closing tag. A rule for a built-in type replaces how that type renders.
This crate has no marks tier. Lexical keeps formatting inside its text
model, and the renderer handles that natively.
prosemirror-yjs-html has
the marks side.
Callback rules
A rule marked callback hands the node to your code. Use it for nodes that
need logic or a database lookup. Deferred nodes come back as segments with
their type, their stored attributes as JSON, and their children already
rendered. The render never runs your code. You splice the result in after
it returns.
use ;
use ;
let rules = parse.unwrap;
let doc = new;
let txn = doc.transact;
let fragment = txn.get_xml_fragment.expect;
let segments = render_segments.expect;
let html = splice;
Rules, Segment, and flatten are re-exported here.
yjs-html-core is an internal
implementation crate.
Schema discovery
Editors store types and attributes under their own names. Lexical prefixes
its own props with __. collect_node_types reports what a real document
holds:
use ;
use ;
let doc = new;
let txn = doc.transact;
let fragment = txn.get_xml_fragment.expect;
for in collect_node_types.unwrap_or_default
Anything where is_builtin is false needs a rule. Without one, the node
still renders its text and child blocks, just unwrapped.
License
MIT. Developed in yrby, where it backs
Y::Lexical and Y::Lexxy.