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.
Model API
The Model API provides high-level model operations, transaction DSL, and operation definitions.
Transaction DSL
transaction(editor, operations)
Creates a transaction builder.
Parameters:
editor: Editor- Editor instanceoperations: (TransactionOperation | TransactionOperation[] | OpFunction)[]- Operations to execute
Returns:
TransactionBuilder- Transaction builder instance
Example:
import { transaction, control, insertText } from '@barocss/model';
const result = await transaction(editor, [
...control('text-1', [
insertText(5, 'Hello')
])
]).commit();
TransactionBuilder
Transaction builder interface.
commit(): Promise<TransactionResult>
Commits the transaction.
Returns:
Promise<TransactionResult>- Transaction result
Behavior:
- Triggers
onBeforeTransactionhooks (extensions can intercept/modify) - Executes all operations
- Commits to DataStore
- Adds to history
- Emits
editor:content.changeevent - Triggers
onTransactionhooks
Example:
const result = await transaction(editor, operations).commit();
if (result.success) {
console.log('Transaction succeeded:', result.transactionId);
} else {
console.error('Transaction failed:', result.errors);
}
TransactionResult
interface TransactionResult {
success: boolean; // Whether transaction succeeded
errors: string[]; // Array of error messages
data?: any; // Transaction data
transactionId?: string; // Transaction ID
operations?: TransactionOperation[]; // Executed operations
selectionBefore?: ModelSelection | null; // Selection before transaction
selectionAfter?: ModelSelection | null; // Selection after transaction
}
Control Function
control(target, actions)
Injects nodeId into operation payloads.
Parameters:
target: HandleOrId- Target node IDactions: Array<{ type: string; payload?: any }>- Operations to inject nodeId into
Returns:
TransactionOperation[]- Operations with injected nodeId
Example:
control('text-1', [
insertText(5, 'Hello'),
toggleMark('bold', [0, 10])
])
// Becomes:
[
{ type: 'insertText', payload: { nodeId: 'text-1', pos: 5, text: 'Hello' } },
{ type: 'toggleMark', payload: { nodeId: 'text-1', markType: 'bold', range: [0, 10] } }
]
Node Creation Helpers
node(stype, attributes?, content?)
Creates a container node.
Parameters:
stype: string- Node typeattributes?: Record<string, any>- Optional attributescontent?: INode[]- Optional child nodes
Returns:
INode- Node object
Example:
const paragraph = node('paragraph', {}, [
textNode('inline-text', 'Hello')
]);
textNode(stype, text, marks?, attributes?)
Creates a text node.
Overloads:
textNode(stype: string, text: string): INode
textNode(stype: string, text: string, marks: MarkDescriptor[]): INode
textNode(stype: string, text: string, attributes: Record<string, any>): INode
textNode(stype: string, text: string, marks: MarkDescriptor[], attributes: Record<string, any>): INode
Parameters:
stype: string- Node typetext: string- Text contentmarks?: MarkDescriptor[]- Optional marksattributes?: Record<string, any>- Optional attributes
Returns:
INode- Text node object
Example:
// Basic text node
const text = textNode('inline-text', 'Hello');
// Text node with marks
const boldText = textNode('inline-text', 'Hello', [
mark('bold', { range: [0, 5] })
]);
// Text node with attributes
const styledText = textNode('inline-text', 'Hello', {
color: 'red'
});
// Text node with marks and attributes
const richText = textNode('inline-text', 'Hello', [
mark('bold', { range: [0, 5] })
], {
color: 'red'
});
mark(stype, attrs?)
Creates a mark descriptor.
Parameters:
stype: string- Mark typeattrs?: Record<string, any>- Optional attributes (can includerange)
Returns:
MarkDescriptor- Mark descriptor
Example:
// Basic mark
const boldMark = mark('bold');
// Mark with attributes
const linkMark = mark('link', {
href: 'https://example.com',
target: '_blank'
});
// Mark with range
const boldRange = mark('bold', {
range: [0, 5]
});
Operation Definition
defineOperation(name, executor, selectionMapper?)
Defines a custom operation.
Parameters:
name: string- Operation nameexecutor: (operation: T, context: TransactionContext) => Promise<void | INode>- Operation executorselectionMapper?: (operation: T, context: TransactionContext) => any- Optional selection mapper
Example:
import { defineOperation } from '@barocss/model';
import type { TransactionContext } from '@barocss/model';
defineOperation('customOp', async (operation, context) => {
const { nodeId, data } = operation.payload;
// Access DataStore
const node = context.dataStore.getNode(nodeId);
// Perform operation
context.dataStore.updateNode(nodeId, data);
// Map selection if needed
if (context.selection?.current) {
// Update selection
}
// Return result with inverse
return {
ok: true,
data: context.dataStore.getNode(nodeId),
inverse: { type: 'customOp', payload: { nodeId, data: oldData } }
};
});
See: Custom Operations Guide for detailed examples.
defineOperationDSL(builder, options?)
Defines a DSL helper for an operation.
Parameters:
builder: BuilderFn<Args, P>- Builder functionoptions?: DefineOperationDSLOptions- Optional options
Returns:
- DSL helper function
Example:
import { defineOperationDSL } from '@barocss/model';
export const customOp = defineOperationDSL(
(nodeId: string, data: Record<string, any>) => ({
type: 'customOp',
payload: { nodeId, data }
}),
{ atom: false, category: 'custom' }
);
// Usage
const ops = control('node-1', [
customOp({ key: 'value' })
]);
Options:
interface DefineOperationDSLOptions {
atom?: boolean; // Whether operation is atomic
category?: string; // Operation category
}
See: Model Operation DSL API for complete DSL helper reference.
Functional DSL
op(operationFn)
Creates a functional operation.
Parameters:
operationFn: (context: TransactionContext) => OpResult | void | Promise<OpResult | void>- Operation function
Returns:
OpFunction- Functional operation
Example:
import { op } from '@barocss/model';
const result = await transaction(editor, [
op(async (context) => {
// Custom logic
const node = context.dataStore.getNode('node-1');
context.dataStore.updateNode('node-1', { text: 'Updated' });
return {
success: true,
data: context.dataStore.getNode('node-1'),
inverse: { type: 'update', payload: { nodeId: 'node-1', data: node } }
};
})
]).commit();
OpResult
interface OpResult {
success: boolean;
data?: any;
error?: string;
inverse?: TransactionOperation; // Inverse operation for undo
}
Transaction Context
Operations receive a TransactionContext:
interface TransactionContext {
dataStore: DataStore; // DataStore instance
selectionManager: SelectionManager; // SelectionManager instance
selection: SelectionContext; // Selection context (before/current)
schema?: Schema; // Active schema
}
SelectionContext
class SelectionContext {
before: ModelSelection | null; // Selection before transaction
current: ModelSelection | null; // Current selection (mutable)
}
Example:
defineOperation('myOp', async (operation, context) => {
// Access selection
const before = context.selection.before;
const current = context.selection.current;
// Update selection
if (context.selection.current) {
context.selection.current.startOffset += 5;
}
// Access DataStore
const node = context.dataStore.getNode('node-1');
// Access schema
const nodeType = context.schema?.getNodeType('paragraph');
});
Transaction Manager
TransactionManager Class
Manages transaction execution.
Constructor
new TransactionManager(editor: Editor)
Parameters:
editor: Editor- Editor instance
Methods
execute(operations: (TransactionOperation | OpFunction)[]): Promise<TransactionResult>
Executes a transaction.
Parameters:
operations: (TransactionOperation | OpFunction)[]- Operations to execute
Returns:
Promise<TransactionResult>- Transaction result
Behavior:
- Acquires global lock
- Begins transaction
- Starts DataStore overlay
- Executes all operations
- Ends overlay and commits
- Adds to history
- Emits events
- Calls after hooks
Note: Usually called via transaction().commit(), not directly.
setSchema(schema: Schema): void
Sets the active schema.
Parameters:
schema: Schema- Schema instance
Position Calculator
Calculates positions in the document.
PositionCalculator Class
import { PositionCalculator } from '@barocss/model';
Constructor
new PositionCalculator(dataStore: DataStore)
Parameters:
dataStore: DataStore- DataStore instance
Methods
calculateAbsolutePosition(nodeId: string, offset: number): number
Calculates absolute position from node ID and offset.
Parameters:
nodeId: string- Node IDoffset: number- Offset in node
Returns:
number- Absolute position
resolveAbsolutePosition(absolutePos: number): { nodeId: string; offset: number } | null
Resolves absolute position to node ID and offset.
Parameters:
absolutePos: number- Absolute position
Returns:
{ nodeId: string; offset: number } | null- Node ID and offset ornull
Operation Registry
Global Operation Registry
Operations are registered in a global registry.
globalOperationRegistry
Global operation registry instance.
Methods:
register(name: string, definition: OperationDefinition): voidget(name: string): OperationDefinition | undefinedgetAll(): Map<string, OperationDefinition>clear(): void
Example:
import { globalOperationRegistry } from '@barocss/model';
// Get all operations
const allOps = globalOperationRegistry.getAll();
// Get specific operation
const insertTextOp = globalOperationRegistry.get('insertText');
DSL Operation Registry
DSL operations are registered separately.
getDefinedDSLOperations(): ReadonlyMap<string, { options?: DefineOperationDSLOptions }>
Gets all defined DSL operations.
Returns:
ReadonlyMap<string, { options?: DefineOperationDSLOptions }>- Map of DSL operations
Example:
import { getDefinedDSLOperations } from '@barocss/model';
const dslOps = getDefinedDSLOperations();
for (const [name, config] of dslOps) {
console.log(`DSL Operation: ${name}`, config);
}
Complete Examples
Example 1: Simple Transaction
import { transaction, control, insertText } from '@barocss/model';
const result = await transaction(editor, [
...control('text-1', [
insertText(5, 'Hello')
])
]).commit();
if (result.success) {
console.log('Text inserted successfully');
}
Example 2: Complex Transaction
import { transaction, control, insertText, toggleMark, create } from '@barocss/model';
const result = await transaction(editor, [
// Create new paragraph
create('paragraph', {}, [
{ stype: 'inline-text', text: 'New paragraph' }
]),
// Insert text and apply mark
...control('text-1', [
insertText(5, ' World'),
toggleMark('bold', [0, 11])
])
]).commit();
Example 3: Custom Operation
import { defineOperation, defineOperationDSL } from '@barocss/model';
// Define operation
defineOperation('highlight', async (operation, context) => {
const { nodeId, range, color } = operation.payload;
// Apply highlight
context.dataStore.mark.setMarks(nodeId, [
{
type: 'highlight',
range,
attrs: { color }
}
]);
return {
ok: true,
data: context.dataStore.getNode(nodeId),
inverse: { type: 'removeHighlight', payload: { nodeId, range } }
};
});
// Define DSL helper
export const highlight = defineOperationDSL(
(range: [number, number], color: string) => ({
type: 'highlight',
payload: { range, color }
})
);
// Use in transaction
const result = await transaction(editor, [
...control('text-1', [
highlight([0, 10], 'yellow')
])
]).commit();
Example 4: Functional Operation
import { transaction, op } from '@barocss/model';
const result = await transaction(editor, [
op(async (context) => {
// Complex multi-step operation
const node1 = context.dataStore.getNode('node-1');
const node2 = context.dataStore.getNode('node-2');
// Swap nodes
context.dataStore.content.moveNode('node-1', node2.parentId, 0);
context.dataStore.content.moveNode('node-2', node1.parentId, 0);
return {
success: true,
data: { swapped: true },
inverse: {
type: 'swapNodes',
payload: { node1: 'node-1', node2: 'node-2' }
}
};
})
]).commit();
Related
- Operations Overview - Understanding the operation hierarchy
- Model Operations API - Complete Model operation reference
- Model Operation DSL API - Complete DSL helper reference
- Custom Operations Guide - Creating custom operations
- DataStore Operations API - DataStore layer operations