This page predates the current package split. Use the current package guides for checked installation, public imports, and onboarding examples. The detailed examples below have not all been revalidated.
Architecture Overview
Barocss Editor uses a model-first, DSL-first architecture. All operations work on a model, and everything (templates, marks, decorators, operations) is defined using DSL.
Core Structure
DSL-First Philosophy
In Barocss, everything is defined using DSL:
- Templates:
define('paragraph', element('p', {}, [slot('content')])) - Marks:
defineMark('bold', element('strong', {}, [data('text')]))ordefineMark('bold', external(BoldComponent)) - Decorators:
defineDecorator('highlight', element('span', {}, [])) - Operations:
defineOperationDSL('insertText', (p) => insertText({ text: p.text }))
This unified approach provides consistency, type safety, and composability across all definitions.
Dual Rendering Pipeline
The same DSL templates power two rendering targets:
Both paths share the same template definitions — you define once and render to either target.
Role of Each Layer
1. DSL Layer (packages/dsl)
Role: Functional template definition
element()- HTML element templatedata()- Data bindingwhen()- Conditional renderingcomponent()- Component templateslot()- Slot templateportal()- Portal templateexternal()- Wrap React components or DOM mount/unmount objects
All builders are pure functions.
Input: Builder parameters Output: Template
2a. VNodeBuilder (packages/renderer-dom)
Role: Convert DSL templates to VNode
- Template lookup from Registry
- Data binding (data(), className, style)
- Component resolution
- Conditional rendering (build time)
Input: Template × Model data Output: VNode tree
2b. buildToReact (packages/renderer-react)
Role: Convert DSL templates directly to ReactNode
- Same template lookup from Registry
- Same data binding and component resolution
- Supports
external(ReactComponent)for marks and blocks - No VNode intermediate — outputs ReactNode directly
Input: Template × Model data Output: ReactNode
3. DOMReconcile (packages/renderer-dom)
Role: Convert VNode differences to DOM changes
- WIP tree creation and management
- Change detection (tag, attrs, children)
- Priority-based processing
- Minimal DOM changes applied
- Children reconcile (React-style)
Input: prevVNode, nextVNode Output: DOM updates
4 Steps of Reconcile
reconcile(prevVNode, nextVNode, container, context) {
// 1. Create WIP Tree
const wipTree = createWorkInProgressTree(nextVNode, prevVNode);
// 2. Detect changes and assign priority
detectChangesAndAssignPriority(prevVNode, nextVNode);
// 3. Process by priority
processByPriority(context, processWorkInProgress);
// 4. Execute DOM updates
executeDOMUpdates(container, finalizeDOMUpdate);
}
Children Reconcile Core
// Reconciliation that directly manipulates DOM
reconcileChildren(wip, prevChildren, nextChildren) {
while (prevIndex < prevChildren.length || nextIndex < nextChildren.length) {
if (!prevChild) {
// Add new child
const newNode = createNewDOMNode(nextChild);
domNode.insertBefore(newNode, referenceNode);
// Important: Set child WIP's domNode
wip.children[nextIndex].domNode = newNode;
} else if (isSameNode(prevChild, nextChild)) {
// Same node - skip
} else {
// Replace node
const newNode = createNewDOMNode(nextChild);
domNode.replaceChild(newNode, oldNode);
wip.children[nextIndex].domNode = newNode;
}
}
}
Core Rule: DOM nodes created/replaced in reconcile must be set in child WIP's domNode to prevent duplicate append
Key Classes
| Class/Function | Layer | Role |
|---|---|---|
element, data, when, component | DSL | Template builder (pure functions) |
VNodeBuilder | VNode | DSL template → VNode conversion |
DOMReconcile | Renderer | VNode → DOM reconcile orchestration |
WorkInProgressManager | Renderer | WIP tree creation and management |
ChangeDetection | Renderer | Change detection |
DOMProcessor | Renderer | DOM manipulation (insert/update/remove) |
ComponentManager | Renderer | Component lifecycle |
PortalManager | Renderer | Portal rendering |
DOMOperations | Renderer | DOM creation/modification utilities |
Core Rules
- DSL builders define templates as pure functions
- VNodeBuilder only converts templates and data to VNode
- DOMReconcile converts VNode differences to DOM changes
- WIP pattern batches actual changes
- children reconcile must set created DOM nodes in child WIP's domNode
- finalizeDOMUpdate prevents duplicate append (
isAlreadyInDOMcheck)
Package Map
packages/
├─ schema/ # Document structure and validation
├─ datastore/ # Transactional node store (overlay/COW)
├─ model/ # Operations, transactions, undo/redo
├─ dsl/ # Declarative template builders ⭐
├─ renderer-dom/ # VNode reconciliation → DOM
├─ renderer-react/ # Direct → ReactNode (no VNode)
├─ editor-core/ # Commands, selection, extensions, history
├─ editor-view-dom/ # DOM input handling, selection sync
├─ editor-view-react/ # React view layer with hooks
├─ extensions/ # 30+ built-in extensions
├─ collaboration/ # CRDT/OT base adapter
├─ collaboration-yjs/ # Yjs adapter
├─ collaboration-liveblocks/ # Liveblocks adapter
├─ converter/ # HTML/Markdown/LaTeX/PDF conversion
├─ shared/ # Platform, keybinding, i18n utilities
├─ text-analyzer/ # Smart text diff (LCP/LCS)
├─ dom-observer/ # DOM mutation observer
└─ devtool/ # Dev tools (tree view, event log)
Usage Examples
For detailed examples, see Practical Examples
Basic Render
// Define DSL template
define('paragraph', element('p', {}, [data('text')]));
// Render
const renderer = new DOMRenderer();
const model = { stype: 'paragraph', text: 'Hello' };
renderer.render(container, model);
// Result: <p>Hello</p>
Update (Automatic Reconcile)
model.text = 'New';
renderer.render(container, model);
// Result: <p>New</p> (only text changed without full regeneration)
Complex Template
define('article', element('article',
{ className: data('className') },
[
when(
(d) => d('published') === true,
element('span', {}, ['Published'])
),
element('h1', {}, [data('title')]),
component('author', { name: data('author') })
]
));
Related Documents
- Core Concepts: Rendering - Understand the rendering pipeline
- Renderer DOM - DOM rendering with VNode reconciliation
- Renderer React - React rendering (no VNode)
- Editor View DOM - DOM view layer
- Editor View React - React view layer
- Practical Examples - Real-world usage examples