editor: The Editor

The entire editing side: EditorCore (configuration and node factory), EditorComponent (the React component and its tree operations), the plugin system, the Slate node utilities, and the editor state hooks.

EditorCore

EditorCore is the entry object of the editing side: constructed once at startup and shared from then on. Its three constructor arguments match the usage in tutorial chapter 3:

new EditorCore({
    renderers: EditorRendererDict,           // {group: {first-concept name: renderer}, ...}
    default_renderers: EditorDefaultRendererDict, // one default renderer per node kind
    printer: Printer,                        // concept definitions are queried from here
})

Its methods fall into two groups. One is the node factory (the create_ family): create new nodes by second-class concept name, with idx and placeholder children filled in automatically; use these rather than hand-written object literals when constructing document content programmatically. The other group is queries: concept lists, renderers, and the associated printer.

MethodDescription
create_text(text?) / create_paragraph(text?)Create text and paragraph nodes
create_group(name, relation?)Create a group node by second-class concept name; relation defaults to "separating"
create_inline(name, text?) / create_support(name) / create_structure(name, relation?) / create_abstract(name)Create the other concept node kinds, likewise by second-class concept name
get_sec_concept_list(type) / get_fst_concept_list(type)List the second- or first-class concept names registered under a node kind
get_first_renderer(type, fst?) / get_second_renderer(type, sec?) / get_node_renderer(node)Renderer lookup; falls back to the default renderers
get_printer()The associated printer
get_meta_param(node)The meta parameters of the node's first-class concept

EditorComponent

The editor's React component (a class component). In practice you usually mount its wrapper DefaultEditorComponent (see the defaults page); the two share one set of props:

interface EditorComponentProps {
    editorcore: EditorCore
    plugin?: EditorPlugin                 // custom plugins, stacked on top of the built-ins
    init_rootchildren?: AbstractNode["children"]        // initial document content
    init_rootproperty?: Omit<AbstractNode, "children">  // initial root properties
    onUpdate?: (v: any) => void           // called on every tree update
    onKeyDown? / onKeyUp?: (e) => void    // keyboard event callbacks
    onFocusChange?: (editor?) => void     // called when the cursor position changes
}
Instance methodDescription
get_root(): AbstractNodeAssemble the current content into a complete document tree; the entry point for saving
get_core() / get_slate()The EditorCore, and the underlying Slate editor object
get_cur_node() / get_cur_concept_node()The node at the cursor, and the nearest enclosing concept node
get_node_by_path(path)Node lookup by path
new_concept_node(type, sec_name)Insert a new node of the given second-class concept at the cursor (what the sidebar insert buttons call)
set_root(property)Modify the root node's properties
add_apply_callback(cb)Register a callback to run after the next Slate apply

Tree operations

The following methods also live on EditorComponent (mixed in; the source is in treeopmixin). They are concept-level wrappers over Slate's Transforms, and they are what plugins and custom buttons mostly deal with:

MethodDescription
set_node(node, partial) / set_node_by_path(path, partial)Modify node properties
auto_set_parameter(node, parameters)Modify node parameters, handling proxy nodes automatically
add_nodes(nodes, path) / add_nodes_here(nodes)Insert nodes at a path, or at the cursor
add_nodes_before(nodes, target) / add_nodes_after(nodes, target)Insert before or after a target node
delete_concept_node(node) / delete_node_by_path(path) / delete_nodes_by_paths(paths)Delete nodes. The batch version deletes by explicit paths without depending on the current selection (so it works in focus-free contexts such as effects); invalid paths are ignored silently
unwrap_node(node)Delete a node but keep its children
move_concept_node(node, posto) / move_node_by_path(from, to)Move nodes
replace_nodes(father, nodes)Replace all children of a node
wrap_selected_nodes(node, opts) / wrap_nodes(node, from, to, opts)Wrap the selection, or a given range, into a new node

Editor renderers

An editor renderer is at bottom just a React component, receiving the editor, the node, and the child content:

type EditorRenderer<NT extends Node = Node> =
    (props: EditorRendererProps<NT>) => React.ReactElement

interface EditorRendererProps<NT> {
    editor: EditorComponent
    node: NT
    children: React.ReactNode   // content supplied by Slate; the renderer must output it
}

This is the raw form of an editor renderer. It is rarely written by hand; the factory functions of the default implementation generate renderers with buttons and parameter editing already handled.

The plugin system

A plugin is a function that wraps the Slate editor:

type EditorPlugin =
    (editor: EditorComponent, slate: SlateReact.ReactEditor) => SlateReact.ReactEditor

A plugin receives the editor and the Slate editor object and returns the modified Slate editor, matching the plugin pattern of the Slate ecosystem. How to write one is covered in tutorial chapter 7. Related exports:

Slate node utilities

Functions for inspecting Slate nodes in plugins and buttons, all prefixed slate_:

FunctionDescription
slate_is_concept(node, type?)Whether the node is a concept node; the second argument narrows the kind
slate_is_paragraph / slate_is_textParagraph and text checks
slate_get_node_type(node)The node's type string
slate_is_same_concept_node(a, b)Whether two references point to the same node, compared by idx
slate_concept_node2path(root, node)The node's path within the tree
slate_concept_father(root, node) / slate_concept_father_path(root, path)The nearest concept ancestor
slate_idx_to_node(root, idx)Find a node by idx

Editor state hooks

For components outside the editor (a toolbar placed elsewhere on the page, say) that need to track editor state:

HookDescription
useEditor()The current EditorComponent, inside editor renderers; throws outside the editor context
useCurEditor()The current editor from anywhere, built on Zustand, refreshing with the editor version
useCurConceptNode()The concept node at the cursor; re-renders when it changes
useCurConceptNodeIdxParam()Same, but re-renders only when the node's idx or parameters change; cheaper
useEditorStateThe underlying Zustand store, for finer subscription control