# Core Functionalities of @openmaic/editor Package: Three-Layer Architecture Explained

> Discover the core functionalities of the @openmaic/editor package. Understand its three-layer architecture: core, React, and UI, all powered by a unified transaction system for modular editing.

- Repository: [MAIC/OpenMAIC](https://github.com/THU-MAIC/OpenMAIC)
- Tags: deep-dive
- Published: 2026-09-02

---

**The @openmaic/editor package provides a modular editing engine split into core (document/transaction logic), React (framework bindings), and UI (ready-to-use components) layers that share a unified transaction system.**

The `@openmaic/editor` package serves as the central editing engine of [OpenMAIC](https://github.com/THU-MAIC/OpenMAIC), an open-source academic content creation platform developed by Tsinghua University. Understanding the `@openmaic/editor` core functionalities helps developers integrate rich text and slide editing capabilities at the appropriate abstraction level for their use case.

## Three-Layer Architecture Overview

The `@openmaic/editor` package implements a deliberate **layered onion pattern** with three interoperable sub-packages. Each layer exposes a focused API while sharing a common data model and transaction system.

| Layer | Package Path | Purpose |
|-------|--------------|---------|
| **Core** | `@openmaic/editor/core` | Document representation, transaction creation, undo/redo history, selection management |
| **React** | `@openmaic/editor/react` | React-specific shortcuts, selection primitives, hooks for state management |
| **UI** | `@openmaic/editor/ui` | High-level components including toolbars, insertion menus, and editable canvas |

According to the [package README](https://github.com/THU-MAIC/OpenMAIC/blob/main/packages/@openmaic/editor/README.md), this separation ensures that **low-level editing operations remain framework-agnostic** while higher layers provide convenient abstractions for React applications.

## Core Layer: Transaction Engine and Document Model

The `@openmaic/editor/core` sub-package contains pure TypeScript data structures with **no UI or framework dependencies**. This enables usage in Node.js scripts, test environments, or alternative frontend frameworks.

### Primary Core APIs

- **`createEditorTransaction`** – Constructs a transaction object describing document changes
- **`applyEditorTransaction`** – Applies a transaction to a document, returning a new immutable state
- **`createEditorHistory`** – Initializes undo/redo history management
- **Document tree queries** – Methods for navigating and inspecting the hierarchical document structure

The transaction system powers **history replay**, enabling robust undo/redo functionality and laying groundwork for collaborative editing scenarios. All state changes in `@openmaic/editor` follow this immutable transaction pattern.

### Framework-Agnostic Design

The core layer's independence from React means developers can:

- Run document transformations in server-side Node.js processes
- Integrate with Vue, Svelte, or other frameworks
- Write deterministic tests without DOM dependencies

This separation of concerns is verified in [[`tests/packages/editor-manifest.test.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/tests/packages/editor-manifest.test.ts)](https://github.com/THU-MAIC/OpenMAIC/blob/main/tests/packages/editor-manifest.test.ts), which confirms the three layers build and export correctly.

## React Layer: Framework Bindings and Selection Primitives

The `@openmaic/editor/react` sub-package provides **thin adapters** that bridge the core transaction model with React's rendering lifecycle and state management patterns.

### Key React Exports

- **`EMPTY_SELECTION`** – Sentinel value representing no active selection
- **`Selection`** type – TypeScript interface for cursor and range selections
- **`useEditorHistory`** hook – React hook integrating `createEditorHistory` with component state
- Transaction dispatch utilities for React state updates

These primitives allow React components to participate in the transaction system without directly managing the underlying document immutable updates.

## UI Layer: Ready-to-Use Editing Components

The `@openmaic/editor/ui` sub-package delivers **full React components** that render complete editing surfaces. These components consume core APIs internally while exposing declarative props for common use cases.

### Primary UI Components

- **`EditableSlideCanvasWithUI`** – Full editing canvas with integrated toolbar and insertion menus
- **`EditorInsertItem`** – Configuration object for items that can be inserted into documents
- **UI-related hooks** – Pre-built hooks for common interaction patterns

The UI layer implements **declarative insertion defaults**: toolbar and menu components automatically generate appropriate `EditorInsertItem` objects that the core transaction engine processes. This abstraction hides transaction complexity from typical UI development workflows.

## Shared Transaction Format: The Unifying Abstraction

All three layers share a **single `EditorTransaction` format**. This design decision enables seamless movement between abstraction levels:

- A UI component's toolbar button generates the same transaction structure as a programmatic server-side script
- History state captured at the UI layer can be replayed through core APIs
- Custom components can inject transactions directly into the dispatch pipeline

This consistency is demonstrated in [`scripts/smoke-test-package-tarballs.mjs`](https://github.com/THU-MAIC/OpenMAIC/blob/main/scripts/smoke-test-package-tarballs.mjs), which verifies typical imports work correctly across all layers.

## Practical Usage Examples

### Low-Level Core Transaction

```typescript
// Programmatic document editing without React
import { createEditorTransaction, applyEditorTransaction } from '@openmaic/editor/core';

const tx = createEditorTransaction({
  steps: [{ type: 'insertParagraph', position: 0 }]
});

const newDoc = applyEditorTransaction(currentDoc, tx);

```

### React Integration with History Management

```tsx
import { EMPTY_SELECTION } from '@openmaic/editor/react';
import { useEditorHistory } from '@openmaic/editor/react';
import { EditableSlideCanvasWithUI } from '@openmaic/editor/ui';

export default function SlideEditor({ initialDoc }) {
  const { history, dispatch } = useEditorHistory(initialDoc);

  return (
    <EditableSlideCanvasWithUI
      doc={history.currentDoc}
      onTransaction={dispatch}
      selection={EMPTY_SELECTION}
    />
  );
}

```

### Custom Insertion Control

```tsx
import { EditorInsertItem } from '@openmaic/editor/ui';

function InsertMathBlock({ onInsert }) {
  const mathItem: EditorInsertItem = {
    type: 'math',
    content: '\\sum_{i=0}^{n} x_i'
  };
  
  return (
    <button onClick={() => onInsert(mathItem)}>
      Insert Equation
    </button>
  );
}

```

## Extensibility Features

The `@openmaic/editor` architecture supports **custom element adapters** through its extension points:

- **Built-in adapters** handle standard OpenMAIC elements: text blocks, mathematical expressions, images, and structured containers
- **Custom adapter registration** allows third-party developers to add new element types that integrate with the transaction system and UI components
- **Adapter interface** specifies how to serialize, render, and transform custom elements within the document model

This extensibility ensures the editing engine accommodates domain-specific content without core modifications.

## Summary

- **Three-layer architecture**: Core (framework-agnostic), React (bindings), UI (components) – each importable separately via `@openmaic/editor/*`
- **Unified transaction system**: `createEditorTransaction` and `applyEditorTransaction` power all state changes across layers
- **Immutable document model**: All edits produce new document states, enabling undo/redo via `createEditorHistory`
- **React integration**: `EMPTY_SELECTION`, `Selection` type, and `useEditorHistory` hook bridge core and component layers
- **Production-ready components**: `EditableSlideCanvasWithUI` provides complete editing surfaces with minimal configuration
- **Extensible element system**: Custom adapters integrate new content types into the transaction and rendering pipeline

## Frequently Asked Questions

### What is the difference between @openmaic/editor/core and @openmaic/editor/react?

The **core** sub-package contains pure TypeScript logic for documents and transactions with no framework dependencies, usable in Node.js or any frontend framework. The **React** sub-package provides React-specific bindings including hooks and selection primitives that connect core functionality to React's component lifecycle. Choose core for headless editing or alternative frameworks; choose React for standard React applications.

### How does the transaction system enable undo/redo functionality?

Every state change in `@openmaic/editor` creates an `EditorTransaction` object describing the operation. The `createEditorHistory` function maintains a stack of these transactions alongside document snapshots. Undo pops and inverts the most recent transaction; redo reapplies previously undone transactions. This approach also supports future collaborative editing through operational transformation of transaction sequences.

### Can I use @openmaic/editor without React?

Yes. The `@openmaic/editor/core` sub-package has zero React dependencies. You can create transactions with `createEditorTransaction`, apply them with `applyEditorTransaction`, and manage history through `createEditorHistory` in any JavaScript or TypeScript environment including Node.js servers, Vue applications, or vanilla JavaScript projects.