Skip to content
QuireKit MSFE
Developer docs
v0.0.0 · Experimental

Projection layers and component lifetime

Implement inline decoration, multiline previews, declared dependencies and measurement.

Source, descriptions and DOM

A codec interprets source; a projection builds declarative descriptions from accepted inputs; a renderer creates DOM or framework components. Never initialize charts, fetch data or dispatch transactions from build().

OutputTypical useConstraint
markHighlighting and annotationsCanonical source coordinates
lineNative paragraph/container stylesAnchor at the line start
widgetControls and hintsMust not own body input
replace + textSource-neutral literal displayText is not interpreted as HTML
replace + viewDiagrams and previewsMultiline structure requires a block layer

Inline versus block

An inline layer works within bounded visible source and must not return multiline structural replacements. Block output is provided before CodeMirror computes its viewport and may affect multiline geometry.

A source NodeView's placement: 'replace' | 'before' is an inline view contract, not an arbitrary block editing container. Images may use the dedicated measureHeight protocol. Use a block layer for large fence previews, as in the diagram example.

Dependencies and stable identity

ts

Layer keys are globally unique; view keys are stable within a layer. Do not create new renderer functions inside build(), which would remount components unnecessarily. A module-level renderer may be shared while all instance resources remain scoped.

Set selection: true if the builder reads input.selection. List state slots read by a layer in states. Ordinary source reveal is already handled separately; it does not require rebuilding every chart on cursor movement.

Modes default to live and locked. suppressDuringComposition defaults to true: in Markdown editing, only descriptions intersecting the IME selection temporarily reveal source. Replacements use their complete revealRange; line descriptions use the source line. Other blocks retain presentation and component identity. Hidden-syntax document editing keeps projections while CodeMirror owns composition in native text.

Composition boundaries rematerialize existing descriptions without rebuilding every layer. Even when previews remain mounted, edit actions must check readSourcePresentation(editor.state).composing before moving selection or opening an editor, so they cannot take IME focus. Keep input protection enabled. Competing replacements may fall back to source; inspect editor.work.projectionConflicts for ownership conflicts.

Updating affected blocks during ordinary input

Declare incremental: true when output depends only on its syntax block. Block layers receive changed complete syntax blocks; untouched descriptions move with the source and retain component identity. Inline layers still query visible ranges and reuse mapped component identities. Omitting the option keeps complete builds for plugins that depend on the whole document.

Before opting in, satisfy these requirements:

  • Use input.query(name) or source within the current range. Output and revealRange must belong to the queried blocks. Do not scan the entire document, number every block or build a document-wide outline in this path.
  • Declare references: true when links depend on definitions elsewhere. Adding, deleting or changing a definition rebuilds the layer. Keep conservative builds for other global dependencies.
  • Continue declaring selection and states. Permission, mode or declared dependency changes trigger complete evaluation.
  • Within one build, each key identifies one source placement. Keep the renderer stable. The runtime maps component identity through source changes; replacing or deleting the entire block ends its old identity.

Map source positions in component props explicitly with the third argument of componentView. This view fragment belongs inside input.query(name).matches.map(...); renderPreview is a module-level renderer:

ts

The mapper only returns new props. It must not create DOM, acquire resources or dispatch transactions. The renderer's update(next) must retain the latest props; click handlers must not capture the initial source position. Reuse the chart instance when preview content is unchanged. After typing before a preview, its edit action then targets the correct block even if that preview mounts only after scrolling into view.

Local updates do not mean parsing only the caret line. Changing fences, list/container boundaries, table delimiters or reference definitions can legitimately affect surrounding blocks. The runtime expands invalidation according to accepted syntax changes. Compare syntaxDiffBuilds, syntaxDiffChunks, syntaxDiffComparisons, layerVisitedNodes and blockBuilds in editor.work, and verify DOM/resource reuse. Existing descriptions still need mapping and decoration materialization; constant cost for every input is not guaranteed.

ComponentView versus NodeView

ContractInputUse
NodeViewnodeView.attrs, updateAttributes, getRangeSource-field controls
ComponentViewFeature-specific view propsSearch, disclosure and chart UI

Use the corresponding Vue or React renderer and a Host inside the existing Provider tree. Do not create an independent framework app per node.

A native ComponentViewRenderer<Props> receives dom, props, host, scope and requestMeasure, and returns update, destroy and optional ignoreEvent. Event ownership defaults to the component; return false only for events intentionally delegated to CodeMirror.

Measurement and teardown

The runtime owns the mount container. Renderers own their child DOM, listeners, observers and external instances. Never mutate .cm-content. Call the coalesced requestMeasure() after asynchronous geometry changes.

Reuse resources for permission-only updates. Cancel obsolete work when source or rendering parameters change. Destroy framework entries and release scope-owned resources, including unfinished loads. See Resource lifetime.

Interaction verification

Cover drag selection across previews, keyboard reveal, search, readonly copying, composition, viewport unmounts, rapid updates and document replacement. Inspect work-count deltas and resource counts as well as final appearance. Cursor movement should not parse the whole document or initialize every chart again. See Rendering API.

MSFE · QuireKitYour Markdown source stays yours.