UNPKG

@tiptap/core

Version:

headless rich text editor

613 lines (612 loc) 22.6 kB
import { DOMOutputSpec, Node as ProseMirrorNode, NodeSpec, NodeType } from '@tiptap/pm/model'; import { Plugin, Transaction } from '@tiptap/pm/state'; import { Editor } from './Editor.js'; import { NodeConfig } from './index.js'; import { InputRule } from './InputRule.js'; import { Mark } from './Mark.js'; import { PasteRule } from './PasteRule.js'; import { Attributes, Extensions, GlobalAttributes, KeyboardShortcutCommand, NodeViewRenderer, ParentConfig, RawCommands } from './types.js'; declare module '@tiptap/core' { interface NodeConfig<Options = any, Storage = any> { [key: string]: any; /** * The extension name - this must be unique. * It will be used to identify the extension. * * @example 'myExtension' */ name: string; /** * The priority of your extension. The higher, the earlier it will be called * and will take precedence over other extensions with a lower priority. * @default 100 * @example 101 */ priority?: number; /** * The default options for this extension. * @example * defaultOptions: { * myOption: 'foo', * myOtherOption: 10, * } */ defaultOptions?: Options; /** * This method will add options to this extension * @see https://tiptap.dev/guide/custom-extensions#settings * @example * addOptions() { * return { * myOption: 'foo', * myOtherOption: 10, * } */ addOptions?: (this: { name: string; parent: Exclude<ParentConfig<NodeConfig<Options, Storage>>['addOptions'], undefined>; }) => Options; /** * The default storage this extension can save data to. * @see https://tiptap.dev/guide/custom-extensions#storage * @example * defaultStorage: { * prefetchedUsers: [], * loading: false, * } */ addStorage?: (this: { name: string; options: Options; parent: Exclude<ParentConfig<NodeConfig<Options, Storage>>['addStorage'], undefined>; }) => Storage; /** * This function adds globalAttributes to specific nodes. * @see https://tiptap.dev/guide/custom-extensions#global-attributes * @example * addGlobalAttributes() { * return [ * { // Extend the following extensions * types: [ * 'heading', * 'paragraph', * ], * // … with those attributes * attributes: { * textAlign: { * default: 'left', * renderHTML: attributes => ({ * style: `text-align: ${attributes.textAlign}`, * }), * parseHTML: element => element.style.textAlign || 'left', * }, * }, * }, * ] * } */ addGlobalAttributes?: (this: { name: string; options: Options; storage: Storage; extensions: (Node | Mark)[]; parent: ParentConfig<NodeConfig<Options, Storage>>['addGlobalAttributes']; }) => GlobalAttributes; /** * This function adds commands to the editor * @see https://tiptap.dev/guide/custom-extensions#keyboard-shortcuts * @example * addCommands() { * return { * myCommand: () => ({ chain }) => chain().setMark('type', 'foo').run(), * } * } */ addCommands?: (this: { name: string; options: Options; storage: Storage; editor: Editor; type: NodeType; parent: ParentConfig<NodeConfig<Options, Storage>>['addCommands']; }) => Partial<RawCommands>; /** * This function registers keyboard shortcuts. * @see https://tiptap.dev/guide/custom-extensions#keyboard-shortcuts * @example * addKeyboardShortcuts() { * return { * 'Mod-l': () => this.editor.commands.toggleBulletList(), * } * }, */ addKeyboardShortcuts?: (this: { name: string; options: Options; storage: Storage; editor: Editor; type: NodeType; parent: ParentConfig<NodeConfig<Options, Storage>>['addKeyboardShortcuts']; }) => { [key: string]: KeyboardShortcutCommand; }; /** * This function adds input rules to the editor. * @see https://tiptap.dev/guide/custom-extensions#input-rules * @example * addInputRules() { * return [ * markInputRule({ * find: inputRegex, * type: this.type, * }), * ] * }, */ addInputRules?: (this: { name: string; options: Options; storage: Storage; editor: Editor; type: NodeType; parent: ParentConfig<NodeConfig<Options, Storage>>['addInputRules']; }) => InputRule[]; /** * This function adds paste rules to the editor. * @see https://tiptap.dev/guide/custom-extensions#paste-rules * @example * addPasteRules() { * return [ * markPasteRule({ * find: pasteRegex, * type: this.type, * }), * ] * }, */ addPasteRules?: (this: { name: string; options: Options; storage: Storage; editor: Editor; type: NodeType; parent: ParentConfig<NodeConfig<Options, Storage>>['addPasteRules']; }) => PasteRule[]; /** * This function adds Prosemirror plugins to the editor * @see https://tiptap.dev/guide/custom-extensions#prosemirror-plugins * @example * addProseMirrorPlugins() { * return [ * customPlugin(), * ] * } */ addProseMirrorPlugins?: (this: { name: string; options: Options; storage: Storage; editor: Editor; type: NodeType; parent: ParentConfig<NodeConfig<Options, Storage>>['addProseMirrorPlugins']; }) => Plugin[]; /** * This function adds additional extensions to the editor. This is useful for * building extension kits. * @example * addExtensions() { * return [ * BulletList, * OrderedList, * ListItem * ] * } */ addExtensions?: (this: { name: string; options: Options; storage: Storage; parent: ParentConfig<NodeConfig<Options, Storage>>['addExtensions']; }) => Extensions; /** * This function extends the schema of the node. * @example * extendNodeSchema() { * return { * group: 'inline', * selectable: false, * } * } */ extendNodeSchema?: ((this: { name: string; options: Options; storage: Storage; parent: ParentConfig<NodeConfig<Options, Storage>>['extendNodeSchema']; }, extension: Node) => Record<string, any>) | null; /** * This function extends the schema of the mark. * @example * extendMarkSchema() { * return { * group: 'inline', * selectable: false, * } * } */ extendMarkSchema?: ((this: { name: string; options: Options; storage: Storage; parent: ParentConfig<NodeConfig<Options, Storage>>['extendMarkSchema']; editor?: Editor; }, extension: Node) => Record<string, any>) | null; /** * The editor is not ready yet. */ onBeforeCreate?: ((this: { name: string; options: Options; storage: Storage; editor: Editor; type: NodeType; parent: ParentConfig<NodeConfig<Options, Storage>>['onBeforeCreate']; }) => void) | null; /** * The editor is ready. */ onCreate?: ((this: { name: string; options: Options; storage: Storage; editor: Editor; type: NodeType; parent: ParentConfig<NodeConfig<Options, Storage>>['onCreate']; }) => void) | null; /** * The content has changed. */ onUpdate?: ((this: { name: string; options: Options; storage: Storage; editor: Editor; type: NodeType; parent: ParentConfig<NodeConfig<Options, Storage>>['onUpdate']; }) => void) | null; /** * The selection has changed. */ onSelectionUpdate?: ((this: { name: string; options: Options; storage: Storage; editor: Editor; type: NodeType; parent: ParentConfig<NodeConfig<Options, Storage>>['onSelectionUpdate']; }) => void) | null; /** * The editor state has changed. */ onTransaction?: ((this: { name: string; options: Options; storage: Storage; editor: Editor; type: NodeType; parent: ParentConfig<NodeConfig<Options, Storage>>['onTransaction']; }, props: { editor: Editor; transaction: Transaction; }) => void) | null; /** * The editor is focused. */ onFocus?: ((this: { name: string; options: Options; storage: Storage; editor: Editor; type: NodeType; parent: ParentConfig<NodeConfig<Options, Storage>>['onFocus']; }, props: { event: FocusEvent; }) => void) | null; /** * The editor isn’t focused anymore. */ onBlur?: ((this: { name: string; options: Options; storage: Storage; editor: Editor; type: NodeType; parent: ParentConfig<NodeConfig<Options, Storage>>['onBlur']; }, props: { event: FocusEvent; }) => void) | null; /** * The editor is destroyed. */ onDestroy?: ((this: { name: string; options: Options; storage: Storage; editor: Editor; type: NodeType; parent: ParentConfig<NodeConfig<Options, Storage>>['onDestroy']; }) => void) | null; /** * Node View */ addNodeView?: ((this: { name: string; options: Options; storage: Storage; editor: Editor; type: NodeType; parent: ParentConfig<NodeConfig<Options, Storage>>['addNodeView']; }) => NodeViewRenderer) | null; /** * Defines if this node should be a top level node (doc) * @default false * @example true */ topNode?: boolean; /** * The content expression for this node, as described in the [schema * guide](/docs/guide/#schema.content_expressions). When not given, * the node does not allow any content. * * You can read more about it on the Prosemirror documentation here * @see https://prosemirror.net/docs/guide/#schema.content_expressions * @default undefined * @example content: 'block+' * @example content: 'headline paragraph block*' */ content?: NodeSpec['content'] | ((this: { name: string; options: Options; storage: Storage; parent: ParentConfig<NodeConfig<Options, Storage>>['content']; editor?: Editor; }) => NodeSpec['content']); /** * The marks that are allowed inside of this node. May be a * space-separated string referring to mark names or groups, `"_"` * to explicitly allow all marks, or `""` to disallow marks. When * not given, nodes with inline content default to allowing all * marks, other nodes default to not allowing marks. * * @example marks: 'strong em' */ marks?: NodeSpec['marks'] | ((this: { name: string; options: Options; storage: Storage; parent: ParentConfig<NodeConfig<Options, Storage>>['marks']; editor?: Editor; }) => NodeSpec['marks']); /** * The group or space-separated groups to which this node belongs, * which can be referred to in the content expressions for the * schema. * * By default Tiptap uses the groups 'block' and 'inline' for nodes. You * can also use custom groups if you want to group specific nodes together * and handle them in your schema. * @example group: 'block' * @example group: 'inline' * @example group: 'customBlock' // this uses a custom group */ group?: NodeSpec['group'] | ((this: { name: string; options: Options; storage: Storage; parent: ParentConfig<NodeConfig<Options, Storage>>['group']; editor?: Editor; }) => NodeSpec['group']); /** * Should be set to true for inline nodes. (Implied for text nodes.) */ inline?: NodeSpec['inline'] | ((this: { name: string; options: Options; storage: Storage; parent: ParentConfig<NodeConfig<Options, Storage>>['inline']; editor?: Editor; }) => NodeSpec['inline']); /** * Can be set to true to indicate that, though this isn't a [leaf * node](https://prosemirror.net/docs/ref/#model.NodeType.isLeaf), it doesn't have directly editable * content and should be treated as a single unit in the view. * * @example atom: true */ atom?: NodeSpec['atom'] | ((this: { name: string; options: Options; storage: Storage; parent: ParentConfig<NodeConfig<Options, Storage>>['atom']; editor?: Editor; }) => NodeSpec['atom']); /** * Controls whether nodes of this type can be selected as a [node * selection](https://prosemirror.net/docs/ref/#state.NodeSelection). Defaults to true for non-text * nodes. * * @default true * @example selectable: false */ selectable?: NodeSpec['selectable'] | ((this: { name: string; options: Options; storage: Storage; parent: ParentConfig<NodeConfig<Options, Storage>>['selectable']; editor?: Editor; }) => NodeSpec['selectable']); /** * Determines whether nodes of this type can be dragged without * being selected. Defaults to false. * * @default: false * @example: draggable: true */ draggable?: NodeSpec['draggable'] | ((this: { name: string; options: Options; storage: Storage; parent: ParentConfig<NodeConfig<Options, Storage>>['draggable']; editor?: Editor; }) => NodeSpec['draggable']); /** * Can be used to indicate that this node contains code, which * causes some commands to behave differently. */ code?: NodeSpec['code'] | ((this: { name: string; options: Options; storage: Storage; parent: ParentConfig<NodeConfig<Options, Storage>>['code']; editor?: Editor; }) => NodeSpec['code']); /** * Controls way whitespace in this a node is parsed. The default is * `"normal"`, which causes the [DOM parser](https://prosemirror.net/docs/ref/#model.DOMParser) to * collapse whitespace in normal mode, and normalize it (replacing * newlines and such with spaces) otherwise. `"pre"` causes the * parser to preserve spaces inside the node. When this option isn't * given, but [`code`](https://prosemirror.net/docs/ref/#model.NodeSpec.code) is true, `whitespace` * will default to `"pre"`. Note that this option doesn't influence * the way the node is rendered—that should be handled by `toDOM` * and/or styling. */ whitespace?: NodeSpec['whitespace'] | ((this: { name: string; options: Options; storage: Storage; parent: ParentConfig<NodeConfig<Options, Storage>>['whitespace']; editor?: Editor; }) => NodeSpec['whitespace']); /** * When enabled, enables both * [`definingAsContext`](https://prosemirror.net/docs/ref/#model.NodeSpec.definingAsContext) and * [`definingForContent`](https://prosemirror.net/docs/ref/#model.NodeSpec.definingForContent). * * @default false * @example isolating: true */ defining?: NodeSpec['defining'] | ((this: { name: string; options: Options; storage: Storage; parent: ParentConfig<NodeConfig<Options, Storage>>['defining']; editor?: Editor; }) => NodeSpec['defining']); /** * When enabled (default is false), the sides of nodes of this type * count as boundaries that regular editing operations, like * backspacing or lifting, won't cross. An example of a node that * should probably have this enabled is a table cell. */ isolating?: NodeSpec['isolating'] | ((this: { name: string; options: Options; storage: Storage; parent: ParentConfig<NodeConfig<Options, Storage>>['isolating']; editor?: Editor; }) => NodeSpec['isolating']); /** * Associates DOM parser information with this node, which can be * used by [`DOMParser.fromSchema`](https://prosemirror.net/docs/ref/#model.DOMParser^fromSchema) to * automatically derive a parser. The `node` field in the rules is * implied (the name of this node will be filled in automatically). * If you supply your own parser, you do not need to also specify * parsing rules in your schema. * * @example parseHTML: [{ tag: 'div', attrs: { 'data-id': 'my-block' } }] */ parseHTML?: (this: { name: string; options: Options; storage: Storage; parent: ParentConfig<NodeConfig<Options, Storage>>['parseHTML']; editor?: Editor; }) => NodeSpec['parseDOM']; /** * A description of a DOM structure. Can be either a string, which is * interpreted as a text node, a DOM node, which is interpreted as * itself, a `{dom, contentDOM}` object, or an array. * * An array describes a DOM element. The first value in the array * should be a string—the name of the DOM element, optionally prefixed * by a namespace URL and a space. If the second element is plain * object, it is interpreted as a set of attributes for the element. * Any elements after that (including the 2nd if it's not an attribute * object) are interpreted as children of the DOM elements, and must * either be valid `DOMOutputSpec` values, or the number zero. * * The number zero (pronounced “hole”) is used to indicate the place * where a node's child nodes should be inserted. If it occurs in an * output spec, it should be the only child element in its parent * node. * * @example toDOM: ['div[data-id="my-block"]', { class: 'my-block' }, 0] */ renderHTML?: ((this: { name: string; options: Options; storage: Storage; parent: ParentConfig<NodeConfig<Options, Storage>>['renderHTML']; editor?: Editor; }, props: { node: ProseMirrorNode; HTMLAttributes: Record<string, any>; }) => DOMOutputSpec) | null; /** * renders the node as text * @example renderText: () => 'foo */ renderText?: ((this: { name: string; options: Options; storage: Storage; parent: ParentConfig<NodeConfig<Options, Storage>>['renderText']; editor?: Editor; }, props: { node: ProseMirrorNode; pos: number; parent: ProseMirrorNode; index: number; }) => string) | null; /** * Add attributes to the node * @example addAttributes: () => ({ class: 'foo' }) */ addAttributes?: (this: { name: string; options: Options; storage: Storage; parent: ParentConfig<NodeConfig<Options, Storage>>['addAttributes']; editor?: Editor; }) => Attributes | {}; } } /** * The Node class is used to create custom node extensions. * @see https://tiptap.dev/api/extensions#create-a-new-extension */ export declare class Node<Options = any, Storage = any> { type: string; name: string; parent: Node | null; child: Node | null; options: Options; storage: Storage; config: NodeConfig; constructor(config?: Partial<NodeConfig<Options, Storage>>); static create<O = any, S = any>(config?: Partial<NodeConfig<O, S>>): Node<O, S>; configure(options?: Partial<Options>): Node<Options, Storage>; extend<ExtendedOptions = Options, ExtendedStorage = Storage>(extendedConfig?: Partial<NodeConfig<ExtendedOptions, ExtendedStorage>>): Node<ExtendedOptions, ExtendedStorage>; }