Skip to content

Extending Features

SciFlow’s feature system keeps schema nodes, commands, and UI wiring isolated. Use this guide when you need to add a new capability or tweak an existing one.

Feature Anatomy

A feature lives under packages/editor/core/src/lib/features/<name> and typically exports:

  • Feature object (name, initialize, optional plugins, nodeViews).
  • Commands registered via registerCommands.
  • Node views (Lit or vanilla) when the feature requires custom rendering.
export const figureFeature: Feature = {
  name: 'figure',
  initialize() {
    registerCommands({
      insertFigure:
        (options: InsertFigureOptions) =>
        (props) => runInsertFigure(props.state, options, getDispatch(props)),
    });
  },
  nodeViews() {
    return { figure: createDecoratedNodeViewFactory(FigureNodeView) };
  },
};

Adding a New Feature

  1. Create the schema node (if required) under packages/schema.
  2. Add commands that manipulate the node or mark.
  3. Register ProseMirror plugins via the feature’s addPlugins hook (drop handlers, keymaps, etc.).
  4. Expose UI hooks in the start package (toolbar buttons, dialogs, custom panels).
  5. Wire feature toggles – include the new feature in the FEATURE_OPTIONS array in the demo so QA can enable/disable it quickly.

Reuse helpers

The command system already provides getDispatch, withCommandRegistration, and flow helpers. Prefer them over hand-rolled dispatch logic to keep flows and availability checks working.

Testing Strategy

  • Unit test commands in isolation (Vitest) by instantiating a ProseMirror state and running the command function.
  • Add integration tests in packages/editor/core/src/lib/features/<feature>/<feature>.spec.ts if the feature already has a suite.
  • Exercise node views in the demo to ensure Lit bindings update as expected.

Surfacing Feature APIs to Consumers

  • Re-export the command helpers (e.g., runInsertFigure) from the feature index so downstream apps can call them with custom dispatchers.
  • Document any additional attributes/events in the User Guide (Customization or Packages chapters).

Updating the Web Components

  • If the feature requires UI controls, modify packages/editor/start/src/lib/format-bar.ts or add a dedicated panel.
  • Keep accessibility glued together (ARIA labels, keyboard interactions) to match existing nodes (heading, citations, etc.).

Feature toggles vs. bundles

Features are tree-shakeable: only the ones you register in editor.configureFeatures() end up active. This keeps the runtime lean even as the feature set grows.