API des plugins

Un plugin de bloc est une seule déclaration couvrant toutes les surfaces qu'un bloc touche : son schéma, sa vue et chacune de ses projections. Cette totalité est délibérée — un bloc ne doit pas pouvoir s'afficher sans dire comment il survit à un export.

BlockPlugin

NomTypeDescription
apiVersion*1

The plugin contract version this was written against.

Checked at registration, so a plugin from a future contract fails loudly by name instead of misbehaving. It also lets v1 and v2 plugins run side by side during a migration, rather than every author breaking on one flag day.

import { PLUGIN_API_VERSION } from '@nbe/core'
const myBlock = { apiVersion: PLUGIN_API_VERSION, schema: { … } }
autoformatAutoformatRule[]

Markdown shortcuts that turn a paragraph into this block as you type — `\`\`\`` for code, the way `- ` makes a list.

Consulted before the built-in table, so a plugin may claim a prefix. It lives on the model half rather than the view because autoformat is a core command: a headless host applying an edit gets the same behaviour.

htmlfunction

Static HTML for export and server rendering.

Returns a string rather than a live element, so it runs with no DOM and the same block renders identically in a CLI, on a server and in a browser.

normalizefunction

Document invariants this block type repairs, run on every transaction that changed structure.

The extension point a table forced into existence, and the one a block with *internal* structure cannot do without: a row that lost a cell, a container left empty, a span pointing at a row that no longer exists. It runs on the model, so a headless import is normalized exactly like a keystroke — ProseMirror's `fixTables` is the same idea, exposed as a command because its plugins cannot reach the state's apply loop. Write it as a *repair*, not a validation: read the doc, emit the ops that make it legal through `tx`, return whether you emitted any. It must be idempotent — it will see its own output on the next transaction.

normalize: (doc, tx) => {
  let changed = false
  for (const row of shortRows(doc)) { tx.op(padRow(row)); changed = true }
  return changed
}
schema*BlockSpec

The block's declarative description: type, version, whether it carries inline text, its default props.

JSON-serializable and free of behaviour on purpose. The static renderer and a future Swift port consume it without executing any JavaScript, which they could not do if rendering functions lived inside it.

viewunknown

Editing-surface behaviour. Lives in the `@nbe/dom` layer, so it is typed as unknown here and refined there — `core` must never depend on the DOM.

MarkdownProjection

Les deux directions sont requises, et c'est le point : n'implémenter que la sérialisation, c'est écrire un bloc qui se dégrade silencieusement au réimport. Quand un format ne peut vraiment pas représenter un bloc, on le déclare avec lossy() plutôt que d'omettre la fonction.

NomTypeDescription
fromMarkdown*MarkdownRule[]

Recognise this block in markdown. Consulted in precedence order, and the first matching rule wins.

lossyReasonstring

Set when this format cannot represent the block faithfully. Read by tooling and by the docs table — never at runtime — so the loss is discoverable instead of discovered.

toMarkdown*string[]

Fonctions

at

at(precedence: Precedence, value: T): Ranked<T>

Tag a contribution with a precedence.

Paramètres

  • precedence: Precedence — Which category this contribution belongs to.
  • value: T — The contribution itself.

Retourne

  • Ranked<T>
keys: { Enter: at('high', handleEnterInsideTable) }

byPrecedence

byPrecedence(items: T | Ranked<T>[]): T[]

Sort contributions by category, then by the order they were registered in.

Paramètres

  • items: T | Ranked<T>[] — Contributions, tagged or not.

Retourne

  • T[]

lossy

lossy(reason: string, fallback: function): MarkdownProjection

Declare that a format cannot represent this block faithfully.

Paramètres

  • reason: string — What this format cannot carry, in one sentence. Surfaced in the documentation rather than read at runtime.
  • fallback: function — What to emit instead.

Retourne

  • MarkdownProjection
markdown: lossy('les colonnes sont aplaties', (b) => [`<!-- ${b.type} -->`])

PluginRegistry

Par éditeur, jamais globale au module. Deux éditeurs sur une même page est la deuxième démo qu'on écrit, et un registre global rend impossible d'y avoir des jeux de blocs différents.

all

all(): BlockPlugin[]

Every registered plugin, for building the schema or a projection table.

Retourne

  • BlockPlugin[]