Default Implementation Overview

Throughout the tutorial, DefaultEditorComponent was a black box: hand it an editor core and a working editing interface appears. This part of the documentation opens the box. This page covers where the default implementation sits in the library, why it is built as a layer you can replace wholesale, and what that one component actually assembles for you. The pages that follow take the interface, the keyboard, the renderer factories, customization and the printer side in turn.

The two halves of the library

The library splits into two parts. One is the core: the definitions of concepts and nodes, the editor core, the printer core. They are concerned only with what a document tree is, how it gets modified and how it gets rendered, and they make no decisions about the interface. There is not a single button, not one colour, not one shortcut anywhere in the core.

The other part is the default implementation. It is one complete answer to the question of what the interface should look like: a sheet of paper, a sidebar, a row of buttons on every node, two draggable floating panels, a full keyboard scheme, and a set of typesetting widgets on the printer side. That answer takes a position. It assumes you are building an editor for long, serious documents whose structure gets manipulated often. If that is not your situation, this whole layer can go.

Where that line falls explains a design that looks odd at first sight: both the editor and the printer are split into a core object and a component object. EditorCore goes with EditorComponent, Printer goes with PrinterComponent. The core holds information but never draws; the component draws but holds nothing.

The benefit of separating them is that several components can share one core. The floating window that edits abstract nodes is a ready example: it is another editor component sharing the main editor's core, so both sides see identical concept definitions and renderers, and a theorem inserted inside a footnote goes through exactly the same code as one inserted in the body.

Three levels of depth

For you as a user, that dividing line means three levels of depth, increasing in both cost and freedom.

ApproachWhat you writeSuits
Use the default implementation as it comesConcept definitions, renderers, and a few props on DefaultEditorComponentThe large majority of cases
Modify the default implementationCustom buttons, a replaced renderer here and there, config and themeWhen you need operations or an appearance of your own
Skip the default implementationYour own interface built on EditorComponentWhen your interface differs fundamentally

Few people need the third level, but it is available: the default implementation uses no private interfaces, so everything it calls, you can call.

What DefaultEditorComponent assembles

The component itself holds almost no logic of its own. Its value is that it stacks seven or eight things that all have to be present, in an order that cannot be varied. Peeling its rendered structure from the outside in:

LayerRole
EditorConfigContext.ProviderHands the style config (fonts, margins, widths) to everything downstream; renderers read it with useEditorConfig()
SnackbarProviderThe container for toast messages, from notistack
IdxConflictSolverWatches for duplicate node indices and renumbers when it finds them
KeyEventManagerThe global key dispatcher, from @ftyyy/mouseless
EditorComponentThe editor proper, the sheet you type on
EditorGlobalInfo.ProviderHands the editor instance downstream; the sidebar, the floating panels and your own buttons all get the editor from here
DefaultSidebar / Areas / AbstractEditorAreaThe sidebar, the two floating panels, the floating editor for abstract nodes

Three of these layers deserve their own explanation.

The first is SnackbarProvider. It is here because the default implementation's buttons report success and failure with toast messages, and those need a container. Since it sits inside the editor, your own buttons can call useSnackbar() with no further setup. The other way round: raising a toast from outside the editor, from a top bar for instance, needs another SnackbarProvider further out.

The second is IdxConflictSolver. Tutorial chapter 1 established that every concept node carries an idx unique within the document, and that cross references locate their targets by it. Copy and paste breaks that uniqueness as a matter of course: copy a theorem, paste it, and the document holds two nodes with the same idx, so references point at the wrong one. This component checks after every change and renumbers one of the offenders. It is work that has to be done and that nobody wants to write, so the default implementation does it.

The third is KeyEventManager, the hub of the whole keyboard scheme. Every keystroke reaches it first and is dispatched from there to the right part of the interface. The default editor registers four groups of interface elements with it and lists the combinations whose browser default must be suppressed. That mechanism has a page of its own, Keyboard Operation.

How to read this part

The remaining five pages stand on their own and can be read as needed, roughly ordered from what you see to what you change:

PageContents
The Editing InterfaceThe paper, the eight buttons on a node, the parameter drawer, abstract nodes, the sidebar, the two floating panels, and the AreaContainer you must place yourself
Keyboard OperationThe model behind spatial navigation, every combination, and the hint mechanism
Editor Renderer FactoriesA factory per node type and its options, UniversalExtra, and the hooks available inside renderers
Customizing the Default EditorStyle config, added buttons, theme, and replacing an individual renderer
The Printer SideDefaultPrinterComponent, the printer configuration, the typesetting widgets

The source of the live demo, in the repository's demo/ directory, is a complete worked example of everything in this part. When a passage feels abstract, that is the place to compare against.