Component Architecture of DrawDB: Editor Canvas and Code Editor Explained

DrawDB implements a layered React architecture where src/pages/Editor.jsx nests multiple Context providers to manage state for the visual Canvas and text-based code editors (RichEditor and DBMLEditor), enabling isolated functionality through dedicated hooks like useCanvas and useDiagram.

The drawdb-io/drawdb repository organizes its frontend as a hierarchy of specialized React components and context providers. This component architecture separates visual diagramming logic from text editing capabilities while maintaining synchronized state across the application through a centralized provider pattern.

Top-Level Provider Stack in Editor.jsx

The entry point for the drawing interface resides in src/pages/Editor.jsx. This file does not render UI directly; instead, it composes a nested stack of Context providers that wrap the Workspace component. Each provider establishes a specific domain of state—such as layout transforms, undo/redo history, or diagram entities.

According to the drawDB source code, the provider hierarchy follows this structure:

// src/pages/Editor.jsx
import LayoutContextProvider from "../context/LayoutContext";
import TransformContextProvider from "../context/TransformContext";
import TablesContextProvider from "../context/DiagramContext";
import UndoRedoContextProvider from "../context/UndoRedoContext";
import SelectContextProvider from "../context/SelectContext";
import AreasContextProvider from "../context/AreasContext";
import NotesContextProvider from "../context/NotesContext";
import TypesContextProvider from "../context/TypesContext";
import SettingsContextProvider from "../context/SettingsContext";
import SaveStateContextProvider from "../context/SaveStateContext";
import EnumsContextProvider from "../context/EnumsContext";
import WorkSpace from "../components/Workspace";

export default function Editor() {
  return (
    <SettingsContextProvider>
      <LayoutContextProvider>
        <TransformContextProvider>
          <UndoRedoContextProvider>
            <SelectContextProvider>
              <AreasContextProvider>
                <NotesContextProvider>
                  <TypesContextProvider>
                    <EnumsContextProvider>
                      <TablesContextProvider>
                        <SaveStateContextProvider>
                          <WorkSpace />
                        </SaveStateContextProvider>
                      </TablesContextProvider>
                    </EnumsContextProvider>
                  </TypesContextProvider>
                </NotesContextProvider>
              </AreasContextProvider>
            </SelectContextProvider>
          </UndoRedoContextProvider>
        </TransformContextProvider>
      </LayoutContextProvider>
    </SettingsContextProvider>
  );
}

This nesting ensures that child components can access specific contexts via custom hooks without prop drilling.

The Workspace Component

src/components/Workspace.jsx serves as the primary layout shell. It splits the interface into two main regions: the interactive diagram canvas and the side panel containing code editors. The Workspace itself remains agnostic of state management logic, consuming contexts through hooks rather than receiving props.

Editor Canvas Architecture

The Canvas component (src/components/Canvas.jsx) renders the visual database diagram using HTML5 Canvas or SVG elements. It relies on several specialized contexts:

  • TransformContext: Manages zoom levels and pan coordinates
  • DiagramContext (Tables): Stores table definitions, fields, and relationships
  • SelectContext: Tracks currently selected entities
  • AreasContext: Handles groupings and bounded regions
  • NotesContext: Manages annotation objects

Utility functions in src/utils/arrangeTables.js and src/utils/autoArrange.js calculate optimal positioning, while src/utils/calcPath.js renders relationship lines between tables.

To interact with the canvas programmatically, components use the useCanvas hook:

// src/hooks/useCanvas.js
import { useContext } from 'react';
import { CanvasContext } from '../context/CanvasContext';

export default function useCanvas() {
  const context = useContext(CanvasContext);
  if (!context) {
    throw new Error('useCanvas must be used within CanvasContextProvider');
  }
  return context;
}

Code Editor Components

DrawDB provides two distinct editing interfaces for schema manipulation:

RichEditor (SQL Editing)

src/components/LexicalEditor/RichEditor.jsx implements a syntax-highlighted SQL editor using the Lexical framework. This component integrates with UndoRedoContext to provide history management and TypesContext for auto-completion of data types.

DBMLEditor

src/components/EditorSidePanel/DBMLEditor.jsx offers a dedicated interface for DBML (Database Markup Language) syntax. Unlike the rich editor, this component typically operates as a controlled textarea with validation logic from src/utils/validateSchema.js.

State Management: Contexts and Hooks

Each domain-specific context pairs with a corresponding hook in src/hooks/:

  • useDiagram(): Accesses table and relationship state from DiagramContext
  • useUndoRedo(): Controls history stacks for reversible actions
  • useLayout(): Manages sidebar and panel visibility states
  • useSettings(): Persists user preferences to local storage

These hooks enforce type safety and provide consistent error handling when consumed outside their providers.

Utility Layer

Supporting modules in src/utils/ handle complex operations outside the React render cycle:

Summary

  • DrawDB uses a nested Context provider pattern in src/pages/Editor.jsx to manage global state without prop drilling.
  • The Workspace component serves as the layout container, hosting both visual and text editing interfaces.
  • Canvas handles diagram rendering through specialized contexts like TransformContext and DiagramContext, supported by arrangement utilities.
  • Code editing splits between RichEditor (Lexical-based SQL) and DBMLEditor for markup syntax.
  • Custom hooks (useCanvas, useDiagram, useUndoRedo) provide type-safe access to context values across the component tree.

Frequently Asked Questions

How does DrawDB manage zoom and pan functionality in the Canvas?

The zoom and pan functionality is managed through TransformContext and consumed via the useTransform hook. The context stores current scale and offset coordinates, while the Canvas component applies these values as CSS transforms or Canvas coordinate adjustments. Utility functions in src/utils/calcPath.js recalculate relationship paths when transforms change.

What is the difference between DiagramContext and CanvasContext?

DiagramContext (aliased as TablesContext in the provider hierarchy) manages the semantic data model—tables, columns, indexes, and foreign keys—while CanvasContext handles the visual representation state such as zoom levels, pan positions, and selection boxes. This separation allows the underlying data to persist independently of viewport changes.

How does DrawDB implement undo/redo functionality?

DrawDB implements undo/redo through UndoRedoContext, which maintains a history stack of immutable state snapshots. Components dispatch actions that the context reduces into new states, pushing the previous state onto an undo stack. The useUndoRedo hook exposes undo() and redo() methods that pop states from these stacks and restore previous configurations.

Which component is responsible for SQL syntax highlighting?

SQL syntax highlighting is handled by RichEditor in src/components/LexicalEditor/RichEditor.jsx. This component leverages the Lexical editor framework to provide token-based highlighting, auto-completion via TypesContext, and integrated validation through src/utils/validateSchema.js before exporting the final SQL DDL.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →