Extension API
Authoring hooks, presets, rules and container control contracts.
Signatures come from public package exports. Descriptions are checked against current JSDoc; identifiers retain their original names.
Extension definitions
These hooks define installation. See Extension model for composition.
@quirekit/msfe-coreDeclarative hooks shared by Extension, Node and Mark. Unsupported PM schema fields are rejected.
export interface ExtensionConfig<Options extends object = Record<string, never>, Storage = Record<string, never>> {
readonly history?: "effects";
addSourceProvider?(this: ExtensionContext<Options, Storage, () => MsfeSourceProvider>): MsfeSourceProvider;
readonly name?: string;
readonly priority?: number;
readonly requires?: readonly string[];
addOptions?(this: OptionsContext<Options>): Options;
addStorage?(this: ExtensionContext<Options, Storage, () => Storage>): Storage;
addState?(this: ExtensionContext<Options, Storage, () => readonly StateSlot<unknown>[]>): readonly StateSlot<unknown>[];
addExtensions?(this: ExtensionContext<Options, Storage, () => readonly AnyExtension[]>): readonly AnyExtension[];
addCommands?(this: ExtensionContext<Options, Storage, () => Partial<RawCommands>>): Partial<RawCommands>;
addAiCapabilities?(this: ExtensionContext<Options, Storage, () => readonly unknown[]>): readonly unknown[];
addKeyboardShortcuts?(this: ExtensionContext<Options, Storage, () => Record<string, () => boolean>>): Record<string, () => boolean>;
addEditingBoundaries?(this: ExtensionContext<Options, Storage, () => readonly EditingBoundaryRule[]>): readonly EditingBoundaryRule[];
addBlockInput?(this: ExtensionContext<Options, Storage, () => readonly BlockInputRule[]>): readonly BlockInputRule[];
addInputRules?(this: ExtensionContext<Options, Storage, () => readonly InputRule[]>): readonly InputRule[];
addPasteRules?(this: ExtensionContext<Options, Storage, () => readonly PasteRule[]>): readonly PasteRule[];
addSource?(this: ExtensionContext<Options, Storage, () => SourceSpec>): SourceSpec;
addAttributes?(this: ExtensionContext<Options, Storage, () => Attributes>): Attributes;
addNodeView?(this: ExtensionContext<Options, Storage, () => MsfeNodeViewRenderer>): MsfeNodeViewRenderer;
addMarkdownExtensions?(this: ExtensionContext<Options, Storage, () => MarkdownExtension>): MarkdownExtension;
addProjections?(this: ExtensionContext<Options, Storage, () => readonly MsfeProjection[]>): readonly MsfeProjection[];
addProjectionLayers?(this: ExtensionContext<Options, Storage, () => readonly ProjectionLayer[]>): readonly ProjectionLayer[];
addCodeMirrorExtensions?(this: ExtensionContext<Options, Storage, () => CodeMirrorExtension>): CodeMirrorExtension;
onBeforeCreate?(this: ExtensionContext<Options, Storage>): void;
onCreate?(this: ExtensionContext<Options, Storage, () => void | (() => void)>): void | (() => void);
onUpdate?(this: ExtensionContext<Options, Storage, (event: MsfeChangeEvent) => void>, event: MsfeChangeEvent): void;
onTransaction?(this: ExtensionContext<Options, Storage, (event: TransactionEvent) => void>, event: TransactionEvent): void;
onSelectionUpdate?(this: ExtensionContext<Options, Storage, (event: TransactionEvent) => void>, event: TransactionEvent): void;
onFocus?(this: ExtensionContext<Options, Storage, (event: FocusEvent) => void>, event: FocusEvent): void;
onBlur?(this: ExtensionContext<Options, Storage, (event: FocusEvent) => void>, event: FocusEvent): void;
onDestroy?(this: ExtensionContext<Options, Storage>): void;
}Base preset
Each entry accepts a definition or false; replace owners instead of duplicating them.
@quirekit/msfe-starter-kitPer-feature overrides or explicit exclusions, with duplicate owners still diagnosed.
export interface StarterKitOptions {
readonly heading?: AnyExtension | false;
readonly bold?: AnyExtension | false;
readonly link?: AnyExtension | false;
readonly codeBlock?: AnyExtension | false;
readonly image?: AnyExtension | false;
readonly emphasis?: AnyExtension | false;
readonly inlineCode?: AnyExtension | false;
readonly strikethrough?: AnyExtension | false;
readonly horizontalRule?: AnyExtension | false;
readonly blockquote?: AnyExtension | false;
readonly listMarkers?: AnyExtension | false;
readonly taskItem?: AnyExtension | false;
readonly table?: AnyExtension | false;
readonly textLiterals?: AnyExtension | false;
readonly dataUrlFold?: AnyExtension | false;
}Source rules
Both rule classes use this configuration. See Input rules.
@quirekit/msfe-coreSource-native rule; unlike a PM input rule, its output is exact Markdown text.
export interface RuleConfig {
readonly find: RegExp;
readonly handler: (context: RuleMatch) => string | null;
}Container options
Arrays replace defaults. Controls own disclosure UI while source owns the body.
@quirekit/msfe-markdown-extrasSafe named containers; HTML attributes and executable render functions are not document syntax.
export interface ContainerOptions {
readonly types: readonly string[];
readonly detailsOpen: boolean;
readonly controls?: ComponentViewRenderer<ContainerControlProps>;
readonly toggleLabel: (expanded: boolean, title: string) => string;
}Disclosure controls
Components receive view; toggling is source-neutral.
@quirekit/msfe-markdown-extrasSource-neutral disclosure control, with no second content or selection owner.
export interface ContainerControlProps {
readonly expanded: boolean;
readonly label: string;
readonly toggle: () => void;
}