From eb48bec035ef364d70181bf626ad71ceabea56d8 Mon Sep 17 00:00:00 2001 From: Tim Baumann Date: Mon, 23 Oct 2017 22:18:31 +0200 Subject: [PATCH] Update prosemirror-* type definitions, add comments (#20637) The type definitions have been generated using https://github.com/bradleyayers/getdocs2ts from the getdocs comments in the ProseMirror source. --- types/prosemirror-collab/index.d.ts | 39 +- types/prosemirror-commands/index.d.ts | 165 ++- types/prosemirror-gapcursor/index.d.ts | 30 + .../prosemirror-gapcursor-tests.ts | 4 + types/prosemirror-gapcursor/tsconfig.json | 24 + types/prosemirror-gapcursor/tslint.json | 3 + types/prosemirror-history/index.d.ts | 39 +- types/prosemirror-inputrules/index.d.ts | 105 +- .../prosemirror-inputrules-tests.ts | 2 +- types/prosemirror-keymap/index.d.ts | 53 +- types/prosemirror-markdown/index.d.ts | 200 ++- types/prosemirror-menu/index.d.ts | 215 ++- types/prosemirror-model/dom.d.ts | 21 - types/prosemirror-model/index.d.ts | 1300 +++++++++++++++-- types/prosemirror-model/tslint.json | 4 +- types/prosemirror-schema-basic/index.d.ts | 47 +- types/prosemirror-schema-list/index.d.ts | 53 +- types/prosemirror-state/index.d.ts | 580 ++++++-- .../prosemirror-state-tests.ts | 38 +- types/prosemirror-tables/dom.d.ts | 21 - types/prosemirror-tables/index.d.ts | 19 +- types/prosemirror-transform/index.d.ts | 475 +++++- types/prosemirror-view/dom.d.ts | 21 - types/prosemirror-view/index.d.ts | 497 ++++++- 24 files changed, 3451 insertions(+), 504 deletions(-) create mode 100644 types/prosemirror-gapcursor/index.d.ts create mode 100644 types/prosemirror-gapcursor/prosemirror-gapcursor-tests.ts create mode 100644 types/prosemirror-gapcursor/tsconfig.json create mode 100644 types/prosemirror-gapcursor/tslint.json delete mode 100644 types/prosemirror-model/dom.d.ts delete mode 100644 types/prosemirror-tables/dom.d.ts delete mode 100644 types/prosemirror-view/dom.d.ts diff --git a/types/prosemirror-collab/index.d.ts b/types/prosemirror-collab/index.d.ts index c4fb3cb7fa..4b84101159 100644 --- a/types/prosemirror-collab/index.d.ts +++ b/types/prosemirror-collab/index.d.ts @@ -1,14 +1,43 @@ -// Type definitions for prosemirror-collab 0.21 +// Type definitions for prosemirror-collab 1.0 // Project: https://github.com/ProseMirror/prosemirror-collab // Definitions by: Bradley Ayers // David Hahn +// Tim Baumann // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.3 +// TypeScript Version: 2.1 -import { Plugin, EditorState, Transaction } from 'prosemirror-state'; +// IMPORTANT +// This file was generated by https://github.com/bradleyayers/getdocs2ts. Please do not edit manually. +// When you find an error in these declarations, fix the getdocs comment upstream or 'getdocs2ts', then regenerate. + +import { EditorState, Plugin, Transaction } from 'prosemirror-state'; import { Step } from 'prosemirror-transform'; -export function collab(config?: { version?: number, clientID?: number | string }): Plugin; +/** + * Creates a plugin that enables the collaborative editing framework + * for the editor. + */ +export function collab(config?: { version?: number | null, clientID?: number | string | null }): Plugin; +/** + * Create a transaction that represents a set of new steps received from + * the authority. Applying this transaction moves the state forward to + * adjust to the authority's view of the document. + */ export function receiveTransaction(state: EditorState, steps: Step[], clientIDs: Array): Transaction; -export function sendableSteps(state: EditorState): { version: number, steps: Step[], clientID: number | string, origins: Transaction[] } | null; +/** + * Provides data describing the editor's unconfirmed steps, which need + * to be sent to the central authority. Returns null when there is + * nothing to send. + * + * `origins` holds the _original_ transactions that produced each + * steps. This can be useful for looking up time stamps and other + * metadata for the steps, but note that the steps may have been + * rebased, whereas the origin transactions are still the old, + * unchanged objects. + */ +export function sendableSteps(state: EditorState): { version: number, steps: Step[], clientID: number | string, origins: Transaction[] } | null | void; +/** + * Get the version up to which the collab plugin has synced with the + * central authority. + */ export function getVersion(state: EditorState): number; diff --git a/types/prosemirror-commands/index.d.ts b/types/prosemirror-commands/index.d.ts index df531d3663..5f8cb75946 100644 --- a/types/prosemirror-commands/index.d.ts +++ b/types/prosemirror-commands/index.d.ts @@ -1,35 +1,178 @@ -// Type definitions for prosemirror-commands 0.24 +// Type definitions for prosemirror-commands 1.0 // Project: https://github.com/ProseMirror/prosemirror-commands // Definitions by: Bradley Ayers // David Hahn +// Tim Baumann // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.2 +// TypeScript Version: 2.1 -import { MarkType, Node, NodeType } from 'prosemirror-model'; +// IMPORTANT +// This file was generated by https://github.com/bradleyayers/getdocs2ts. Please do not edit manually. +// When you find an error in these declarations, fix the getdocs comment upstream or 'getdocs2ts', then regenerate. + +import { MarkType, Node as ProsemirrorNode, NodeType } from 'prosemirror-model'; import { EditorState, Transaction } from 'prosemirror-state'; import { EditorView } from 'prosemirror-view'; +/** + * Delete the selection, if there is one. + */ export function deleteSelection(state: EditorState, dispatch?: (tr: Transaction) => void): boolean; +/** + * If the selection is empty and at the start of a textblock, try to + * reduce the distance between that block and the one before it—if + * there's a block directly before it that can be joined, join them. + * If not, try to move the selected block closer to the next one in + * the document structure by lifting it out of its parent or moving it + * into a parent of the previous block. Will use the view for accurate + * (bidi-aware) start-of-textblock detection if given. + */ export function joinBackward(state: EditorState, dispatch?: (tr: Transaction) => void, view?: EditorView): boolean; +/** + * When the selection is empty and at the start of a textblock, select + * the node before that textblock, if possible. This is intended to be + * bound to keys like backspace, after + * [`joinBackward`](#commands.joinBackward) or other deleting + * commands, as a fall-back behavior when the schema doesn't allow + * deletion at the selected point. + */ export function selectNodeBackward(state: EditorState, dispatch?: (tr: Transaction) => void, view?: EditorView): boolean; -export function selectNodeForward(state: EditorState, dispatch?: (tr: Transaction) => void, view?: EditorView): boolean; +/** + * If the selection is empty and the cursor is at the end of a + * textblock, try to reduce or remove the boundary between that block + * and the one after it, either by joining them or by moving the other + * block closer to this one in the tree structure. Will use the view + * for accurate start-of-textblock detection if given. + */ export function joinForward(state: EditorState, dispatch?: (tr: Transaction) => void, view?: EditorView): boolean; +/** + * When the selection is empty and at the end of a textblock, select + * the node coming after that textblock, if possible. This is intended + * to be bound to keys like delete, after + * [`joinForward`](#commands.joinForward) and similar deleting + * commands, to provide a fall-back behavior when the schema doesn't + * allow deletion at the selected point. + */ +export function selectNodeForward(state: EditorState, dispatch?: (tr: Transaction) => void, view?: EditorView): boolean; +/** + * Join the selected block or, if there is a text selection, the + * closest ancestor block of the selection that can be joined, with + * the sibling above it. + */ export function joinUp(state: EditorState, dispatch?: (tr: Transaction) => void): boolean; +/** + * Join the selected block, or the closest ancestor of the selection + * that can be joined, with the sibling after it. + */ export function joinDown(state: EditorState, dispatch?: (tr: Transaction) => void): boolean; +/** + * Lift the selected block, or the closest ancestor block of the + * selection that can be lifted, out of its parent node. + */ export function lift(state: EditorState, dispatch?: (tr: Transaction) => void): boolean; +/** + * If the selection is in a node whose type has a truthy + * [`code`](#model.NodeSpec.code) property in its spec, replace the + * selection with a newline character. + */ export function newlineInCode(state: EditorState, dispatch?: (tr: Transaction) => void): boolean; +/** + * When the selection is in a node with a truthy + * [`code`](#model.NodeSpec.code) property in its spec, create a + * default block after the code block, and move the cursor there. + */ export function exitCode(state: EditorState, dispatch?: (tr: Transaction) => void): boolean; +/** + * If a block node is selected, create an empty paragraph before (if + * it is its parent's first child) or after it. + */ export function createParagraphNear(state: EditorState, dispatch?: (tr: Transaction) => void): boolean; +/** + * If the cursor is in an empty textblock that can be lifted, lift the + * block. + */ export function liftEmptyBlock(state: EditorState, dispatch?: (tr: Transaction) => void): boolean; +/** + * Split the parent block of the selection. If the selection is a text + * selection, also delete its content. + */ export function splitBlock(state: EditorState, dispatch?: (tr: Transaction) => void): boolean; +/** + * Acts like [`splitBlock`](#commands.splitBlock), but without + * resetting the set of active marks at the cursor. + */ export function splitBlockKeepMarks(state: EditorState, dispatch?: (tr: Transaction) => void): boolean; +/** + * Move the selection to the node wrapping the current selection, if + * any. (Will not select the document node.) + */ export function selectParentNode(state: EditorState, dispatch?: (tr: Transaction) => void): boolean; +/** + * Select the whole document. + */ export function selectAll(state: EditorState, dispatch?: (tr: Transaction) => void): boolean; -export function wrapIn(nodeType: NodeType, attrs?: object): (state: EditorState, dispatch?: (tr: Transaction) => void) => boolean; -export function setBlockType(nodeType: NodeType, attrs?: object): (state: EditorState, dispatch?: (tr: Transaction) => void) => boolean; -export function toggleMark(markType: MarkType, attrs?: object): (state: EditorState, dispatch?: (tr: Transaction) => void) => boolean; +/** + * Wrap the selection in a node of the given type with the given + * attributes. + */ +export function wrapIn(nodeType: NodeType, attrs?: { [key: string]: any }): (state: EditorState, dispatch?: (tr: Transaction) => void) => boolean; +/** + * Returns a command that tries to set the textblock around the + * selection to the given node type with the given attributes. + */ +export function setBlockType(nodeType: NodeType, attrs?: { [key: string]: any }): (state: EditorState, dispatch?: (tr: Transaction) => void) => boolean; +/** + * Create a command function that toggles the given mark with the + * given attributes. Will return `false` when the current selection + * doesn't support that mark. This will remove the mark if any marks + * of that type exist in the selection, or add it otherwise. If the + * selection is empty, this applies to the [stored + * marks](#state.EditorState.storedMarks) instead of a range of the + * document. + */ +export function toggleMark(markType: MarkType, attrs?: { [key: string]: any }): (state: EditorState, dispatch?: (tr: Transaction) => void) => boolean; +/** + * Wrap a command so that, when it produces a transform that causes + * two joinable nodes to end up next to each other, those are joined. + * Nodes are considered joinable when they are of the same type and + * when the `isJoinable` predicate returns true for them or, if an + * array of strings was passed, if their node type name is in that + * array. + */ export function autoJoin( - command: (state: EditorState, p1?: (tr: Transaction) => void) => boolean, - isJoinable: ((before: Node, after: Node) => boolean) | string[]): (state: EditorState, p1?: (tr: Transaction) => void) => boolean; -export function chainCommands(...commands: Array<(p1: EditorState, p2?: (tr: Transaction) => void) => boolean>): (p1: EditorState, p2?: (tr: Transaction) => void) => boolean; -export const baseKeymap: { [key: string]: any }; + command: (state: EditorState, p1?: (tr: Transaction) => void) => boolean, + isJoinable: ((before: ProsemirrorNode, after: ProsemirrorNode) => boolean) | string[] +): (state: EditorState, p1?: (tr: Transaction) => void) => boolean; +/** + * Combine a number of command functions into a single function (which + * calls them one by one until one returns true). + */ +export function chainCommands( + ...commands: Array<(p1: EditorState, p2?: (tr: Transaction) => void, p3?: EditorView) => boolean> +): (p1: EditorState, p2?: (tr: Transaction) => void, p3?: EditorView) => boolean; +/** + * A basic keymap containing bindings not specific to any schema. + * Binds the following keys (when multiple commands are listed, they + * are chained with [`chainCommands`](#commands.chainCommands)): + * + * * **Enter** to `newlineInCode`, `createParagraphNear`, `liftEmptyBlock`, `splitBlock` + * * **Mod-Enter** to `exitCode` + * * **Backspace** and **Mod-Backspace** to `deleteSelection`, `joinBackward`, `selectNodeBackward` + * * **Delete** and **Mod-Delete** to `deleteSelection`, `joinForward`, `selectNodeForward` + * * **Mod-Delete** to `deleteSelection`, `joinForward`, `selectNodeForward` + * * **Mod-a** to `selectAll` + */ +export let pcBaseKeymap: { [key: string]: any }; +/** + * A copy of `pcBaseKeymap` that also binds **Ctrl-h** like Backspace, + * **Ctrl-d** like Delete, **Alt-Backspace** like Ctrl-Backspace, and + * **Ctrl-Alt-Backspace**, **Alt-Delete**, and **Alt-d** like + * Ctrl-Delete. + */ +export let macBaseKeymap: { [key: string]: any }; +/** + * Depending on the detected platform, this will hold + * [`pcBasekeymap`](#commands.pcBaseKeymap) or + * [`macBaseKeymap`](#commands.macBaseKeymap). + */ +export let baseKeymap: { [key: string]: any }; diff --git a/types/prosemirror-gapcursor/index.d.ts b/types/prosemirror-gapcursor/index.d.ts new file mode 100644 index 0000000000..41edf50e3f --- /dev/null +++ b/types/prosemirror-gapcursor/index.d.ts @@ -0,0 +1,30 @@ +// Type definitions for prosemirror-gapcursor 1.0 +// Project: https://github.com/ProseMirror/prosemirror-gapcursor +// Definitions by: Bradley Ayers +// David Hahn +// Tim Baumann +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.1 + +// IMPORTANT +// This file was generated by https://github.com/bradleyayers/getdocs2ts. Please do not edit manually. +// When you find an error in these declarations, fix the getdocs comment upstream or 'getdocs2ts', then regenerate. + +import { Plugin, Selection } from 'prosemirror-state'; + +/** + * Gap cursor selections are represented using this class. Its + * `$anchor` and `$head` properties both point at the cursor position. + */ +export class GapCursor extends Selection { +} +/** + * Create a gap cursor plugin. When enabled, this will capture clicks + * near and arrow-key-motion past places that don't have a normally + * selectable position nearby, and create a gap cursor selection for + * them. The cursor is drawn as an element with class + * `ProseMirror-gapcursor`. You can either include + * `style/gapcursor.css` from the package's directory or add your own + * styles to make it visible. + */ +export function gapCursor(): Plugin; diff --git a/types/prosemirror-gapcursor/prosemirror-gapcursor-tests.ts b/types/prosemirror-gapcursor/prosemirror-gapcursor-tests.ts new file mode 100644 index 0000000000..1a3ecf2d0a --- /dev/null +++ b/types/prosemirror-gapcursor/prosemirror-gapcursor-tests.ts @@ -0,0 +1,4 @@ +import { gapCursor } from 'prosemirror-gapcursor'; +import { Plugin } from 'prosemirror-state'; + +const gapCursorPlugin: Plugin = gapCursor(); diff --git a/types/prosemirror-gapcursor/tsconfig.json b/types/prosemirror-gapcursor/tsconfig.json new file mode 100644 index 0000000000..957316926f --- /dev/null +++ b/types/prosemirror-gapcursor/tsconfig.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "module": "commonjs", + "lib": [ + "es6", + "dom" + ], + "noImplicitAny": true, + "noImplicitThis": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "baseUrl": "../", + "typeRoots": [ + "../" + ], + "types": [], + "noEmit": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.d.ts", + "prosemirror-gapcursor-tests.ts" + ] +} \ No newline at end of file diff --git a/types/prosemirror-gapcursor/tslint.json b/types/prosemirror-gapcursor/tslint.json new file mode 100644 index 0000000000..f93cf8562a --- /dev/null +++ b/types/prosemirror-gapcursor/tslint.json @@ -0,0 +1,3 @@ +{ + "extends": "dtslint/dt.json" +} diff --git a/types/prosemirror-history/index.d.ts b/types/prosemirror-history/index.d.ts index 55895338a9..4fbb59ecb9 100644 --- a/types/prosemirror-history/index.d.ts +++ b/types/prosemirror-history/index.d.ts @@ -1,15 +1,46 @@ -// Type definitions for prosemirror-history 0.21 +// Type definitions for prosemirror-history 1.0 // Project: https://github.com/ProseMirror/prosemirror-history // Definitions by: Bradley Ayers // David Hahn +// Tim Baumann // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.3 +// TypeScript Version: 2.1 -import { Plugin, EditorState, Transaction } from 'prosemirror-state'; +// IMPORTANT +// This file was generated by https://github.com/bradleyayers/getdocs2ts. Please do not edit manually. +// When you find an error in these declarations, fix the getdocs comment upstream or 'getdocs2ts', then regenerate. +import { EditorState, Plugin, Transaction } from 'prosemirror-state'; + +/** + * Set a flag on the given transaction that will prevent further steps + * from being appended to an existing history event (so that they + * require a separate undo command to undo). + */ export function closeHistory(tr: Transaction): Transaction; -export function history(config?: { depth?: number, newGroupDelay: number, preserveItems?: boolean }): Plugin; +/** + * Returns a plugin that enables the undo history for an editor. The + * plugin will track undo and redo stacks, which can be used with the + * [`undo`](#history.undo) and [`redo`](#history.redo) commands. + * + * You can set an `"addToHistory"` [metadata + * property](#state.Transaction.setMeta) of `false` on a transaction + * to prevent it from being rolled back by undo. + */ +export function history(config?: { depth?: number | null, newGroupDelay?: number | null }): Plugin; +/** + * A command function that undoes the last change, if any. + */ export function undo(state: EditorState, dispatch?: (tr: Transaction) => void): boolean; +/** + * A command function that redoes the last undone change, if any. + */ export function redo(state: EditorState, dispatch?: (tr: Transaction) => void): boolean; +/** + * The amount of undoable events available in a given state. + */ export function undoDepth(state: EditorState): number; +/** + * The amount of redoable events available in a given editor state. + */ export function redoDepth(state: EditorState): number; diff --git a/types/prosemirror-inputrules/index.d.ts b/types/prosemirror-inputrules/index.d.ts index d2c6d9c876..a75dc9cff5 100644 --- a/types/prosemirror-inputrules/index.d.ts +++ b/types/prosemirror-inputrules/index.d.ts @@ -1,30 +1,111 @@ -// Type definitions for prosemirror-inputrules 0.21 +// Type definitions for prosemirror-inputrules 1.0 // Project: https://github.com/ProseMirror/prosemirror-inputrules // Definitions by: Bradley Ayers // David Hahn +// Tim Baumann // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.3 +// TypeScript Version: 2.1 -import { Node, NodeType } from 'prosemirror-model'; +// IMPORTANT +// This file was generated by https://github.com/bradleyayers/getdocs2ts. Please do not edit manually. +// When you find an error in these declarations, fix the getdocs comment upstream or 'getdocs2ts', then regenerate. + +import { Node as ProsemirrorNode, NodeType } from 'prosemirror-model'; import { EditorState, Plugin, Transaction } from 'prosemirror-state'; +/** + * Input rules are regular expressions describing a piece of text + * that, when typed, causes something to happen. This might be + * changing two dashes into an emdash, wrapping a paragraph starting + * with `"> "` into a blockquote, or something entirely different. + */ export class InputRule { - constructor(match: RegExp, handler: string | ((state: EditorState, match: string[], start: number, end: number) => Transaction | null | undefined)) + /** + * Create an input rule. The rule applies when the user typed + * something and the text directly in front of the cursor matches + * `match`, which should probably end with `$`. + * + * The `handler` can be a string, in which case the matched text, or + * the first matched group in the regexp, is replaced by that + * string. + * + * Or a it can be a function, which will be called with the match + * array produced by + * [`RegExp.exec`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec), + * as well as the start and end of the matched range, and which can + * return a [transaction](#state.Transaction) that describes the + * rule's effect, or null to indicate the input was not handled. + */ + constructor(match: RegExp, handler: string | ((state: EditorState, match: string[], start: number, end: number) => Transaction | null | void)); } +/** + * Create an input rules plugin. When enabled, it will cause text + * input that matches any of the given rules to trigger the rule's + * action. + */ export function inputRules(config: { rules: InputRule[] }): Plugin; +/** + * This is a command that will undo an input rule, if applying such a + * rule was the last thing that the user did. + */ export function undoInputRule(state: EditorState, dispatch?: (p: Transaction) => void): boolean; +/** + * Build an input rule for automatically wrapping a textblock when a + * given string is typed. The `regexp` argument is + * directly passed through to the `InputRule` constructor. You'll + * probably want the regexp to start with `^`, so that the pattern can + * only occur at the start of a textblock. + * + * `nodeType` is the type of node to wrap in. If it needs attributes, + * you can either pass them directly, or pass a function that will + * compute them from the regular expression match. + * + * By default, if there's a node with the same type above the newly + * wrapped node, the rule will try to [join](#transform.Transform.join) those + * two nodes. You can pass a join predicate, which takes a regular + * expression match and the node before the wrapped node, and can + * return a boolean to indicate whether a join should happen. + */ +export function wrappingInputRule( + regexp: RegExp, + nodeType: NodeType, + getAttrs?: { [key: string]: any } | ((p: string[]) => { [key: string]: any } | null | void), + joinPredicate?: (p1: string[], p2: ProsemirrorNode) => boolean +): InputRule; +/** + * Build an input rule that changes the type of a textblock when the + * matched text is typed into it. You'll usually want to start your + * regexp with `^` to that it is only matched at the start of a + * textblock. The optional `getAttrs` parameter can be used to compute + * the new node's attributes, and works the same as in the + * `wrappingInputRule` function. + */ +export function textblockTypeInputRule(regexp: RegExp, nodeType: NodeType, getAttrs?: { [key: string]: any } | ((p: string[]) => { [key: string]: any } | null | void)): InputRule; +/** + * Converts double dashes to an emdash. + */ export let emDash: InputRule; +/** + * Converts three dots to an ellipsis character. + */ export let ellipsis: InputRule; +/** + * “Smart” opening double quotes. + */ export let openDoubleQuote: InputRule; +/** + * “Smart” closing double quotes. + */ export let closeDoubleQuote: InputRule; +/** + * “Smart” opening single quotes. + */ export let openSingleQuote: InputRule; +/** + * “Smart” closing single quotes. + */ export let closeSingleQuote: InputRule; +/** + * Smart-quote related input rules. + */ export let smartQuotes: InputRule[]; -export let allInputRules: InputRule[]; -export function wrappingInputRule(regexp: RegExp, nodeType: NodeType, getAttrs?: object | ((p: string[]) => object | null | undefined), joinPredicate?: (p1: string[], p2: Node) => boolean): InputRule; -export function textblockTypeInputRule(regexp: RegExp, nodeType: NodeType, getAttrs?: object | ((p: string[]) => object | null | undefined)): InputRule; -export function blockQuoteRule(nodeType: NodeType): InputRule; -export function orderedListRule(nodeType: NodeType): InputRule; -export function bulletListRule(nodeType: NodeType): InputRule; -export function codeBlockRule(nodeType: NodeType): InputRule; -export function headingRule(nodeType: NodeType, maxLevel: number): InputRule; diff --git a/types/prosemirror-inputrules/prosemirror-inputrules-tests.ts b/types/prosemirror-inputrules/prosemirror-inputrules-tests.ts index fbfe71ccd3..0d59a02be7 100644 --- a/types/prosemirror-inputrules/prosemirror-inputrules-tests.ts +++ b/types/prosemirror-inputrules/prosemirror-inputrules-tests.ts @@ -2,4 +2,4 @@ import * as inputrules from 'prosemirror-inputrules'; import { NodeType } from 'prosemirror-model'; const nodeType = new NodeType(); -const rule = inputrules.blockQuoteRule(nodeType); +const rule: inputrules.InputRule = inputrules.wrappingInputRule(/^\$/, nodeType); diff --git a/types/prosemirror-keymap/index.d.ts b/types/prosemirror-keymap/index.d.ts index 9e190f33b3..2e049948d5 100644 --- a/types/prosemirror-keymap/index.d.ts +++ b/types/prosemirror-keymap/index.d.ts @@ -1,16 +1,53 @@ -// Type definitions for prosemirror-keymap 0.24 +// Type definitions for prosemirror-keymap 1.0 // Project: https://github.com/ProseMirror/prosemirror-keymap // Definitions by: Bradley Ayers // David Hahn +// Tim Baumann // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.3 +// TypeScript Version: 2.1 + +// IMPORTANT +// This file was generated by https://github.com/bradleyayers/getdocs2ts. Please do not edit manually. +// When you find an error in these declarations, fix the getdocs comment upstream or 'getdocs2ts', then regenerate. import { Plugin } from 'prosemirror-state'; import { EditorView } from 'prosemirror-view'; -export interface Bindings { - [key: string]: any; -} - -export function keymap(bindings: Bindings): Plugin; -export function keydownHandler(bindings: Bindings): (view: EditorView, event: Event) => boolean; +/** + * Create a keymap plugin for the given set of bindings. + * + * Bindings should map key names to [command](#commands)-style + * functions, which will be called with `(EditorState, dispatch, + * EditorView)` arguments, and should return true when they've handled + * the key. Note that the view argument isn't part of the command + * protocol, but can be used as an escape hatch if a binding needs to + * directly interact with the UI. + * + * Key names may be strings like `"Shift-Ctrl-Enter"`—a key + * identifier prefixed with zero or more modifiers. Key identifiers + * are based on the strings that can appear in + * [`KeyEvent.key`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key). + * Use lowercase letters to refer to letter keys (or uppercase letters + * if you want shift to be held). You may use `"Space"` as an alias + * for the `" "` name. + * + * Modifiers can be given in any order. `Shift-` (or `s-`), `Alt-` (or + * `a-`), `Ctrl-` (or `c-` or `Control-`) and `Cmd-` (or `m-` or + * `Meta-`) are recognized. For characters that are created by holding + * shift, the `Shift-` prefix is implied, and should not be added + * explicitly. + * + * You can use `Mod-` as a shorthand for `Cmd-` on Mac and `Ctrl-` on + * other platforms. + * + * You can add multiple keymap plugins to an editor. The order in + * which they appear determines their precedence (the ones early in + * the array get to dispatch first). + */ +export function keymap(bindings: { [key: string]: any }): Plugin; +/** + * Given a set of bindings (using the same format as + * [`keymap`](#keymap.keymap), return a [keydown + * handler](#view.EditorProps.handleKeyDown) handles them. + */ +export function keydownHandler(bindings: { [key: string]: any }): (view: EditorView, event: Event) => boolean; diff --git a/types/prosemirror-markdown/index.d.ts b/types/prosemirror-markdown/index.d.ts index 0f91962dd6..6617166c6e 100644 --- a/types/prosemirror-markdown/index.d.ts +++ b/types/prosemirror-markdown/index.d.ts @@ -1,60 +1,176 @@ -// Type definitions for prosemirror-markdown 0.21 +// Type definitions for prosemirror-markdown 1.0 // Project: https://github.com/ProseMirror/prosemirror-markdown // Definitions by: Bradley Ayers +// David Hahn +// Tim Baumann // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.3 +// TypeScript Version: 2.1 + +// IMPORTANT +// This file was generated by https://github.com/bradleyayers/getdocs2ts. Please do not edit manually. +// When you find an error in these declarations, fix the getdocs comment upstream or 'getdocs2ts', then regenerate. import { MarkdownIt } from 'markdown-it'; -import { Mark, Node, Schema } from 'prosemirror-model'; +import { Node as ProsemirrorNode, Schema } from 'prosemirror-model'; +/** + * A configuration of a Markdown parser. Such a parser uses + * [markdown-it](https://github.com/markdown-it/markdown-it) to + * tokenize a file, and then runs the custom rules it is given over + * the tokens to create a ProseMirror document tree. + */ export class MarkdownParser { + /** + * Create a parser with the given configuration. You can configure + * the markdown-it parser to parse the dialect you want, and provide + * a description of the ProseMirror entities those tokens map to in + * the `tokens` object, which maps token names to descriptions of + * what to do with them. Such a description is an object, and may + * have the following properties: + * + * **`node`**`: ?string` + * : This token maps to a single node, whose type can be looked up + * in the schema under the given name. Exactly one of `node`, + * `block`, or `mark` must be set. + * + * **`block`**`: ?string` + * : This token comes in `_open` and `_close` variants (which are + * appended to the base token name provides a the object + * property), and wraps a block of content. The block should be + * wrapped in a node of the type named to by the property's + * value. + * + * **`mark`**`: ?string` + * : This token also comes in `_open` and `_close` variants, but + * should add a mark (named by the value) to its content, rather + * than wrapping it in a node. + * + * **`attrs`**`: ?Object` + * : Attributes for the node or mark. When `getAttrs` is provided, + * it takes precedence. + * + * **`getAttrs`**`: ?(MarkdownToken) → Object` + * : A function used to compute the attributes for the node or mark + * that takes a [markdown-it + * token](https://markdown-it.github.io/markdown-it/#Token) and + * returns an attribute object. + * + * **`ignore`**`: ?bool` + * : When true, ignore content for the matched token. + */ constructor(schema: Schema, tokenizer: MarkdownIt, tokens: { [key: string]: any }); + /** + * The value of the `tokens` object used to construct + * this parser. Can be useful to copy and modify to base other + * parsers on. + */ + tokens: { [key: string]: any }; + /** + * Parse a string as [CommonMark](http://commonmark.org/) markup, + * and create a ProseMirror document as prescribed by this parser's + * rules. + */ + parse(text: string): ProsemirrorNode; } - -export type NodeSerializer = (state: MarkdownSerializerState, node?: Node, parent?: Node, index?: number) => void; - -export interface MarkSerializer { - open: string | ((state: MarkdownSerializerState, mark: Mark) => string); - close: string | ((state: MarkdownSerializerState, mark: Mark) => string); - mixable?: boolean; -} - -export interface NodeSerializerSpec { - [ nodeName: string ]: NodeSerializer; -} - -export interface MarkSerializerSpec { - [ markName: string ]: MarkSerializer; -} - +/** + * A parser parsing unextended [CommonMark](http://commonmark.org/), + * without inline HTML, and producing a document in the basic schema. + */ +export let defaultMarkdownParser: MarkdownParser; +/** + * A specification for serializing a ProseMirror document as + * Markdown/CommonMark text. + */ export class MarkdownSerializer { - constructor(nodes: NodeSerializerSpec, marks: MarkSerializerSpec); - serialize(content: Node, options?: { [key: string]: any }): string; - nodes: any; - marks: any; + constructor(nodes: { [name: string]: (state: MarkdownSerializerState, node: ProsemirrorNode, parent: ProsemirrorNode, index: number) => void }, marks: { [key: string]: any }); + /** + * The node serializer + * functions for this serializer. + */ + nodes: { [name: string]: (p1: MarkdownSerializerState, p2: ProsemirrorNode) => void }; + /** + * The mark serializer info. + */ + marks: { [key: string]: any }; + /** + * Serialize the content of the given node to + * [CommonMark](http://commonmark.org/). + */ + serialize(content: ProsemirrorNode, options?: { [key: string]: any }): string; } - -export const defaultMarkdownSerializer: MarkdownSerializer; - +/** + * A serializer for the [basic schema](#schema). + */ +export let defaultMarkdownSerializer: MarkdownSerializer; +/** + * This is an object used to track state and expose + * methods related to markdown serialization. Instances are passed to + * node and mark serialization methods (see `toMarkdown`). + */ export class MarkdownSerializerState { - constructor(nodes: NodeSerializerSpec, marks: MarkSerializerSpec, options?: object); - flushClose(size: number): void; - wrapBlock(delim: string, firstDelim: string | null, node: Node, f: (...args: any[]) => void): void; - atBlank(): boolean; + /** + * The options passed to the serializer. + */ + options: { tightLists?: boolean | null }; + /** + * Render a block, prefixing each line with `delim`, and the first + * line in `firstDelim`. `node` should be the node that is closed at + * the end of the block, and `f` is a function that renders the + * content of the block. + */ + wrapBlock(delim: string, firstDelim: string | undefined, node: ProsemirrorNode, f: () => void): void; + /** + * Ensure the current content ends with a newline. + */ ensureNewLine(): void; + /** + * Prepare the state for writing output (closing closed paragraphs, + * adding delimiters, and so on), and then optionally add content + * (unescaped) to the output. + */ write(content?: string): void; - closeBlock(node: Node): void; + /** + * Close the block for the given node. + */ + closeBlock(node: ProsemirrorNode): void; + /** + * Add the given text to the document. When escape is not `false`, + * it will be escaped. + */ text(text: string, escape?: boolean): void; - render(node: Node, parent: Node, index: number): void; - renderContent(parent: Node): void; - renderInline(parent: Node): void; - renderList(node: Node, delim: string, firstDelim: (number: number) => string): void; + /** + * Render the given node as a block. + */ + render(node: ProsemirrorNode): void; + /** + * Render the contents of `parent` as block nodes. + */ + renderContent(parent: ProsemirrorNode): void; + /** + * Render the contents of `parent` as inline content. + */ + renderInline(parent: ProsemirrorNode): void; + /** + * Render a node's content as a list. `delim` should be the extra + * indentation added to all lines except the first in an item, + * `firstDelim` is a function going from an item index to a + * delimiter for the first line of the item. + */ + renderList(node: ProsemirrorNode, delim: string, firstDelim: (p: number) => string): void; + /** + * Escape the given string so that it can safely appear in Markdown + * content. If `startOfLine` is true, also escape characters that + * has special meaning only at the start of the line. + */ esc(str: string, startOfLine?: boolean): string; - quote(str: string): string; + /** + * Repeat the given string `n` times. + */ repeat(str: string, n: number): string; - markString(mark: Mark, open: boolean): string; - out: any; - closed: any; - nodes: any; - marks: any; + /** + * Get leading and trailing whitespace from a string. Values of + * leading or trailing property of the return object will be undefined + * if there is no match. + */ + getEnclosingWhitespace(text: string): { leading?: string | null, trailing?: string | null }; } diff --git a/types/prosemirror-menu/index.d.ts b/types/prosemirror-menu/index.d.ts index 43b4cf59d6..898fdffd20 100644 --- a/types/prosemirror-menu/index.d.ts +++ b/types/prosemirror-menu/index.d.ts @@ -1,49 +1,214 @@ -// Type definitions for prosemirror-menu 0.21 +// Type definitions for prosemirror-menu 1.0 // Project: https://github.com/ProseMirror/prosemirror-menu -// Definitions by: David Hahn +// Definitions by: Bradley Ayers +// David Hahn +// Tim Baumann // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.3 +// TypeScript Version: 2.1 + +// IMPORTANT +// This file was generated by https://github.com/bradleyayers/getdocs2ts. Please do not edit manually. +// When you find an error in these declarations, fix the getdocs comment upstream or 'getdocs2ts', then regenerate. import { NodeType } from 'prosemirror-model'; import { EditorState, Plugin, Transaction } from 'prosemirror-state'; -import { EditorProps, EditorView } from 'prosemirror-view'; +import { EditorView } from 'prosemirror-view'; +/** + * The types defined in this module aren't the only thing you can + * display in your menu. Anything that conforms to this interface can + * be put into a menu structure. + */ export interface MenuElement { - render(pm: any): Node; + /** + * Render the element for display in the menu. Must return a DOM + * element and a function that can be used to update the element to + * a new state. The `update` function will return false if the + * update hid the entire element. + */ + render(pm: EditorView): { dom: Node, update(p: EditorState): boolean }; } +/** + * An icon or label that, when clicked, executes a command. + */ export class MenuItem { - constructor(spec: MenuItemSpec) + constructor(spec: MenuItemSpec); + /** + * The spec used to create the menu item. + */ spec: MenuItemSpec; - render(view: EditorView): Node; + /** + * Renders the icon according to its [display + * spec](#menu.MenuItemSpec.display), and adds an event handler which + * executes the command when the representation is clicked. + */ + render(view: EditorView): { dom: Node, update(p: EditorState): boolean }; } +/** + * The configuration object passed to the `MenuItem` constructor. + */ export interface MenuItemSpec { - run(p1: EditorState, fn: (p: Transaction) => void, p2: EditorView, ev: Event): void; - select?(p: EditorState): boolean; - onDeselected?: string; - active?(p: EditorState): boolean; - render?(p: EditorView): Node; - icon?: { [key: string]: any }; - label?: string; - title?: string | ((s: EditorState) => string); + /** + * The function to execute when the menu item is activated. + */ + run(p1: EditorState, p2: (p: Transaction) => void, p3: EditorView, p4: Event): void; + /** + * Optional function that is used to determine whether the item is + * appropriate at the moment. Deselected items will be hidden. + */ + select?: ((p: EditorState) => boolean) | null; + /** + * Function that is used to determine if the item is enabled. If + * given and returning false, the item will be given a disabled + * styling. + */ + enable?: ((p: EditorState) => boolean) | null; + /** + * A predicate function to determine whether the item is 'active' (for + * example, the item for toggling the strong mark might be active then + * the cursor is in strong text). + */ + active?: ((p: EditorState) => boolean) | null; + /** + * A function that renders the item. You must provide either this, + * [`icon`](#menu.MenuItemSpec.icon), or [`label`](#MenuItemSpec.label). + */ + render?: ((p: EditorView) => Node) | null; + /** + * Describes an icon to show for this item. The object may specify + * an SVG icon, in which case its `path` property should be an [SVG + * path + * spec](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/d), + * and `width` and `height` should provide the viewbox in which that + * path exists. Alternatively, it may have a `text` property + * specifying a string of text that makes up the icon, with an + * optional `css` property giving additional CSS styling for the + * text. _Or_ it may contain `dom` property containing a DOM node. + */ + icon?: { [key: string]: any } | null; + /** + * Makes the item show up as a text label. Mostly useful for items + * wrapped in a [drop-down](#menu.Dropdown) or similar menu. The object + * should have a `label` property providing the text to display. + */ + label?: string | null; + /** + * Defines DOM title (mouseover) text for the item. + */ + title?: string | ((p: EditorState) => string) | null; + /** + * Optionally adds a CSS class to the item's DOM representation. + */ class: string; + /** + * Optionally adds a string of inline CSS to the item's DOM + * representation. + */ css: string; + /** + * Defines which event on the command's DOM representation should + * trigger the execution of the command. Defaults to mousedown. + */ execEvent: string; } +/** + * A drop-down menu, displayed as a label with a downwards-pointing + * triangle to the right of it. + */ export class Dropdown { - constructor(content: MenuElement[], options?: object) - render(view: EditorView): Node; + /** + * Create a dropdown wrapping the elements. Options may include + * the following properties: + * + * **`label`**`: string` + * : The label to show on the drop-down control. + * + * **`title`**`: string` + * : Sets the + * [`title`](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/title) + * attribute given to the menu control. + * + * **`class`**`: string` + * : When given, adds an extra CSS class to the menu control. + * + * **`css`**`: string` + * : When given, adds an extra set of CSS styles to the menu control. + */ + constructor(content: MenuElement[], options?: { [key: string]: any }); + /** + * Render the dropdown menu and sub-items. + */ + render(view: EditorView): { dom: Node, update(p: EditorState): void }; } +/** + * Represents a submenu wrapping a group of elements that start + * hidden and expand to the right when hovered over or tapped. + */ export class DropdownSubmenu { - constructor(content: MenuElement[], options?: object) - render(view: EditorView): Node; + /** + * Creates a submenu for the given group of menu elements. The + * following options are recognized: + * + * **`label`**`: string` + * : The label to show on the submenu. + */ + constructor(content: MenuElement[], options?: { [key: string]: any }); + /** + * Renders the submenu. + */ + render(view: EditorView): { dom: Node, update(p: EditorState): boolean }; } -export function renderGrouped(view: EditorView, content: MenuElement | MenuElement[][]): DocumentFragment; +/** + * Render the given, possibly nested, array of menu elements into a + * document fragment, placing separators between them (and ensuring no + * superfluous separators appear when some of the groups turn out to + * be empty). + */ +export function renderGrouped(view: EditorView, content: Array): { dom?: DocumentFragment | null, update(p: EditorState): boolean }; +/** + * A set of basic editor-related icons. Contains the properties + * `join`, `lift`, `selectParentNode`, `undo`, `redo`, `strong`, `em`, + * `code`, `link`, `bulletList`, `orderedList`, and `blockquote`, each + * holding an object that can be used as the `icon` option to + * `MenuItem`. + */ export let icons: { [key: string]: any }; +/** + * Menu item for the `joinUp` command. + */ export let joinUpItem: MenuItem; +/** + * Menu item for the `lift` command. + */ export let liftItem: MenuItem; +/** + * Menu item for the `selectParentNode` command. + */ export let selectParentNodeItem: MenuItem; -export function undoItem(p: object): MenuItem; -export function redoItem(p: object): MenuItem; -export function wrapItem(nodeType: NodeType, options: object): MenuItem; -export function blockTypeItem(nodeType: NodeType, options: object): MenuItem; -export function menuBar(options: { content: MenuElement[][], floating?: boolean }): Plugin; +/** + * Menu item for the `undo` command. + */ +export function undoItem(p: { [key: string]: any }): MenuItem; +/** + * Menu item for the `redo` command. + */ +export function redoItem(p: { [key: string]: any }): MenuItem; +/** + * Build a menu item for wrapping the selection in a given node type. + * Adds `run` and `select` properties to the ones present in + * `options`. `options.attrs` may be an object or a function, as in + * `toggleMarkItem`. + */ +export function wrapItem(nodeType: NodeType, options: { [key: string]: any }): MenuItem; +/** + * Build a menu item for changing the type of the textblock around the + * selection to the given type. Provides `run`, `active`, and `select` + * properties. Others must be given in `options`. `options.attrs` may + * be an object to provide the attributes for the textblock node. + */ +export function blockTypeItem(nodeType: NodeType, options: { [key: string]: any }): MenuItem; +/** + * A plugin that will place a menu bar above the editor. Note that + * this involves wrapping the editor in an additional `
`. + */ +export function menuBar(options: { content: MenuElement[][], floating?: boolean | null }): Plugin; diff --git a/types/prosemirror-model/dom.d.ts b/types/prosemirror-model/dom.d.ts deleted file mode 100644 index b4b02d1c24..0000000000 --- a/types/prosemirror-model/dom.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -export type DOMDataTransfer = DataTransfer; -export type DOMDocument = Document; -export type DOMElement = HTMLElement; -export type DOMEvent = Event; -export type DOMFragment = DocumentFragment; -export type DOMKeyboardEvent = KeyboardEvent; -export type DOMMouseEvent = MouseEvent; -export type DOMMutationRecord = MutationRecord; -export type DOMNode = Node; - -export { - DOMDataTransfer as DataTransfer, - DOMDocument as Document, - DOMElement as Element, - DOMEvent as Event, - DOMFragment as DocumentFragment, - DOMKeyboardEvent as KeyboardEvent, - DOMMouseEvent as MouseEvent, - DOMMutationRecord as MutationRecord, - DOMNode as Node, -}; diff --git a/types/prosemirror-model/index.d.ts b/types/prosemirror-model/index.d.ts index 805e9fe46d..cb93cf851c 100644 --- a/types/prosemirror-model/index.d.ts +++ b/types/prosemirror-model/index.d.ts @@ -1,259 +1,1290 @@ -// Type definitions for prosemirror-model 0.24 +// Type definitions for prosemirror-model 1.0 // Project: https://github.com/ProseMirror/prosemirror-model // Definitions by: Bradley Ayers // David Hahn +// Tim Baumann // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.1 +// IMPORTANT +// This file was generated by https://github.com/bradleyayers/getdocs2ts. Please do not edit manually. +// When you find an error in these declarations, fix the getdocs comment upstream or 'getdocs2ts', then regenerate. + import OrderedMap = require('orderedmap'); -import * as dom from './dom'; - -export interface AnyObject { - [key: string]: any; -} +/** + * Instances of this class represent a match state of a node + * type's [content expression](#model.NodeSpec.content), and can be + * used to find out whether further content matches here, and whether + * a given position is a valid end of the node. + */ export class ContentMatch { - matchType(type: NodeType, attrs?: AnyObject, marks?: Mark[]): ContentMatch | null | undefined; - matchFragment(fragment: Fragment, from?: number, to?: number): ContentMatch | boolean | null | undefined; + /** + * True when this match state represents a valid end of the node. + */ validEnd: boolean; - fillBefore(after: Fragment, toEnd: boolean, startIndex?: number): Fragment | null | undefined; - findWrapping(target: NodeType): NodeType[] | null; + /** + * Match a node type and marks, returning a match after that node + * if successful. + */ + matchType(type: NodeType): ContentMatch | null | void; + /** + * Try to match a fragment. Returns the resulting match when + * successful. + */ + matchFragment(frag: Fragment, start?: number, end?: number): ContentMatch | null | void; + /** + * Try to match the given fragment, and if that fails, see if it can + * be made to match by inserting nodes in front of it. When + * successful, return a fragment of inserted nodes (which may be + * empty if nothing had to be inserted). When `toEnd` is true, only + * return a fragment if the resulting match goes to the end of the + * content expression. + */ + fillBefore(after: Fragment, toEnd?: boolean, startIndex?: number): Fragment | null | void; + /** + * Find a set of wrapping node types that would allow a node of the + * given type to appear at this position. The result may be empty + * (when it fits directly) and will be null when no such wrapping + * exists. + */ + findWrapping(target: NodeType): NodeType[] | null | void; } +/** + * A fragment represents a node's collection of child nodes. + * + * Like nodes, fragments are persistent data structures, and you + * should not mutate them or their content. Rather, you create new + * instances whenever needed. The API tries to make this easy. + */ export class Fragment { + /** + * The size of the fragment, which is the total of the size of its + * content nodes. + */ size: number; - nodesBetween(from: number, to: number, f: (node: Node, start: number, parent: Node, index: number) => boolean | null | void): void; - descendants(f: (node: Node, pos: number, parent: Node) => boolean | null | void): void; + /** + * Invoke a callback for all descendant nodes between the given two + * positions (relative to start of this fragment). Doesn't descend + * into a node when the callback returns `false`. + */ + nodesBetween(from: number, to: number, f: (node: ProsemirrorNode, start: number, parent: ProsemirrorNode, index: number) => boolean | null | void): void; + /** + * Call the given callback for every descendant node. The callback + * may return `false` to prevent traversal of a given node's children. + */ + descendants(f: (node: ProsemirrorNode, pos: number, parent: ProsemirrorNode) => boolean | null | void): void; + /** + * Create a new fragment containing the combined content of this + * fragment and the other. + */ append(other: Fragment): Fragment; + /** + * Cut out the sub-fragment between the two given positions. + */ cut(from: number, to?: number): Fragment; - replaceChild(index: number, node: Node): Fragment; + /** + * Create a new fragment in which the node at the given index is + * replaced by the given node. + */ + replaceChild(index: number, node: ProsemirrorNode): Fragment; + /** + * Compare this fragment to another one. + */ eq(other: Fragment): boolean; - firstChild?: Node | null; - lastChild?: Node | null; + /** + * The first child of the fragment, or `null` if it is empty. + */ + firstChild?: ProsemirrorNode | null; + /** + * The last child of the fragment, or `null` if it is empty. + */ + lastChild?: ProsemirrorNode | null; + /** + * The number of child nodes in this fragment. + */ childCount: number; - child(index: number): Node; - maybeChild(index: number): Node | null | undefined; - forEach(f: (node: Node, offset: number, index: number) => void): void; - findDiffStart(other: Fragment): number | null | undefined; - findDiffEnd(other: Node): { a: number, b: number } | null | undefined; + /** + * Get the child node at the given index. Raise an error when the + * index is out of range. + */ + child(index: number): ProsemirrorNode; + /** + * Get the child node at the given index, if it exists. + */ + maybeChild(index: number): ProsemirrorNode | null | void; + /** + * Call `f` for every child node, passing the node, its offset + * into this parent node, and its index. + */ + forEach(f: (node: ProsemirrorNode, offset: number, index: number) => void): void; + /** + * Find the first position at which this fragment and another + * fragment differ, or `null` if they are the same. + */ + findDiffStart(other: Fragment): number | null | void; + /** + * Find the first position, searching from the end, at which this + * fragment and the given fragment differ, or `null` if they are the + * same. Since this position will not be the same in both nodes, an + * object with two separate positions is returned. + */ + findDiffEnd(other: ProsemirrorNode): { a: number, b: number } | null | void; + /** + * Return a debugging string that describes this fragment. + */ toString(): string; - toJSON(): AnyObject | null | undefined; - static fromJSON(schema: Schema, value?: AnyObject): Fragment; - static fromArray(array: Node[]): Fragment; - static from(nodes?: Fragment | Node | Node[]): Fragment; + /** + * Create a JSON-serializeable representation of this fragment. + */ + toJSON(): { [key: string]: any } | null | void; + /** + * Deserialize a fragment from its JSON representation. + */ + static fromJSON(schema: Schema, value?: { [key: string]: any }): Fragment; + /** + * Build a fragment from an array of nodes. Ensures that adjacent + * text nodes with the same marks are joined together. + */ + static fromArray(array: ProsemirrorNode[]): Fragment; + /** + * Create a fragment from something that can be interpreted as a set + * of nodes. For `null`, it returns the empty fragment. For a + * fragment, the fragment itself. For a node or array of nodes, a + * fragment containing those nodes. + */ + static from(nodes?: Fragment | ProsemirrorNode | ProsemirrorNode[]): Fragment; + /** + * An empty fragment. Intended to be reused whenever a node doesn't + * contain anything (rather than allocating a new empty fragment for + * each leaf node). + */ static empty: Fragment; } -export interface ParseRule { - tag?: string | null; - namespace?: string | null; - style?: string | null; - context?: string | null; - node?: string | null; - mark?: string | null; - priority?: number | null; - ignore?: boolean | null; - skip?: boolean | null; - attrs?: AnyObject | null; - getAttrs?: ((p: dom.Node | string) => boolean | AnyObject | null | void) | null; - contentElement?: string | ((p: dom.Node) => dom.Node) | null; - getContent?: ((p: dom.Node) => Fragment) | null; - preserveWhitespace?: boolean | 'full' | null; +/** + * These are the options recognized by the + * [`parse`](#model.DOMParser.parse) and + * [`parseSlice`](#model.DOMParser.parseSlice) methods. + */ +export interface ParseOptions { + /** + * By default, whitespace is collapsed as per HTML's rules. Pass + * `true` to preserve whitespace, but normalize newlines to + * spaces, and `"full"` to preserve whitespace entirely. + */ + preserveWhitespace?: boolean | "full" | null; + /** + * When given, the parser will, beside parsing the content, + * record the document positions of the given DOM positions. It + * will do so by writing to the objects, adding a `pos` property + * that holds the document position. DOM positions that are not + * in the parsed content will not be written to. + */ + findPositions?: Array<{ node: Node, offset: number }> | null; + /** + * The child node index to start parsing from. + */ + from?: number | null; + /** + * The child node index to stop parsing at. + */ + to?: number | null; + /** + * By default, the content is parsed into the schema's default + * [top node type](#model.Schema.topNodeType). You can pass this + * option to use the type and attributes from a different node + * as the top container. + */ + topNode?: ProsemirrorNode | null; + /** + * Provide the starting content match that content parsed into the + * top node is matched against. + */ + topMatch?: ContentMatch | null; + /** + * A set of additional nodes to count as + * [context](#model.ParseRule.context) when parsing, above the + * given [top node](#model.ParseOptions.topNode). + */ + context?: ResolvedPos | null; } +/** + * A value that describes how to parse a given DOM node or inline + * style as a ProseMirror node or mark. + */ +export interface ParseRule { + /** + * A CSS selector describing the kind of DOM elements to match. A + * single rule should have _either_ a `tag` or a `style` property. + */ + tag?: string | null; + /** + * The namespace to match. This should be used with `tag`. + * Nodes are only matched when the namespace matches or this property + * is null. + */ + namespace?: string | null; + /** + * A CSS property name to match. When given, this rule matches + * inline styles that list that property. May also have the form + * `"property=value"`, in which case the rule only matches if the + * propery's value exactly matches the given value. (For more + * complicated filters, use [`getAttrs`](#model.ParseRule.getAttrs) + * and return undefined to indicate that the match failed.) + */ + style?: string | null; + /** + * Can be used to change the order in which the parse rules in a + * schema are tried. Those with higher priority come first. Rules + * without a priority are counted as having priority 50. This + * property is only meaningful in a schema—when directly + * constructing a parser, the order of the rule array is used. + */ + priority?: number | null; + /** + * When given, restricts this rule to only match when the current + * context—the parent nodes into which the content is being + * parsed—matches this expression. Should contain one or more node + * names or node group names followed by single or double slashes. + * For example `"paragraph/"` means the rule only matches when the + * parent node is a paragraph, `"blockquote/paragraph/"` restricts + * it to be in a paragraph that is inside a blockquote, and + * `"section//"` matches any position inside a section—a double + * slash matches any sequence of ancestor nodes. To allow multiple + * different contexts, they can be separated by a pipe (`|`) + * character, as in `"blockquote/|list_item/"`. + */ + context?: string | null; + /** + * The name of the node type to create when this rule matches. Only + * valid for rules with a `tag` property, not for style rules. Each + * rule should have one of a `node`, `mark`, or `ignore` property + * (except when it appears in a [node](#model.NodeSpec.parseDOM) or + * [mark spec](#model.MarkSpec.parseDOM), in which case the `node` + * or `mark` property will be derived from its position). + */ + node?: string | null; + /** + * The name of the mark type to wrap the matched content in. + */ + mark?: string | null; + /** + * When true, ignore content that matches this rule. + */ + ignore?: boolean | null; + /** + * When true, ignore the node that matches this rule, but do parse + * its content. + */ + skip?: boolean | null; + /** + * Attributes for the node or mark created by this rule. When + * `getAttrs` is provided, it takes precedence. + */ + attrs?: { [key: string]: any } | null; + /** + * A function used to compute the attributes for the node or mark + * created by this rule. Can also be used to describe further + * conditions the DOM element or style must match. When it returns + * `false`, the rule won't match. When it returns null or undefined, + * that is interpreted as an empty/default set of attributes. + * + * Called with a DOM Element for `tag` rules, and with a string (the + * style's value) for `style` rules. + */ + getAttrs?: ((p: Node | string) => { [key: string]: any } | false | null | void) | null; + /** + * For `tag` rules that produce non-leaf nodes or marks, by default + * the content of the DOM element is parsed as content of the mark + * or node. If the child nodes are in a descendent node, this may be + * a CSS selector string that the parser must use to find the actual + * content element, or a function that returns the actual content + * element to the parser. + */ + contentElement?: string | ((p: Node) => Node) | null; + /** + * Can be used to override the content of a matched node. When + * present, instead of parsing the node's child nodes, the result of + * this function is used. + */ + getContent?: ((p: Node) => Fragment) | null; + /** + * Controls whether whitespace should be preserved when parsing the + * content inside the matched element. `false` means whitespace may + * be collapsed, `true` means that whitespace should be preserved + * but newlines normalized to spaces, and `"full"` means that + * newlines should also be preserved. + */ + preserveWhitespace?: boolean | "full" | null; +} +/** + * A DOM parser represents a strategy for parsing DOM content into + * a ProseMirror document conforming to a given schema. Its behavior + * is defined by an array of [rules](#model.ParseRule). + */ export class DOMParser { - constructor(schema: Schema, rules: ParseRule[]) + /** + * Create a parser that targets the given schema, using the given + * parsing rules. + */ + constructor(schema: Schema, rules: ParseRule[]); + /** + * The schema into which the parser parses. + */ schema: Schema; + /** + * The set of [parse rules](#model.ParseRule) that the parser + * uses, in order of precedence. + */ rules: ParseRule[]; - parse(dom: dom.Node, options?: { - preserveWhitespace?: boolean | 'full' | null, - findPositions?: Array<{ node: Node, offset: number }> | null, - from?: number | null, - to?: number | null, - topNode?: Node | null, - topMatch?: ContentMatch | null, - context?: ResolvedPos | null - }): Node; - parseSlice(dom: dom.Node, options?: AnyObject): Slice; + /** + * Parse a document from the content of a DOM node. + */ + parse(dom: Node, options?: ParseOptions): ProsemirrorNode; + /** + * Parses the content of the given DOM node, like + * [`parse`](#model.DOMParser.parse), and takes the same set of + * options. But unlike that method, which produces a whole node, + * this one returns a slice that is open at the sides, meaning that + * the schema constraints aren't applied to the start of nodes to + * the left of the input and the end of nodes at the end. + */ + parseSlice(dom: Node, options?: ParseOptions): Slice; + /** + * Construct a DOM parser using the parsing rules listed in a + * schema's [node specs](#model.NodeSpec.parseDOM), reordered by + * [priority](#model.ParseRule.priority). + */ static fromSchema(schema: Schema): DOMParser; } +/** + * A mark is a piece of information that can be attached to a node, + * such as it being emphasized, in code font, or a link. It has a type + * and optionally a set of attributes that provide further information + * (such as the target of the link). Marks are created through a + * `Schema`, which controls which types exist and which + * attributes they have. + */ export class Mark { + /** + * The type of this mark. + */ type: MarkType; - attrs: AnyObject; + /** + * The attributes associated with this mark. + */ + attrs: { [key: string]: any }; + /** + * Given a set of marks, create a new set which contains this one as + * well, in the right position. If this mark is already in the set, + * the set itself is returned. If any marks that are set to be + * [exclusive](#model.MarkSpec.excludes) with this mark are present, + * those are replaced by this one. + */ addToSet(set: Mark[]): Mark[]; + /** + * Remove this mark from the given set, returning a new set. If this + * mark is not in the set, the set itself is returned. + */ removeFromSet(set: Mark[]): Mark[]; + /** + * Test whether this mark is in the given set of marks. + */ isInSet(set: Mark[]): boolean; + /** + * Test whether this mark has the same type and attributes as + * another mark. + */ eq(other: Mark): boolean; - toJSON(): AnyObject; - static fromJSON(schema: Schema, json: AnyObject): Mark; + /** + * Convert this mark to a JSON-serializeable representation. + */ + toJSON(): { [key: string]: any }; + static fromJSON(schema: Schema, json: { [key: string]: any }): Mark; + /** + * Test whether two sets of marks are identical. + */ static sameSet(a: Mark[], b: Mark[]): boolean; + /** + * Create a properly sorted mark set from null, a single mark, or an + * unsorted array of marks. + */ static setFrom(marks?: Mark | Mark[]): Mark[]; + /** + * The empty set of marks. + */ static none: Mark[]; } -export class Node { +/** + * This class represents a node in the tree that makes up a + * ProseMirror document. So a document is an instance of `Node`, with + * children that are also instances of `Node`. + * + * Nodes are persistent data structures. Instead of changing them, you + * create new ones with the content you want. Old ones keep pointing + * at the old document shape. This is made cheaper by sharing + * structure between the old and new data as much as possible, which a + * tree shape like this (without back pointers) makes easy. + * + * **Do not** directly mutate the properties of a `Node` object. See + * [the guide](/docs/guide/#doc) for more information. + */ +declare class ProsemirrorNode { + /** + * The type of node that this is. + */ type: NodeType; + /** + * An object mapping attribute names to values. The kind of + * attributes allowed and required are + * [determined](#model.NodeSpec.attrs) by the node type. + */ attrs: { [key: string]: any }; + /** + * A container holding the node's children. + */ content: Fragment; + /** + * The marks (things like whether it is emphasized or part of a + * link) applied to this node. + */ marks: Mark[]; + /** + * For text nodes, this contains the node's text content. + */ text?: string | null; + /** + * The size of this node, as defined by the integer-based [indexing + * scheme](/docs/guide/#doc.indexing). For text nodes, this is the + * amount of characters. For other leaf nodes, it is one. For + * non-leaf nodes, it is the size of the content plus two (the start + * and end token). + */ nodeSize: number; + /** + * The number of children that the node has. + */ childCount: number; - child(index: number): Node; - maybeChild(index: number): Node | null | undefined; - forEach(f: (node: Node, offset: number, index: number) => void): void; - nodesBetween(from: number | undefined, to: number | undefined, f: (node: Node, pos: number, parent: Node, index: number) => boolean | null | void): void; - descendants(f: (node: Node, pos: number, parent: Node) => boolean | null | void): void; + /** + * Get the child node at the given index. Raises an error when the + * index is out of range. + */ + child(index: number): ProsemirrorNode; + /** + * Get the child node at the given index, if it exists. + */ + maybeChild(index: number): ProsemirrorNode | null | void; + /** + * Call `f` for every child node, passing the node, its offset + * into this parent node, and its index. + */ + forEach(f: (node: ProsemirrorNode, offset: number, index: number) => void): void; + /** + * Invoke a callback for all descendant nodes recursively between + * the given two positions that are relative to start of this node's + * content. The callback is invoked with the node, its + * parent-relative position, its parent node, and its child index. + * When the callback returns false for a given node, that node's + * children will not be recursed over. + */ + nodesBetween(from: number, to: number, f: (node: ProsemirrorNode, pos: number, parent: ProsemirrorNode, index: number) => boolean | null | void): void; + /** + * Call the given callback for every descendant node. Doesn't + * descend into a node when the callback returns `false`. + */ + descendants(f: (node: ProsemirrorNode, pos: number, parent: ProsemirrorNode) => boolean | null | void): void; + /** + * Concatenates all the text nodes found in this fragment and its + * children. + */ textContent: string; + /** + * Get all text between positions `from` and `to`. When + * `blockSeparator` is given, it will be inserted whenever a new + * block node is started. When `leafText` is given, it'll be + * inserted for every non-text leaf node encountered. + */ textBetween(from: number, to: number, blockSeparator?: string, leafText?: string): string; - firstChild?: Node | null; - lastChild?: Node | null; - eq(other: Node): boolean; - sameMarkup(other: Node): boolean; - hasMarkup(type: NodeType, attrs?: AnyObject, marks?: Mark[]): boolean; - copy(content?: Fragment): Node; - mark(marks: Mark[]): Node; - cut(from: number, to?: number): Node; + /** + * Returns this node's first child, or `null` if there are no + * children. + */ + firstChild?: ProsemirrorNode | null; + /** + * Returns this node's last child, or `null` if there are no + * children. + */ + lastChild?: ProsemirrorNode | null; + /** + * Test whether two nodes represent the same piece of document. + */ + eq(other: ProsemirrorNode): boolean; + /** + * Compare the markup (type, attributes, and marks) of this node to + * those of another. Returns `true` if both have the same markup. + */ + sameMarkup(other: ProsemirrorNode): boolean; + /** + * Check whether this node's markup correspond to the given type, + * attributes, and marks. + */ + hasMarkup(type: NodeType, attrs?: { [key: string]: any }, marks?: Mark[]): boolean; + /** + * Create a new node with the same markup as this node, containing + * the given content (or empty, if no content is given). + */ + copy(content?: Fragment): ProsemirrorNode; + /** + * Create a copy of this node, with the given set of marks instead + * of the node's own marks. + */ + mark(marks: Mark[]): ProsemirrorNode; + /** + * Create a copy of this node with only the content between the + * given positions. If `to` is not given, it defaults to the end of + * the node. + */ + cut(from: number, to?: number): ProsemirrorNode; + /** + * Cut out the part of the document between the given positions, and + * return it as a `Slice` object. + */ slice(from: number, to?: number): Slice; - replace(from: number, to: number, slice: Slice): Node; - nodeAt(pos: number): Node | null | undefined; - childAfter(pos: number): { node?: Node | null, index: number, offset: number }; - childBefore(pos: number): { node?: Node | null, index: number, offset: number }; + /** + * Replace the part of the document between the given positions with + * the given slice. The slice must 'fit', meaning its open sides + * must be able to connect to the surrounding content, and its + * content nodes must be valid children for the node they are placed + * into. If any of this is violated, an error of type + * [`ReplaceError`](#model.ReplaceError) is thrown. + */ + replace(from: number, to: number, slice: Slice): ProsemirrorNode; + /** + * Find the node starting at the given position. + */ + nodeAt(pos: number): ProsemirrorNode | null | void; + /** + * Find the (direct) child node after the given offset, if any, + * and return it along with its index and offset relative to this + * node. + */ + childAfter(pos: number): { node?: ProsemirrorNode | null, index: number, offset: number }; + /** + * Find the (direct) child node before the given offset, if any, + * and return it along with its index and offset relative to this + * node. + */ + childBefore(pos: number): { node?: ProsemirrorNode | null, index: number, offset: number }; + /** + * Resolve the given position in the document, returning an + * [object](#model.ResolvedPos) with information about its context. + */ resolve(pos: number): ResolvedPos; - rangeHasMark(from: number | undefined, to: number | undefined, type: MarkType): boolean; + /** + * Test whether a mark of the given type occurs in this document + * between the two given positions. + */ + rangeHasMark(from: number, to: number, type: MarkType): boolean; + /** + * True when this is a block (non-inline node) + */ isBlock: boolean; + /** + * True when this is a textblock node, a block node with inline + * content. + */ isTextblock: boolean; + /** + * True when this node has inline content. + */ inlineContent: boolean; + /** + * True when this is an inline node (a text node or a node that can + * appear among text). + */ isInline: boolean; + /** + * True when this is a text node. + */ isText: boolean; + /** + * True when this is a leaf node. + */ isLeaf: boolean; + /** + * True when this is an atom, i.e. when it does not have directly + * editable content. This is usually the same as `isLeaf`, but can + * be configured with the [`atom` property](#model.NodeSpec.atom) on + * a node's spec (typically used when the node is displayed as an + * uneditable [node view](#view.NodeView)). + */ isAtom: boolean; + /** + * Return a string representation of this node for debugging + * purposes. + */ toString(): string; + /** + * Get the content match in this node at the given index. + */ contentMatchAt(index: number): ContentMatch; + /** + * Test whether replacing the range between `from` and `to` (by + * child index) with the given replacement fragment (which defaults + * to the empty fragment) would leave the node's content valid. You + * can optionally pass `start` and `end` indices into the + * replacement fragment. + */ canReplace(from: number, to: number, replacement?: Fragment, start?: number, end?: number): boolean; - canReplaceWith(from: number, to: number, type: NodeType, attrs?: Mark[]): boolean; - canAppend(other: Node): boolean; + /** + * Test whether replacing the range `from` to `to` (by index) with a + * node of the given type. + */ + canReplaceWith(from: number, to: number, type: NodeType, marks?: Mark[]): boolean; + /** + * Test whether the given node's content could be appended to this + * node. If that node is empty, this will only return true if there + * is at least one node type that can appear in both nodes (to avoid + * merging completely incompatible nodes). + */ + canAppend(other: ProsemirrorNode): boolean; + /** + * Check whether this node and its descendants conform to the + * schema, and raise error when they do not. + */ check(): void; - toJSON(): AnyObject; - static fromJSON(schema: Schema, json: AnyObject): Node; + /** + * Return a JSON-serializeable representation of this node. + */ + toJSON(): { [key: string]: any }; + /** + * Deserialize a node from its JSON representation. + */ + static fromJSON(schema: Schema, json: { [key: string]: any }): ProsemirrorNode; } +export { ProsemirrorNode as Node }; +/** + * Error type raised by [`Node.replace`](#model.Node.replace) when + * given an invalid replacement. + */ export class ReplaceError extends Error { } +/** + * A slice represents a piece cut out of a larger document. It + * stores not only a fragment, but also the depth up to which nodes on + * both side are ‘open’ (cut through). + */ export class Slice { - constructor(content: Fragment, openStart: number, openEnd: number) + /** + * Create a slice. When specifying a non-zero open depth, you must + * make sure that there are nodes of at least that depth at the + * appropriate side of the fragment—i.e. if the fragment is an empty + * paragraph node, `openStart` and `openEnd` can't be greater than + * 1. + * + * It is not necessary for the content of open nodes to conform to + * the schema's content constraints, though it should be a valid + * start/end/middle for such a node, depending on which sides are + * open. + */ + constructor(content: Fragment, openStart: number, openEnd: number); + /** + * The slice's content. + */ content: Fragment; + /** + * The open depth at the start. + */ openStart: number; + /** + * The open depth at the end. + */ openEnd: number; + /** + * The size this slice would add when inserted into a document. + */ size: number; + /** + * Tests whether this slice is equal to another slice. + */ eq(other: Slice): boolean; - toJSON(): AnyObject | null | undefined; - static fromJSON(schema: Schema, json?: AnyObject): Slice; + /** + * Convert a slice to a JSON-serializable representation. + */ + toJSON(): { [key: string]: any } | null | void; + /** + * Deserialize a slice from its JSON representation. + */ + static fromJSON(schema: Schema, json?: { [key: string]: any }): Slice; + /** + * Create a slice from a fragment by taking the maximum possible + * open value on both side of the fragment. + */ static maxOpen(fragment: Fragment): Slice; + /** + * The empty slice. + */ static empty: Slice; } +/** + * You can [_resolve_](#model.Node.resolve) a position to get more + * information about it. Objects of this class represent such a + * resolved position, providing various pieces of context information, + * and some helper methods. + * + * Throughout this interface, methods that take an optional `depth` + * parameter will interpret undefined as `this.depth` and negative + * numbers as `this.depth + value`. + */ export class ResolvedPos { + /** + * The position that was resolved. + */ pos: number; + /** + * The number of levels the parent node is from the root. If this + * position points directly into the root node, it is 0. If it + * points into a top-level paragraph, 1, and so on. + */ depth: number; + /** + * The offset this position has into its parent node. + */ parentOffset: number; - parent: Node; - doc: Node; - node(depth?: number): Node; + /** + * The parent node that the position points into. Note that even if + * a position points into a text node, that node is not considered + * the parent—text nodes are ‘flat’ in this model, and have no content. + */ + parent: ProsemirrorNode; + /** + * The root node in which the position was resolved. + */ + doc: ProsemirrorNode; + /** + * The ancestor node at the given level. `p.node(p.depth)` is the + * same as `p.parent`. + */ + node(depth?: number): ProsemirrorNode; + /** + * The index into the ancestor at the given level. If this points at + * the 3rd node in the 2nd paragraph on the top level, for example, + * `p.index(0)` is 2 and `p.index(1)` is 3. + */ index(depth?: number): number; + /** + * The index pointing after this position into the ancestor at the + * given level. + */ indexAfter(depth?: number): number; + /** + * The (absolute) position at the start of the node at the given + * level. + */ start(depth?: number): number; + /** + * The (absolute) position at the end of the node at the given + * level. + */ end(depth?: number): number; + /** + * The (absolute) position directly before the wrapping node at the + * given level, or, when `level` is `this.depth + 1`, the original + * position. + */ before(depth?: number): number; + /** + * The (absolute) position directly after the wrapping node at the + * given level, or the original position when `level` is `this.depth + 1`. + */ after(depth?: number): number; + /** + * When this position points into a text node, this returns the + * distance between the position and the start of the text node. + * Will be zero for positions that point between nodes. + */ textOffset: number; - nodeAfter?: Node | null; - nodeBefore?: Node | null; + /** + * Get the node directly after the position, if any. If the position + * points into a text node, only the part of that node after the + * position is returned. + */ + nodeAfter?: ProsemirrorNode | null; + /** + * Get the node directly before the position, if any. If the + * position points into a text node, only the part of that node + * before the position is returned. + */ + nodeBefore?: ProsemirrorNode | null; + /** + * Get the marks at this position, factoring in the surrounding + * marks' [`inclusive`](#model.MarkSpec.inclusive) property. If the + * position is at the start of a non-empty node, the marks of the + * node after it (if any) are returned. + */ marks(): Mark[]; - marksAcross(): Mark[] | null; + /** + * Get the marks after the current position, if any, except those + * that are non-inclusive and not present at position `$end`. This + * is mostly useful for getting the set of marks to preserve after a + * deletion. Will return `null` if this position is at the end of + * its parent node or its parent node isn't a textblock (in which + * case no marks should be preserved). + */ + marksAcross(): Mark[] | null | void; + /** + * The depth up to which this position and the given (non-resolved) + * position share the same parent nodes. + */ sharedDepth(pos: number): number; - blockRange(other?: ResolvedPos, pred?: (p: Node) => boolean): NodeRange | null | undefined; + /** + * Returns a range based on the place where this position and the + * given position diverge around block content. If both point into + * the same textblock, for example, a range around that textblock + * will be returned. If they point into different blocks, the range + * around those blocks in their shared ancestor is returned. You can + * pass in an optional predicate that will be called with a parent + * node to see if a range into that parent is acceptable. + */ + blockRange(other?: ResolvedPos, pred?: (p: ProsemirrorNode) => boolean): NodeRange | null | void; + /** + * Query whether the given position shares the same parent node. + */ sameParent(other: ResolvedPos): boolean; + /** + * Return the greater of this and the given position. + */ max(other: ResolvedPos): ResolvedPos; + /** + * Return the smaller of this and the given position. + */ min(other: ResolvedPos): ResolvedPos; } +/** + * Represents a flat range of content, i.e. one that starts and + * ends in the same node. + */ export class NodeRange { + /** + * Construct a node range. `$from` and `$to` should point into the + * same node until at least the given `depth`, since a node range + * denotes an adjacent set of nodes in a single parent node. + */ constructor($from: ResolvedPos, $to: ResolvedPos, depth: number); + /** + * A resolved position along the start of the + * content. May have a `depth` greater than this object's `depth` + * property, since these are the positions that were used to + * compute the range, not re-resolved positions directly at its + * boundaries. + */ $from: ResolvedPos; + /** + * A position along the end of the content. See + * caveat for [`$from`](#model.NodeRange.$from). + */ $to: ResolvedPos; + /** + * The depth of the node that this range points into. + */ depth: number; + /** + * The position at the start of the range. + */ start: number; + /** + * The position at the end of the range. + */ end: number; - parent: Node; + /** + * The parent node that the range points into. + */ + parent: ProsemirrorNode; + /** + * The start index of the range in the parent node. + */ startIndex: number; + /** + * The end index of the range in the parent node. + */ endIndex: number; } +/** + * Node types are objects allocated once per `Schema` and used to + * [tag](#model.Node.type) `Node` instances. They contain information + * about the node type, such as its name and what kind of node it + * represents. + */ export class NodeType { + /** + * The name the node type has in this schema. + */ name: string; + /** + * A link back to the `Schema` the node type belongs to. + */ schema: Schema; + /** + * The spec that this type is based on + */ spec: NodeSpec; + /** + * The starting match of the node type's content expression. + */ contentMatch: ContentMatch; - isBlock: boolean; - isText: boolean; - isInline: boolean; - isTextblock: boolean; + /** + * True if this node type has inline content. + */ inlineContent: boolean; + /** + * True if this is a block type + */ + isBlock: boolean; + /** + * True if this is the text node type. + */ + isText: boolean; + /** + * True if this is an inline type. + */ + isInline: boolean; + /** + * True if this is a textblock type, a block that contains inline + * content. + */ + isTextblock: boolean; + /** + * True for node types that allow no content. + */ isLeaf: boolean; + /** + * True when this node is an atom, i.e. when it does not have + * directly editable content. + */ isAtom: boolean; - create(attrs?: AnyObject, content?: Fragment | Node | Node[], marks?: Mark[]): Node; - createChecked(attrs?: AnyObject, content?: Fragment | Node | Node[], marks?: Mark[]): Node; - createAndFill(attrs?: AnyObject, content?: Fragment | Node | Node[], marks?: Mark[]): Node | null | undefined; - validContent(content: Fragment, attrs?: AnyObject): boolean; + /** + * Create a `Node` of this type. The given attributes are + * checked and defaulted (you can pass `null` to use the type's + * defaults entirely, if no required attributes exist). `content` + * may be a `Fragment`, a node, an array of nodes, or + * `null`. Similarly `marks` may be `null` to default to the empty + * set of marks. + */ + create(attrs?: { [key: string]: any }, content?: Fragment | ProsemirrorNode | ProsemirrorNode[], marks?: Mark[]): ProsemirrorNode; + /** + * Like [`create`](#model.NodeType.create), but check the given content + * against the node type's content restrictions, and throw an error + * if it doesn't match. + */ + createChecked(attrs?: { [key: string]: any }, content?: Fragment | ProsemirrorNode | ProsemirrorNode[], marks?: Mark[]): ProsemirrorNode; + /** + * Like [`create`](#model.NodeType.create), but see if it is necessary to + * add nodes to the start or end of the given fragment to make it + * fit the node. If no fitting wrapping can be found, return null. + * Note that, due to the fact that required nodes can always be + * created, this will always succeed if you pass null or + * `Fragment.empty` as content. + */ + createAndFill(attrs?: { [key: string]: any }, content?: Fragment | ProsemirrorNode | ProsemirrorNode[], marks?: Mark[]): ProsemirrorNode | null | void; + /** + * Returns true if the given fragment is valid content for this node + * type with the given attributes. + */ + validContent(content: Fragment): boolean; + /** + * Check whether the given mark type is allowed in this node. + */ allowsMarkType(markType: MarkType): boolean; + /** + * Test whether the given set of marks are allowed in this node. + */ allowsMarks(marks: Mark[]): boolean; + /** + * Removes the marks that are not allowed in this node from the given set. + */ allowedMarks(marks: Mark[]): Mark[]; } +/** + * Like nodes, marks (which are associated with nodes to signify + * things like emphasis or being part of a link) are + * [tagged](#model.Mark.type) with type objects, which are + * instantiated once per `Schema`. + */ export class MarkType { + /** + * The name of the mark type. + */ name: string; + /** + * The schema that this mark type instance is part of. + */ schema: Schema; + /** + * The spec on which the type is based. + */ spec: MarkSpec; - create(attrs?: AnyObject): Mark; + /** + * Create a mark of this type. `attrs` may be `null` or an object + * containing only some of the mark's attributes. The others, if + * they have defaults, will be added. + */ + create(attrs?: { [key: string]: any }): Mark; + /** + * When there is a mark of this type in the given set, a new set + * without it is returned. Otherwise, the input set is returned. + */ removeFromSet(set: Mark[]): Mark[]; - isInSet(set: Mark[]): Mark | null | undefined; + /** + * Tests whether there is a mark of this type in the given set. + */ + isInSet(set: Mark[]): Mark | null | void; + /** + * Queries whether a given mark type is + * [excluded](#model.MarkSpec.excludes) by this one. + */ excludes(other: MarkType): boolean; } +/** + * An object describing a schema, as passed to the [`Schema`](#model.Schema) + * constructor. + */ export interface SchemaSpec { + /** + * The node types in this schema. Maps names to + * [`NodeSpec`](#model.NodeSpec) objects that describe the node type + * associated with that name. Their order is significant—it + * determines which [parse rules](#model.NodeSpec.parseDOM) take + * precedence by default, and which nodes come first in a given + * [group](#model.NodeSpec.group). + */ nodes: { [name: string]: NodeSpec } | OrderedMap; + /** + * The mark types that exist in this schema. The order in which they + * are provided determines the order in which [mark + * sets](#model.Mark.addToSet) are sorted and in which [parse + * rules](#model.MarkSpec.parseDOM) are tried. + */ marks?: { [name: string]: MarkSpec } | OrderedMap | null; + /** + * The name of the default top-level node for the schema. Defaults + * to `"doc"`. + */ topNode?: string | null; } export interface NodeSpec { + /** + * 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. + */ content?: string | null; + /** + * 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. + */ marks?: string | null; + /** + * The group or space-separated groups to which this node belongs, + * which can be referred to in the content expressions for the + * schema. + */ group?: string | null; + /** + * Should be set to true for inline nodes. (Implied for text nodes.) + */ inline?: boolean | null; + /** + * Can be set to true to indicate that, though this isn't a [leaf + * node](#model.NodeType.isLeaf), it doesn't have directly editable + * content and should be treated as a single unit in the view. + */ atom?: boolean | null; + /** + * The attributes that nodes of this type get. + */ attrs?: { [name: string]: AttributeSpec } | null; + /** + * Controls whether nodes of this type can be selected as a [node + * selection](#state.NodeSelection). Defaults to true for non-text + * nodes. + */ selectable?: boolean | null; + /** + * Determines whether nodes of this type can be dragged without + * being selected. Defaults to false. + */ draggable?: boolean | null; + /** + * Can be used to indicate that this node contains code, which + * causes some commands to behave differently. + */ code?: boolean | null; + /** + * Determines whether this node is considered an important parent + * node during replace operations (such as paste). Non-defining (the + * default) nodes get dropped when their entire content is replaced, + * whereas defining nodes persist and wrap the inserted content. + * Likewise, in _inserted_ content the defining parents of the + * content are preserved when possible. Typically, + * non-default-paragraph textblock types, and possibly list items, + * are marked as defining. + */ defining?: boolean | null; + /** + * 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?: boolean | null; - toDOM?: ((node: Node) => DOMOutputSpec) | null; + /** + * Defines the default way a node of this type should be serialized + * to DOM/HTML (as used by + * [`DOMSerializer.fromSchema`](#model.DOMSerializer^fromSchema)). + * Should return a DOM node or an [array + * structure](#model.DOMOutputSpec) that describes one, with an + * optional number zero (“hole”) in it to indicate where the node's + * content should be inserted. + * + * For text nodes, the default is to create a text DOM node. Though + * it is possible to create a serializer where text is rendered + * differently, this is not supported inside the editor, so you + * shouldn't override that in your text node spec. + */ + toDOM?: ((node: ProsemirrorNode) => DOMOutputSpec) | null; + /** + * Associates DOM parser information with this node, which can be + * used by [`DOMParser.fromSchema`](#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. + */ parseDOM?: ParseRule[] | null; } export interface MarkSpec { + /** + * The attributes that marks of this type get. + */ attrs?: { [name: string]: AttributeSpec } | null; + /** + * Whether this mark should be active when the cursor is positioned + * at its end (or at its start when that is also the start of the + * parent node). Defaults to true. + */ inclusive?: boolean | null; + /** + * Determines which other marks this mark can coexist with. Should + * be a space-separated strings naming other marks or groups of marks. + * When a mark is [added](#model.Mark.addToSet) to a set, all marks + * that it excludes are removed in the process. If the set contains + * any mark that excludes the new mark but is not, itself, excluded + * by the new mark, the mark can not be added an the set. You can + * use the value `"_"` to indicate that the mark excludes all + * marks in the schema. + * + * Defaults to only being exclusive with marks of the same type. You + * can set it to an empty string (or any string not containing the + * mark's own name) to allow multiple marks of a given type to + * coexist (as long as they have different attributes). + */ excludes?: string | null; + /** + * The group or space-separated groups to which this mark belongs. + */ group?: string | null; + /** + * Defines the default way marks of this type should be serialized + * to DOM/HTML. + */ toDOM?: ((mark: Mark, inline: boolean) => DOMOutputSpec) | null; + /** + * Associates DOM parser information with this mark (see the + * corresponding [node spec field](#model.NodeSpec.parseDOM)). The + * `mark` field in the rules is implied. + */ parseDOM?: ParseRule[] | null; } +/** + * Used to [define](#model.NodeSpec.attrs) attributes on nodes or + * marks. + */ export interface AttributeSpec { - default?: any | null; + /** + * The default value for this attribute, to use when no explicit + * value is provided. Attributes that have no default must be + * provided whenever a node or mark of a type that has them is + * created. + */ + default?: any; } +/** + * A document schema. Holds [node](#model.NodeType) and [mark + * type](#model.MarkType) objects for the nodes and marks that may + * occur in conforming documents, and provides functionality for + * creating and deserializing such documents. + */ export class Schema { - constructor(spec: SchemaSpec) + /** + * Construct a schema from a schema [specification](#model.SchemaSpec). + */ + constructor(spec: SchemaSpec); + /** + * The [spec](#model.SchemaSpec) on which the schema is based, + * with the added guarantee that its `nodes` and `marks` + * properties are + * [`OrderedMap`](https://github.com/marijnh/orderedmap) instances + * (not raw objects). + */ spec: SchemaSpec; + /** + * An object mapping the schema's node names to node type objects. + */ nodes: { [name: string]: NodeType }; + /** + * A map from mark names to mark type objects. + */ marks: { [name: string]: MarkType }; - cached: AnyObject; + /** + * The type of the [default top node](#model.SchemaSpec.topNode) + * for this schema. + */ topNodeType: NodeType; - node(type: string | NodeType, attrs?: AnyObject, content?: Fragment | Node | Node[], marks?: Mark[]): Node; - text(text: string, marks?: Mark[]): Node; - mark(type: string | MarkType, attrs?: AnyObject): Mark; - nodeFromJSON(json: AnyObject): Node; - markFromJSON(json: AnyObject): Mark; + /** + * An object for storing whatever values modules may want to + * compute and cache per schema. (If you want to store something + * in it, try to use property names unlikely to clash.) + */ + cached: { [key: string]: any }; + /** + * Create a node in this schema. The `type` may be a string or a + * `NodeType` instance. Attributes will be extended + * with defaults, `content` may be a `Fragment`, + * `null`, a `Node`, or an array of nodes. + */ + node(type: string | NodeType, attrs?: { [key: string]: any }, content?: Fragment | ProsemirrorNode | ProsemirrorNode[], marks?: Mark[]): ProsemirrorNode; + /** + * Create a text node in the schema. Empty text nodes are not + * allowed. + */ + text(text: string, marks?: Mark[]): ProsemirrorNode; + /** + * Create a mark with the given type and attributes. + */ + mark(type: string | MarkType, attrs?: { [key: string]: any }): Mark; + /** + * Deserialize a node from its JSON representation. This method is + * bound. + */ + nodeFromJSON(json: { [key: string]: any }): ProsemirrorNode; + /** + * Deserialize a mark from its JSON representation. This method is + * bound. + */ + markFromJSON(json: { [key: string]: any }): Mark; } export interface DOMOutputSpecArray { 0: string; @@ -268,15 +1299,56 @@ export interface DOMOutputSpecArray { 9?: DOMOutputSpec | 0; } export type DOMOutputSpec - = string - | dom.Node - | DOMOutputSpecArray; + = string + | Node + | DOMOutputSpecArray; +/** + * A DOM serializer knows how to convert ProseMirror nodes and + * marks of various types to DOM nodes. + */ export class DOMSerializer { - constructor(nodes: { [name: string]: (node: Node) => DOMOutputSpec }, marks: { [name: string]: (mark: Mark, inline: boolean) => DOMOutputSpec }) - nodes: { [name: string]: (node: Node) => DOMOutputSpec }; - marks: { [name: string]: (mark: Mark) => DOMOutputSpec }; - serializeFragment(fragment: Fragment, options?: AnyObject): DocumentFragment; - serializeNode(node: Node, options?: AnyObject): Node; + /** + * Create a serializer. `nodes` should map node names to functions + * that take a node and return a description of the corresponding + * DOM. `marks` does the same for mark names, but also gets an + * argument that tells it whether the mark's content is block or + * inline content (for typical use, it'll always be inline). A mark + * serializer may be `null` to indicate that marks of that type + * should not be serialized. + */ + constructor(nodes: { [name: string]: (node: ProsemirrorNode) => DOMOutputSpec }, marks: { [name: string]: (mark: Mark, inline: boolean) => DOMOutputSpec }); + /** + * The node serialization functions. + */ + nodes: { [name: string]: (node: ProsemirrorNode) => DOMOutputSpec }; + /** + * The mark serialization functions. + */ + marks: { [name: string]: (mark: Mark, inline: boolean) => DOMOutputSpec }; + /** + * Serialize the content of this fragment to a DOM fragment. When + * not in the browser, the `document` option, containing a DOM + * document, should be passed so that the serializer can create + * nodes. + */ + serializeFragment(fragment: Fragment, options?: { [key: string]: any }): DocumentFragment; + /** + * Serialize this node to a DOM node. This can be useful when you + * need to serialize a part of a document, as opposed to the whole + * document. To serialize a whole document, use + * [`serializeFragment`](#model.DOMSerializer.serializeFragment) on + * its [content](#model.Node.content). + */ + serializeNode(node: ProsemirrorNode, options?: { [key: string]: any }): Node; + /** + * Render an [output spec](#model.DOMOutputSpec) to a DOM node. If + * the spec has a hole (zero) in it, `contentDOM` will point at the + * node with the hole. + */ static renderSpec(doc: Document, structure: DOMOutputSpec): { dom: Node, contentDOM?: Node | null }; + /** + * Build a serializer using the [`toDOM`](#model.NodeSpec.toDOM) + * properties in a schema's node and mark specs. + */ static fromSchema(schema: Schema): DOMSerializer; } diff --git a/types/prosemirror-model/tslint.json b/types/prosemirror-model/tslint.json index b1439230db..ef60a6f2cc 100644 --- a/types/prosemirror-model/tslint.json +++ b/types/prosemirror-model/tslint.json @@ -1,7 +1,7 @@ { "extends": "dtslint/dt.json", "rules": { - // TODO - "no-any-union": false + // Node is declared as `ProsemirrorNode` to avoid name-clash with `Node` from the DOM + "strict-export-declare-modifiers": false } } diff --git a/types/prosemirror-schema-basic/index.d.ts b/types/prosemirror-schema-basic/index.d.ts index e5db9ffb80..0e7a6f7846 100644 --- a/types/prosemirror-schema-basic/index.d.ts +++ b/types/prosemirror-schema-basic/index.d.ts @@ -1,27 +1,42 @@ -// Type definitions for prosemirror-schema-basic 0.21 +// Type definitions for prosemirror-schema-basic 1.0 // Project: https://github.com/ProseMirror/prosemirror-schema-basic // Definitions by: Bradley Ayers // David Hahn +// Tim Baumann // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.1 +// IMPORTANT +// This file was generated by https://github.com/bradleyayers/getdocs2ts. Please do not edit manually. +// When you find an error in these declarations, fix the getdocs comment upstream or 'getdocs2ts', then regenerate. + import { MarkSpec, NodeSpec, Schema } from 'prosemirror-model'; +/** + * [Specs](#model.NodeSpec) for the nodes defined in this schema. + */ export let nodes: { - doc: NodeSpec, - paragraph: NodeSpec, - blockquote: NodeSpec, - horizontal_rule: NodeSpec, - heading: NodeSpec, - code_block: NodeSpec, - text: NodeSpec, - image: NodeSpec, - hard_break: NodeSpec -}; -export let marks: { - link: MarkSpec, - em: MarkSpec, - strong: MarkSpec, - code: MarkSpec + doc: NodeSpec, + paragraph: NodeSpec, + blockquote: NodeSpec, + horizontal_rule: NodeSpec, + heading: NodeSpec, + code_block: NodeSpec, + text: NodeSpec, + image: NodeSpec, + hard_break: NodeSpec }; +/** + * [Specs](#model.MarkSpec) for the marks in the schema. + */ +export let marks: { link: MarkSpec, em: MarkSpec, strong: MarkSpec, code: MarkSpec }; +/** + * This schema rougly corresponds to the document schema used by + * [CommonMark](http://commonmark.org/), minus the list elements, + * which are defined in the [`prosemirror-schema-list`](#schema-list) + * module. + * + * To reuse elements from this schema, extend or read from its + * `spec.nodes` and `spec.marks` [properties](#model.Schema.spec). + */ export let schema: Schema; diff --git a/types/prosemirror-schema-list/index.d.ts b/types/prosemirror-schema-list/index.d.ts index 2378dc8b3c..01053b06cd 100644 --- a/types/prosemirror-schema-list/index.d.ts +++ b/types/prosemirror-schema-list/index.d.ts @@ -1,19 +1,68 @@ -// Type definitions for prosemirror-schema-list 0.21 +// Type definitions for prosemirror-schema-list 1.0 // Project: https://github.com/ProseMirror/prosemirror-schema-list // Definitions by: Bradley Ayers // David Hahn +// Tim Baumann // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.1 +// IMPORTANT +// This file was generated by https://github.com/bradleyayers/getdocs2ts. Please do not edit manually. +// When you find an error in these declarations, fix the getdocs comment upstream or 'getdocs2ts', then regenerate. + import OrderedMap = require('orderedmap'); import { NodeSpec, NodeType } from 'prosemirror-model'; import { EditorState, Transaction } from 'prosemirror-state'; +/** + * An ordered list [node spec](#model.NodeSpec). Has a single + * attribute, `order`, which determines the number at which the list + * starts counting, and defaults to 1. Represented as an `
    ` + * element. + */ export let orderedList: NodeSpec; +/** + * A bullet list node spec, represented in the DOM as `
      `. + */ export let bulletList: NodeSpec; +/** + * A list item (`
    • `) spec. + */ export let listItem: NodeSpec; -export function addListNodes(nodes: OrderedMap, itemContent: string, listGroup?: string): OrderedMap; +/** + * Convenience function for adding list-related node types to a map + * specifying the nodes for a schema. Adds + * [`orderedList`](#schema-list.orderedList) as `"ordered_list"`, + * [`bulletList`](#schema-list.bulletList) as `"bullet_list"`, and + * [`listItem`](#schema-list.listItem) as `"list_item"`. + * + * `itemContent` determines the content expression for the list items. + * If you want the commands defined in this module to apply to your + * list structure, it should have a shape like `"paragraph block*"` or + * `"paragraph (ordered_list | bullet_list)*"`. `listGroup` can be + * given to assign a group name to the list node types, for example + * `"block"`. + */ +export function addListNodes(nodes: OrderedMap, itemContent: string, listGroup?: string): OrderedMap; +/** + * Returns a command function that wraps the selection in a list with + * the given type an attributes. If `dispatch` is null, only return a + * value to indicate whether this is possible, but don't actually + * perform the change. + */ export function wrapInList(listType: NodeType, attrs?: { [key: string]: any }): (state: EditorState, dispatch?: (tr: Transaction) => void) => boolean; +/** + * Build a command that splits a non-empty textblock at the top level + * of a list item by also splitting that list item. + */ export function splitListItem(itemType: NodeType): (state: EditorState, dispatch?: (tr: Transaction) => void) => boolean; +/** + * Create a command to lift the list item around the selection up into + * a wrapping list. + */ export function liftListItem(itemType: NodeType): (state: EditorState, dispatch?: (tr: Transaction) => void) => boolean; +/** + * Create a command to sink the list item around the selection down + * into an inner list. + */ export function sinkListItem(itemType: NodeType): (state: EditorState, dispatch?: (tr: Transaction) => void) => boolean; diff --git a/types/prosemirror-state/index.d.ts b/types/prosemirror-state/index.d.ts index 93e6582c71..781a1459e9 100644 --- a/types/prosemirror-state/index.d.ts +++ b/types/prosemirror-state/index.d.ts @@ -1,162 +1,562 @@ -// Type definitions for prosemirror-state 0.24 +// Type definitions for prosemirror-state 1.0 // Project: https://github.com/ProseMirror/prosemirror-state // Definitions by: Bradley Ayers // David Hahn +// Tim Baumann // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.3 +// TypeScript Version: 2.1 -import { Mark, MarkType, Node, ResolvedPos, Schema, Slice } from 'prosemirror-model'; +// IMPORTANT +// This file was generated by https://github.com/bradleyayers/getdocs2ts. Please do not edit manually. +// When you find an error in these declarations, fix the getdocs comment upstream or 'getdocs2ts', then regenerate. + +import { Mark, MarkType, Node as ProsemirrorNode, ResolvedPos, Schema, Slice } from 'prosemirror-model'; import { Mappable, Mapping, Transform } from 'prosemirror-transform'; import { EditorProps, EditorView } from 'prosemirror-view'; -export interface AnyObject { - [key: string]: any; -} - -export interface PluginSpecProps { - // State is not part of this type. - // state: EditorProps["state"]; - // dispatchTransaction?: EditorProps["dispatchTransaction"]; - handleDOMEvents?: EditorProps["handleDOMEvents"]; - handleKeyDown?: EditorProps["handleKeyDown"]; - handleKeyPress?: EditorProps["handleKeyPress"]; - handleTextInput?: EditorProps["handleTextInput"]; - handleClickOn?: EditorProps["handleClickOn"]; - handleClick?: EditorProps["handleClick"]; - handleDoubleClickOn?: EditorProps["handleDoubleClickOn"]; - handleDoubleClick?: EditorProps["handleDoubleClick"]; - handleTripleClickOn?: EditorProps["handleTripleClickOn"]; - handleTripleClick?: EditorProps["handleTripleClick"]; - handlePaste?: EditorProps["handlePaste"]; - handleDrop?: EditorProps["handleDrop"]; - createSelectionBetween?: EditorProps["createSelectionBetween"]; - domParser?: EditorProps["domParser"]; - clipboardParser?: EditorProps["clipboardParser"]; - transformPasted?: EditorProps["transformPasted"]; - transformPastedHTML?: EditorProps["transformPastedHTML"]; - transformPastedText?: EditorProps["transformPastedText"]; - nodeViews?: EditorProps["nodeViews"]; - clipboardSerializer?: EditorProps["clipboardSerializer"]; - decorations?: EditorProps["decorations"]; - editable?: EditorProps["editable"]; - attributes?: EditorProps["attributes"]; - scrollThreshold?: EditorProps["scrollThreshold"]; - scrollMargin?: EditorProps["scrollMargin"]; -} - -export interface PluginSpec { - props?: PluginSpecProps | null; - state?: StateField | null; +/** + * This is the type passed to the [`Plugin`](#state.Plugin) + * constructor. It provides a definition for a plugin. + */ +export interface PluginSpec { + /** + * The [view props](#view.EditorProps) added by this plugin. Props + * that are functions will be bound to have the plugin instance as + * their `this` binding. + */ + props?: EditorProps | null; + /** + * Allows a plugin to define a [state field](#state.StateField), an + * extra slot in the state object in which it can keep its own data. + */ + state?: StateField | null; + /** + * Can be used to make this a keyed plugin. You can have only one + * plugin with a given key in a given state, but it is possible to + * access the plugin's configuration and state through the key, + * without having access to the plugin instance object. + */ key?: PluginKey | null; - view?: ((p: EditorView) => { - update?: ((view: EditorView, prevState: EditorState) => void) | null, - destroy?: (() => void) | null - }) | null; + /** + * When the plugin needs to interact with the editor view, or + * set something up in the DOM, use this field. The function + * will be called when the plugin's state is associated with an + * editor view. + */ + view?: ((p: EditorView) => { update?: ((view: EditorView, prevState: EditorState) => void) | null, destroy?: (() => void) | null }) | null; + /** + * When present, this will be called before a transaction is + * applied by the state, allowing the plugin to cancel it (by + * returning false). + */ filterTransaction?: ((p1: Transaction, p2: EditorState) => boolean) | null; - appendTransaction?: ((transactions: Transaction[], oldState: EditorState, newState: EditorState) => Transaction | null | undefined) | null; + /** + * Allows the plugin to append another transaction to be applied + * after the given array of transactions. When another plugin + * appends a transaction after this was called, it is called again + * with the new state and new transactions—but only the new + * transactions, i.e. it won't be passed transactions that it + * already saw. + */ + appendTransaction?: ((transactions: Transaction[], oldState: EditorState, newState: EditorState) => Transaction | null | void) | null; } - -export class Plugin { - constructor(spec: PluginSpec) - props: PluginSpecProps; - spec: AnyObject; - getState(state: EditorState): T | undefined; +/** + * Plugins bundle functionality that can be added to an editor. + * They are part of the [editor state](#state.EditorState) and + * may influence that state and the view that contains it. + */ +export class Plugin { + /** + * Create a plugin. + */ + constructor(spec: PluginSpec); + /** + * The [props](#view.EditorProps) exported by this plugin. + */ + props: EditorProps; + /** + * The plugin's [spec object](#state.PluginSpec). + */ + spec: { [key: string]: any }; + /** + * Extract the plugin's state field from an editor state. + */ + getState(state: EditorState): any; } - +/** + * A plugin spec may provide a state field (under its + * [`state`](#state.PluginSpec.state) property) of this type, which + * describes the state it wants to keep. Functions provided here are + * always called with the plugin instance as their `this` binding. + */ export interface StateField { - init(config: AnyObject, instance: EditorState): T; + /** + * Initialize the value of the field. `config` will be the object + * passed to [`EditorState.create`](#state.EditorState^create). Note + * that `instance` is a half-initialized state instance, and will + * not have values for plugin fields initialized after this one. + */ + init(config: { [key: string]: any }, instance: EditorState): T; + /** + * Apply the given transaction to this state field, producing a new + * field value. Note that the `newState` argument is again a partially + * constructed state does not yet contain the state from plugins + * coming after this one. + */ apply(tr: Transaction, value: T, oldState: EditorState, newState: EditorState): T; + /** + * Convert this field to JSON. Optional, can be left off to disable + * JSON serialization for the field. + */ toJSON?: ((value: T) => any) | null; - fromJSON?: ((config: AnyObject, value: any, state: EditorState) => T) | null; + /** + * Deserialize the JSON representation of this field. Note that the + * `state` argument is again a half-initialized state. + */ + fromJSON?: ((config: { [key: string]: any }, value: any, state: EditorState) => T) | null; } +/** + * A key is used to [tag](#state.PluginSpec.key) + * plugins in a way that makes it possible to find them, given an + * editor state. Assigning a key does mean only one plugin of that + * type can be active in a state. + */ export class PluginKey { - constructor(name?: string) - get(state: EditorState): Plugin | null | undefined; - getState(state: EditorState): any | null | undefined; + /** + * Create a plugin key. + */ + constructor(name?: string); + /** + * Get the active plugin with this key, if any, from an editor + * state. + */ + get(state: EditorState): Plugin | null | void; + /** + * Get the plugin's state from an editor state. + */ + getState(state: EditorState): any | null | void; } +/** + * Superclass for editor selections. Every selection type should + * extend this. Should not be instantiated directly. + */ export class Selection { - constructor($anchor: ResolvedPos, $head: ResolvedPos, ranges?: SelectionRange[]) + /** + * Initialize a selection with the head and anchor and ranges. If no + * ranges are given, constructs a single range across `$anchor` and + * `$head`. + */ + constructor($anchor: ResolvedPos, $head: ResolvedPos, ranges?: SelectionRange[]); + /** + * The ranges covered by the selection. + */ ranges: SelectionRange[]; + /** + * The resolved anchor of the selection (the side that stays in + * place when the selection is modified). + */ $anchor: ResolvedPos; + /** + * The resolved head of the selection (the side that moves when + * the selection is modified). + */ $head: ResolvedPos; + /** + * The selection's anchor, as an unresolved position. + */ anchor: number; + /** + * The selection's head. + */ head: number; + /** + * The lower bound of the selection's main range. + */ from: number; + /** + * The upper bound of the selection's main range. + */ to: number; + /** + * The resolved lower bound of the selection's main range. + */ $from: ResolvedPos; + /** + * The resolved upper bound of the selection's main range. + */ $to: ResolvedPos; + /** + * Indicates whether the selection contains any content. + */ empty: boolean; + /** + * Test whether the selection is the same as another selection. + */ eq(p: Selection): boolean; - map(doc: Node, mapping: Mappable): Selection; + /** + * Map this selection through a [mappable](#transform.Mappable) thing. `doc` + * should be the new document to which we are mapping. + */ + map(doc: ProsemirrorNode, mapping: Mappable): Selection; + /** + * Get the content of this selection as a slice. + */ content(): Slice; + /** + * Replace the selection with a slice or, if no slice is given, + * delete the selection. Will append to the given transaction. + */ replace(tr: Transaction, content?: Slice): void; - replaceWith(tr: Transaction, node: Node): void; - toJSON(): AnyObject; + /** + * Replace the selection with the given node, appending the changes + * to the given transaction. + */ + replaceWith(tr: Transaction, node: ProsemirrorNode): void; + /** + * Convert the selection to a JSON representation. When implementing + * this for a custom selection class, make sure to give the object a + * `type` property whose value matches the ID under which you + * [registered](#state.Selection^jsonID) your class. + */ + toJSON(): { [key: string]: any }; + /** + * Get a [bookmark](#state.SelectionBookmark) for this selection, + * which is a value that can be mapped without having access to a + * current document, and later resolved to a real selection for a + * given document again. (This is used mostly by the history to + * track and restore old selections.) The default implementation of + * this method just converts the selection to a text selection and + * returns the bookmark for that. + */ getBookmark(): SelectionBookmark; + /** + * Controls whether, when a selection of this type is active in the + * browser, the selected range should be visible to the user. Defaults + * to `true`. + */ visible: boolean; - static findFrom($pos: ResolvedPos, dir: number, textOnly?: boolean): Selection | null | undefined; + /** + * Find a valid cursor or leaf node selection starting at the given + * position and searching back if `dir` is negative, and forward if + * positive. When `textOnly` is true, only consider cursor + * selections. Will return null when no valid selection position is + * found. + */ + static findFrom($pos: ResolvedPos, dir: number, textOnly?: boolean): Selection | null | void; + /** + * Find a valid cursor or leaf node selection near the given + * position. Searches forward first by default, but if `bias` is + * negative, it will search backwards first. + */ static near($pos: ResolvedPos, bias?: number): Selection; - static atStart(doc: Node): Selection; - static atEnd(doc: Node): Selection; - static fromJSON(doc: Node, json: AnyObject): Selection; + /** + * Find the cursor or leaf node selection closest to the start of + * the given document. Will return an + * [`AllSelection`](#state.AllSelection) if no valid position + * exists. + */ + static atStart(doc: ProsemirrorNode): Selection; + /** + * Find the cursor or leaf node selection closest to the end of the + * given document. + */ + static atEnd(doc: ProsemirrorNode): Selection; + /** + * Deserialize the JSON representation of a selection. Must be + * implemented for custom classes (as a static class method). + */ + static fromJSON(doc: ProsemirrorNode, json: { [key: string]: any }): Selection; + /** + * To be able to deserialize selections from JSON, custom selection + * classes must register themselves with an ID string, so that they + * can be disambiguated. Try to pick something that's unlikely to + * clash with classes from other modules. + */ static jsonID(id: string, selectionClass: { new(...args: any[]): Selection }): void; } +/** + * A lightweight, document-independent representation of a selection. + * You can define a custom bookmark type for a custom selection class + * to make the history handle it well. + */ export interface SelectionBookmark { + /** + * Map the bookmark through a set of changes. + */ map(mapping: Mapping): SelectionBookmark; - resolve(doc: Node): Selection; + /** + * Resolve the bookmark to a real selection again. This may need to + * do some error checking and may fall back to a default (usually + * [`TextSelection.between`](#state.TextSelection^between)) if + * mapping made the bookmark invalid. + */ + resolve(doc: ProsemirrorNode): Selection; } +/** + * Represents a selected range in a document. + */ export class SelectionRange { - constructor($from: ResolvedPos, $to: ResolvedPos) + constructor($from: ResolvedPos, $to: ResolvedPos); + /** + * The lower bound of the range. + */ $from: ResolvedPos; + /** + * The upper bound of the range. + */ $to: ResolvedPos; } +/** + * A text selection represents a classical editor selection, with + * a head (the moving side) and anchor (immobile side), both of which + * point into textblock nodes. It can be empty (a regular cursor + * position). + */ export class TextSelection extends Selection { - constructor($anchor: ResolvedPos, $head?: ResolvedPos) + /** + * Construct a text selection between the given points. + */ + constructor($anchor: ResolvedPos, $head?: ResolvedPos); + /** + * Returns a resolved position if this is a cursor selection (an + * empty text selection), and null otherwise. + */ $cursor?: ResolvedPos | null; - static create(doc: Node, anchor: number, head?: number): TextSelection; + /** + * Create a text selection from non-resolved positions. + */ + static create(doc: ProsemirrorNode, anchor: number, head?: number): TextSelection; + /** + * Return a text selection that spans the given positions or, if + * they aren't text positions, find a text selection near them. + * `bias` determines whether the method searches forward (default) + * or backwards (negative number) first. Will fall back to calling + * [`Selection.near`](#state.Selection^near) when the document + * doesn't contain a valid text position. + */ static between($anchor: ResolvedPos, $head: ResolvedPos, bias?: number): Selection; } +/** + * A node selection is a selection that points at a single node. + * All nodes marked [selectable](#model.NodeSpec.selectable) can be + * the target of a node selection. In such a selection, `from` and + * `to` point directly before and after the selected node, `anchor` + * equals `from`, and `head` equals `to`.. + */ export class NodeSelection extends Selection { - constructor($pos: ResolvedPos) - node: Node; - static create(doc: Node, from: number, p1?: number): NodeSelection; - static isSelectable(node: Node): boolean; + /** + * Create a node selection. Does not verify the validity of its + * argument. + */ + constructor($pos: ResolvedPos); + /** + * The selected node. + */ + node: ProsemirrorNode; + /** + * Create a node selection from non-resolved positions. + */ + static create(doc: ProsemirrorNode, from: number): NodeSelection; + /** + * Determines whether the given node may be selected as a node + * selection. + */ + static isSelectable(node: ProsemirrorNode): boolean; } +/** + * A selection type that represents selecting the whole document + * (which can not necessarily be expressed with a text selection, when + * there are for example leaf block nodes at the start or end of the + * document). + */ export class AllSelection extends Selection { - constructor(doc: Node) + /** + * Create an all-selection over the given document. + */ + constructor(doc: ProsemirrorNode); } +/** + * The state of a ProseMirror editor is represented by an object + * of this type. A state is a persistent data structure—it isn't + * updated, but rather a new state value is computed from an old one + * using the [`apply`](#state.EditorState.apply) method. + * + * A state holds a number of built-in fields, and plugins can + * [define](#state.PluginSpec.state) additional fields. + */ export class EditorState { - doc: Node; + /** + * The current document. + */ + doc: ProsemirrorNode; + /** + * The selection. + */ selection: Selection; + /** + * A set of marks to apply to the next input. Will be null when + * no explicit marks have been set. + */ storedMarks?: Mark[] | null; + /** + * The schema of the state's document. + */ schema: Schema; + /** + * The plugins that are active in this state. + */ plugins: Plugin[]; + /** + * Apply the given transaction to produce a new state. + */ apply(tr: Transaction): EditorState; + /** + * Verbose variant of [`apply`](#state.EditorState.apply) that + * returns the precise transactions that were applied (which might + * be influenced by the [transaction + * hooks](#state.PluginSpec.filterTransaction) of + * plugins) along with the new state. + */ applyTransaction(tr: Transaction): { state: EditorState, transactions: Transaction[] }; + /** + * Start a [transaction](#state.Transaction) from this state. + */ tr: Transaction; - reconfigure(config: AnyObject): EditorState; - toJSON(pluginFields?: { [name: string]: Plugin }): AnyObject; - static create(config: AnyObject): EditorState; - static fromJSON(config: AnyObject, json: AnyObject, pluginFields?: { [name: string]: Plugin }): EditorState; + /** + * Create a new state based on this one, but with an adjusted set of + * active plugins. State fields that exist in both sets of plugins + * are kept unchanged. Those that no longer exist are dropped, and + * those that are new are initialized using their + * [`init`](#state.StateField.init) method, passing in the new + * configuration object.. + */ + reconfigure(config: { schema?: Schema | null, plugins?: Plugin[] | null }): EditorState; + /** + * Serialize this state to JSON. If you want to serialize the state + * of plugins, pass an object mapping property names to use in the + * resulting JSON object to plugin objects. + */ + toJSON(pluginFields?: { [name: string]: Plugin }): { [key: string]: any }; + /** + * Create a new state. + */ + static create(config: { schema?: Schema | null, doc?: ProsemirrorNode | null, selection?: Selection | null, plugins?: Plugin[] | null }): EditorState; + /** + * Deserialize a JSON representation of a state. `config` should + * have at least a `schema` field, and should contain array of + * plugins to initialize the state with. `pluginFields` can be used + * to deserialize the state of plugins, by associating plugin + * instances with the property names they use in the JSON object. + */ + static fromJSON(config: { schema: Schema, plugins?: Plugin[] | null }, json: { [key: string]: any }, pluginFields?: { [name: string]: Plugin }): EditorState; } +/** + * An editor state transaction, which can be applied to a state to + * create an updated state. Use + * [`EditorState.tr`](#state.EditorState.tr) to create an instance. + * + * Transactions track changes to the document (they are a subclass of + * [`Transform`](#transform.Transform)), but also other state changes, + * like selection updates and adjustments of the set of [stored + * marks](#state.EditorState.storedMarks). In addition, you can store + * metadata properties in a transaction, which are extra pieces of + * information that client code or plugins can use to describe what a + * transacion represents, so that they can update their [own + * state](#state.StateField) accordingly. + * + * The [editor view](#view.EditorView) uses a few metadata properties: + * it will attach a property `"pointer"` with the value `true` to + * selection transactions directly caused by mouse or touch input, and + * a `"paste"` property of true to transactions caused by a paste.. + */ export class Transaction extends Transform { + /** + * The timestamp associated with this transaction, in the same + * format as `Date.now()`. + */ time: number; + /** + * The stored marks set by this transaction, if any. + */ storedMarks?: Mark[] | null; + /** + * The transaction's current selection. This defaults to the editor + * selection [mapped](#state.Selection.map) through the steps in the + * transaction, but can be overwritten with + * [`setSelection`](#state.Transaction.setSelection). + */ selection: Selection; + /** + * Update the transaction's current selection. Will determine the + * selection that the editor gets when the transaction is applied. + */ setSelection(selection: Selection): Transaction; + /** + * Whether the selection was explicitly updated by this transaction. + */ selectionSet: boolean; + /** + * Set the current stored marks. + */ setStoredMarks(marks?: Mark[]): Transaction; + /** + * Make sure the current stored marks or, if that is null, the marks + * at the selection, match the given set of marks. Does nothing if + * this is already the case. + */ ensureMarks(marks: Mark[]): Transaction; - storedMarksSet: boolean; - setTime(time: number): Transaction; - replaceSelection(slice: Slice): Transaction; - replaceSelectionWith(node: Node, inheritMarks?: boolean): Transaction; - deleteSelection(): Transaction; - insertText(text: string, from?: number, to?: number): Transaction; - setMeta(key: string | Plugin | PluginKey, value: any): Transaction; - getMeta(key: string | Plugin | PluginKey): any; - isGeneric: boolean; - scrollIntoView(): Transaction; + /** + * Add a mark to the set of stored marks. + */ addStoredMark(mark: Mark): Transaction; + /** + * Remove a mark or mark type from the set of stored marks. + */ removeStoredMark(mark: Mark | MarkType): Transaction; + /** + * Whether the stored marks were explicitly set for this transaction. + */ + storedMarksSet: boolean; + /** + * Update the timestamp for the transaction. + */ + setTime(time: number): Transaction; + /** + * Replace the current selection with the given slice. + */ + replaceSelection(slice: Slice): Transaction; + /** + * Replace the selection with the given node. When `inheritMarks` is + * true and the content is inline, it inherits the marks from the + * place where it is inserted. + */ + replaceSelectionWith(node: ProsemirrorNode, inheritMarks?: boolean): Transaction; + /** + * Delete the selection. + */ + deleteSelection(): Transaction; + /** + * Replace the given range, or the selection if no range is given, + * with a text node containing the given string. + */ + insertText(text: string, from?: number, to?: number): Transaction; + /** + * Store a metadata property in this transaction, keyed either by + * name or by plugin. + */ + setMeta(key: string | Plugin | PluginKey, value: any): Transaction; + /** + * Retrieve a metadata property for a given name or plugin. + */ + getMeta(key: string | Plugin | PluginKey): any; + /** + * Returns true if this transaction doesn't contain any metadata, + * and can thus safely be extended. + */ + isGeneric: boolean; + /** + * Indicate that the editor should scroll the selection into view + * when updated to the state produced by this transaction. + */ + scrollIntoView(): Transaction; } diff --git a/types/prosemirror-state/prosemirror-state-tests.ts b/types/prosemirror-state/prosemirror-state-tests.ts index 7b8ff3578a..0c1cddc24e 100644 --- a/types/prosemirror-state/prosemirror-state-tests.ts +++ b/types/prosemirror-state/prosemirror-state-tests.ts @@ -20,23 +20,23 @@ const nodeRange = {} as model.NodeRange; const step = {} as transform.Step; const nodeType = {} as model.NodeType; -let transaction: state.Transaction; +let transaction = {} as state.Transaction; -transaction = new state.Transaction(node).delete(0, 0); -transaction = new state.Transaction(node).addMark(0, 0, mark); -transaction = new state.Transaction(node).removeMark(0, 0); -transaction = new state.Transaction(node).clearIncompatible(0, nodeType); -transaction = new state.Transaction(node).replaceRange(0, 0, slice); -transaction = new state.Transaction(node).replaceRangeWith(0, 0, node); -transaction = new state.Transaction(node).deleteRange(0, 0); -transaction = new state.Transaction(node).delete(0, 0); -transaction = new state.Transaction(node).replace(0, 0); -transaction = new state.Transaction(node).replaceWith(0, 0, node); -transaction = new state.Transaction(node).insert(0, node); -transaction = new state.Transaction(node).lift(nodeRange, 0); -transaction = new state.Transaction(node).wrap(nodeRange, []); -transaction = new state.Transaction(node).setBlockType(0, 0, node.type); -transaction = new state.Transaction(node).setNodeMarkup(0); -transaction = new state.Transaction(node).split(0); -transaction = new state.Transaction(node).join(0); -transaction = new state.Transaction(node).step(step); +transaction = transaction.delete(0, 0); +transaction = transaction.addMark(0, 0, mark); +transaction = transaction.removeMark(0, 0); +transaction = transaction.clearIncompatible(0, nodeType); +transaction = transaction.replaceRange(0, 0, slice); +transaction = transaction.replaceRangeWith(0, 0, node); +transaction = transaction.deleteRange(0, 0); +transaction = transaction.delete(0, 0); +transaction = transaction.replace(0, 0); +transaction = transaction.replaceWith(0, 0, node); +transaction = transaction.insert(0, node); +transaction = transaction.lift(nodeRange, 0); +transaction = transaction.wrap(nodeRange, []); +transaction = transaction.setBlockType(0, 0, node.type); +transaction = transaction.setNodeMarkup(0); +transaction = transaction.split(0); +transaction = transaction.join(0); +transaction = transaction.step(step); diff --git a/types/prosemirror-tables/dom.d.ts b/types/prosemirror-tables/dom.d.ts deleted file mode 100644 index b4b02d1c24..0000000000 --- a/types/prosemirror-tables/dom.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -export type DOMDataTransfer = DataTransfer; -export type DOMDocument = Document; -export type DOMElement = HTMLElement; -export type DOMEvent = Event; -export type DOMFragment = DocumentFragment; -export type DOMKeyboardEvent = KeyboardEvent; -export type DOMMouseEvent = MouseEvent; -export type DOMMutationRecord = MutationRecord; -export type DOMNode = Node; - -export { - DOMDataTransfer as DataTransfer, - DOMDocument as Document, - DOMElement as Element, - DOMEvent as Event, - DOMFragment as DocumentFragment, - DOMKeyboardEvent as KeyboardEvent, - DOMMouseEvent as MouseEvent, - DOMMutationRecord as MutationRecord, - DOMNode as Node, -}; diff --git a/types/prosemirror-tables/index.d.ts b/types/prosemirror-tables/index.d.ts index fe24b41189..59f54b697b 100644 --- a/types/prosemirror-tables/index.d.ts +++ b/types/prosemirror-tables/index.d.ts @@ -5,8 +5,7 @@ // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped // TypeScript Version: 2.3 import { EditorState, Plugin, SelectionRange, Transaction } from 'prosemirror-state'; -import { Node, NodeSpec, Slice, ResolvedPos } from 'prosemirror-model'; -import * as dom from './dom'; +import { Node as ProsemirrorNode, NodeSpec, Slice, ResolvedPos } from 'prosemirror-model'; export interface TableNodesOptions { tableGroup?: string; @@ -14,7 +13,7 @@ export interface TableNodesOptions { cellAttributes: { [key: string]: CellAttributes }; } -export type getFromDOM = (dom: dom.DOMElement) => any; +export type getFromDOM = (dom: Element) => any; export type setDOMAttr = (value: any, attrs: any) => any; export interface CellAttributes { @@ -54,11 +53,11 @@ export class CellSelection { empty: boolean; ranges: SelectionRange[]; - map(doc: Node, mapping: any): any; + map(doc: ProsemirrorNode, mapping: any): any; content(): Slice; replace(tr: Transaction, content: Slice): void; - replaceWith(tr: Transaction, node: Node): void; - forEachCell(f: (node: Node, pos: number) => void): void; + replaceWith(tr: Transaction, node: ProsemirrorNode): void; + forEachCell(f: (node: ProsemirrorNode, pos: number) => void): void; isRowSelection(): boolean; isColSelection(): boolean; eq(other: any): boolean; @@ -67,8 +66,8 @@ export class CellSelection { static colSelection(anchorCell: ResolvedPos, headCell?: ResolvedPos): CellSelection; static rowSelection(anchorCell: ResolvedPos, headCell?: ResolvedPos): CellSelection; - static create(doc: Node, anchorCell: number, headCell?: number): CellSelection; - static fromJSON(doc: Node, json: CellSelectionJSON): CellSelection; + static create(doc: ProsemirrorNode, anchorCell: number, headCell?: number): CellSelection; + static fromJSON(doc: ProsemirrorNode, json: CellSelectionJSON): CellSelection; } export interface Rect { @@ -89,9 +88,9 @@ export class TableMap { nextCell(pos: number, axis: string, dir: number): number; rectBetween(a: number, b: number): Rect; cellsInRect(rect: Rect): number[]; - positionAt(row: number, col: number, table: Node): number; + positionAt(row: number, col: number, table: ProsemirrorNode): number; - static get(table: Node): TableMap; + static get(table: ProsemirrorNode): TableMap; } export function tableEditing(): Plugin; diff --git a/types/prosemirror-transform/index.d.ts b/types/prosemirror-transform/index.d.ts index 15cc94e936..8f386b4bd3 100644 --- a/types/prosemirror-transform/index.d.ts +++ b/types/prosemirror-transform/index.d.ts @@ -1,100 +1,487 @@ -// Type definitions for prosemirror-transform 0.24 +// Type definitions for prosemirror-transform 1.0 // Project: https://github.com/ProseMirror/prosemirror-transform // Definitions by: Bradley Ayers // David Hahn +// Tim Baumann // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.3 +// TypeScript Version: 2.1 -import { Fragment, Mark, MarkType, Node, NodeRange, NodeType, Schema, Slice, ContentMatch } from 'prosemirror-model'; +// IMPORTANT +// This file was generated by https://github.com/bradleyayers/getdocs2ts. Please do not edit manually. +// When you find an error in these declarations, fix the getdocs comment upstream or 'getdocs2ts', then regenerate. +import { ContentMatch, Fragment, Mark, MarkType, Node as ProsemirrorNode, NodeRange, NodeType, Schema, Slice } from 'prosemirror-model'; + +/** + * There are several things that positions can be mapped through. + * Such objects conform to this interface. + */ export interface Mappable { + /** + * Map a position through this object. When given, `assoc` (should + * be -1 or 1, defaults to 1) determines with which side the + * position is associated, which determines in which direction to + * move when a chunk of content is inserted at the mapped position. + */ map(pos: number, assoc?: number): number; + /** + * Map a position, and return an object containing additional + * information about the mapping. The result's `deleted` field tells + * you whether the position was deleted (completely enclosed in a + * replaced range) during the mapping. When content on only one side + * is deleted, the position itself is only considered deleted when + * `assoc` points in the direction of the deleted content. + */ mapResult(pos: number, assoc?: number): MapResult; } +/** + * An object representing a mapped position with extra + * information. + */ export class MapResult { + /** + * The mapped version of the position. + */ pos: number; + /** + * Tells you whether the position was deleted, that is, + * whether the step removed its surroundings from the document. + */ deleted: boolean; } -export class StepMap { - constructor(ranges: number[]) - mapResult(pos: number, assoc?: number): MapResult; - map(pos: number, assoc?: number): number; +/** + * A map describing the deletions and insertions made by a step, which + * can be used to find the correspondence between positions in the + * pre-step version of a document and the same position in the + * post-step version. + */ +export class StepMap implements Mappable { + /** + * Create a position map. The modifications to the document are + * represented as an array of numbers, in which each group of three + * represents a modified chunk as `[start, oldSize, newSize]`. + */ + constructor(ranges: number[]); + /** + * Calls the given function on each of the changed ranges included in + * this map. + */ forEach(f: (oldStart: number, oldEnd: number, newStart: number, newEnd: number) => void): void; + /** + * Create an inverted version of this map. The result can be used to + * map positions in the post-step document to the pre-step document. + */ invert(): StepMap; + /** + * Map a position through this object. When given, `assoc` (should + * be -1 or 1, defaults to 1) determines with which side the + * position is associated, which determines in which direction to + * move when a chunk of content is inserted at the mapped position. + */ + map(pos: number, assoc?: number): number; + /** + * Map a position, and return an object containing additional + * information about the mapping. The result's `deleted` field tells + * you whether the position was deleted (completely enclosed in a + * replaced range) during the mapping. When content on only one side + * is deleted, the position itself is only considered deleted when + * `assoc` points in the direction of the deleted content. + */ + mapResult(pos: number, assoc?: number): MapResult; + /** + * Create a map that moves all positions by offset `n` (which may be + * negative). This can be useful when applying steps meant for a + * sub-document to a larger document, or vice-versa. + */ static offset(n: number): StepMap; } -export class Mapping { - constructor(maps?: StepMap[]) +/** + * A mapping represents a pipeline of zero or more [step + * maps](#transform.StepMap). It has special provisions for losslessly + * handling mapping positions through a series of steps in which some + * steps are inverted versions of earlier steps. (This comes up when + * ‘[rebasing](/docs/guide/#transform.rebasing)’ steps for + * collaboration or history management.) + */ +export class Mapping implements Mappable { + /** + * Create a new mapping with the given position maps. + */ + constructor(maps?: StepMap[]); + /** + * The step maps in this mapping. + */ maps: StepMap[]; + /** + * The starting position in the `maps` array, used when `map` or + * `mapResult` is called. + */ from: number; + /** + * The end position in the `maps` array. + */ to: number; + /** + * Create a mapping that maps only through a part of this one. + */ slice(from?: number, to?: number): Mapping; + /** + * Add a step map to the end of this mapping. If `mirrors` is + * given, it should be the index of the step map that is the mirror + * image of this one. + */ appendMap(map: StepMap, mirrors?: number): void; + /** + * Add all the step maps in a given mapping to this one (preserving + * mirroring information). + */ appendMapping(mapping: Mapping): void; + /** + * Append the inverse of the given mapping to this one. + */ appendMappingInverted(mapping: Mapping): void; + /** + * Map a position through this object. When given, `assoc` (should + * be -1 or 1, defaults to 1) determines with which side the + * position is associated, which determines in which direction to + * move when a chunk of content is inserted at the mapped position. + */ map(pos: number, assoc?: number): number; + /** + * Map a position, and return an object containing additional + * information about the mapping. The result's `deleted` field tells + * you whether the position was deleted (completely enclosed in a + * replaced range) during the mapping. When content on only one side + * is deleted, the position itself is only considered deleted when + * `assoc` points in the direction of the deleted content. + */ mapResult(pos: number, assoc?: number): MapResult; } +/** + * Add a mark to all inline content between two positions. + */ export class AddMarkStep extends Step { - constructor(from: number, to: number, mark: Mark) + constructor(from: number, to: number, mark: Mark); } +/** + * Remove a mark from all inline content between two positions. + */ export class RemoveMarkStep extends Step { - constructor(from: number, to: number, mark: Mark) + constructor(from: number, to: number, mark: Mark); } +/** + * Abstraction to build up and track an array of + * [steps](#transform.Step) representing a document transformation. + * + * Most transforming methods return the `Transform` object itself, so + * that they can be chained. + */ export class Transform { - constructor(doc: Node) + /** + * Create a transform that starts with the given document. + */ + constructor(doc: ProsemirrorNode); + /** + * Add the given mark to the inline content between `from` and `to`. + */ addMark(from: number, to: number, mark: Mark): this; + /** + * Remove marks from inline nodes between `from` and `to`. When `mark` + * is a single mark, remove precisely that mark. When it is a mark type, + * remove all marks of that type. When it is null, remove all marks of + * any type. + */ removeMark(from: number, to: number, mark?: Mark | MarkType): this; - clearIncompatible(pos: number, parentType: NodeType, match?: ContentMatch | null): this; - replaceRange(from: number, to: number, slice: Slice): this; - replaceRangeWith(from: number, to: number, node: Node): this; - deleteRange(from: number, to: number): this; - delete(from: number, to: number): this; + /** + * Removes all marks and nodes from the content of the node at `pos` + * that don't match the given new parent node type. Accepts an + * optional starting [content match](#model.ContentMatch) as third + * argument. + */ + clearIncompatible(pos: number, parentType: NodeType, match?: ContentMatch): this; + /** + * Replace the part of the document between `from` and `to` with the + * given `slice`. + */ replace(from: number, to?: number, slice?: Slice): this; - replaceWith(from: number, to: number, content: Fragment | Node | Node[]): this; - insert(pos: number, content: Fragment | Node | Node[]): this; + /** + * Replace the given range with the given content, which may be a + * fragment, node, or array of nodes. + */ + replaceWith(from: number, to: number, content: Fragment | ProsemirrorNode | ProsemirrorNode[]): this; + /** + * Delete the content between the given positions. + */ + delete(from: number, to: number): this; + /** + * Insert the given content at the given position. + */ + insert(pos: number, content: Fragment | ProsemirrorNode | ProsemirrorNode[]): this; + /** + * Replace a range of the document with a given slice, using `from`, + * `to`, and the slice's [`openStart`](#model.Slice.openStart) property + * as hints, rather than fixed start and end points. This method may + * grow the replaced area or close open nodes in the slice in order to + * get a fit that is more in line with WYSIWYG expectations, by + * dropping fully covered parent nodes of the replaced region when + * they are marked [non-defining](#model.NodeSpec.defining), or + * including an open parent node from the slice that _is_ marked as + * [defining](#model.NodeSpec.defining). + * + * This is the method, for example, to handle paste. The similar + * [`replace`](#transform.Transform.replace) method is a more + * primitive tool which will _not_ move the start and end of its given + * range, and is useful in situations where you need more precise + * control over what happens. + */ + replaceRange(from: number, to: number, slice: Slice): this; + /** + * Replace the given range with a node, but use `from` and `to` as + * hints, rather than precise positions. When from and to are the same + * and are at the start or end of a parent node in which the given + * node doesn't fit, this method may _move_ them out towards a parent + * that does allow the given node to be placed. When the given range + * completely covers a parent node, this method may completely replace + * that parent node. + */ + replaceRangeWith(from: number, to: number, node: ProsemirrorNode): this; + /** + * Delete the given range, expanding it to cover fully covered + * parent nodes until a valid replace is found. + */ + deleteRange(from: number, to: number): this; + /** + * Split the content in the given range off from its parent, if there + * is sibling content before or after it, and move it up the tree to + * the depth specified by `target`. You'll probably want to use + * [`liftTarget`](#transform.liftTarget) to compute `target`, to make + * sure the lift is valid. + */ lift(range: NodeRange, target: number): this; - wrap(range: NodeRange, wrappers: Array<{ type: NodeType, attrs?: object | null }>): this; - setBlockType(from: number, to: number | undefined, type: NodeType, attrs?: object): this; - setNodeMarkup(pos: number, type?: NodeType, attrs?: object, marks?: Mark[]): this; - split(pos: number, depth?: number, typesAfter?: Array<{ type: NodeType, attrs?: object | null }>): this; + /** + * Wrap the given [range](#model.NodeRange) in the given set of wrappers. + * The wrappers are assumed to be valid in this position, and should + * probably be computed with [`findWrapping`](#transform.findWrapping). + */ + wrap(range: NodeRange, wrappers: Array<{ type: NodeType, attrs?: { [key: string]: any } | null }>): this; + /** + * Set the type of all textblocks (partly) between `from` and `to` to + * the given node type with the given attributes. + */ + setBlockType(from: number, to: number | undefined, type: NodeType, attrs?: { [key: string]: any }): this; + /** + * Change the type, attributes, and/or marks of the node at `pos`. + * When `nodeType` is null, the existing node type is preserved, + */ + setNodeMarkup(pos: number, type?: NodeType, attrs?: { [key: string]: any }, marks?: Mark[]): this; + /** + * Split the node at the given position, and optionally, if `depth` is + * greater than one, any number of nodes above that. By default, the + * parts split off will inherit the node type of the original node. + * This can be changed by passing an array of types and attributes to + * use after the split. + */ + split(pos: number, depth?: number, typesAfter?: Array<{ type: NodeType, attrs?: { [key: string]: any } | null }>): this; + /** + * Join the blocks around the given position. If depth is 2, their + * last and first siblings are also joined, and so on. + */ join(pos: number, depth?: number, p1?: boolean): this; - doc: Node; + /** + * The current document (the result of applying the steps in the + * transform). + */ + doc: ProsemirrorNode; + /** + * The steps in this transform. + */ steps: Step[]; - docs: Node[]; + /** + * The documents before each of the steps. + */ + docs: ProsemirrorNode[]; + /** + * A mapping with the maps for each of the steps in this transform. + */ mapping: Mapping; - before: Node; + /** + * The starting document. + */ + before: ProsemirrorNode; + /** + * Apply a new step in this transform, saving the result. Throws an + * error when the step fails. + */ step(step: Step): this; + /** + * Try to apply a step in this transformation, ignoring it if it + * fails. Returns the step result. + */ maybeStep(step: Step): StepResult; + /** + * True when the document has been changed (when there are any + * steps). + */ docChanged: boolean; } +/** + * Replace a part of the document with a slice of new content. + */ export class ReplaceStep extends Step { - constructor(from: number, to: number, slice: Slice, structure?: boolean) + /** + * The given `slice` should fit the 'gap' between `from` and + * `to`—the depths must line up, and the surrounding nodes must be + * able to be joined with the open sides of the slice. When + * `structure` is true, the step will fail if the content between + * from and to is not just a sequence of closing and then opening + * tokens (this is to guard against rebased replace steps + * overwriting something they weren't supposed to). + */ + constructor(from: number, to: number, slice: Slice, structure?: boolean); } +/** + * Replace a part of the document with a slice of content, but + * preserve a range of the replaced content by moving it into the + * slice. + */ export class ReplaceAroundStep extends Step { - constructor(from: number, to: number, gapFrom: number, gapTo: number, slice: Slice, insert: number, structure?: boolean) + /** + * Create a replace-around step with the given range and gap. + * `insert` should be the point in the slice into which the content + * of the gap should be moved. `structure` has the same meaning as + * it has in the [`ReplaceStep`](#transform.ReplaceStep) class. + */ + constructor(from: number, to: number, gapFrom: number, gapTo: number, slice: Slice, insert: number, structure?: boolean); } -export function replaceStep(doc: Node, from: number, to?: number, slice?: Slice): Step | null | undefined; +/** + * ‘Fit’ a slice into a given position in the document, producing a + * [step](#transform.Step) that inserts it. Will return null if + * there's no meaningful way to insert the slice here, or inserting it + * would be a no-op (an empty slice over an empty range). + */ +export function replaceStep(doc: ProsemirrorNode, from: number, to?: number, slice?: Slice): Step | null | void; +/** + * A step object represents an atomic change. It generally applies + * only to the document it was created for, since the positions + * stored in it will only make sense for that document. + * + * New steps are defined by creating classes that extend `Step`, + * overriding the `apply`, `invert`, `map`, `getMap` and `fromJSON` + * methods, and registering your class with a unique + * JSON-serialization identifier using + * [`Step.jsonID`](#transform.Step^jsonID). + */ export class Step { - apply(doc: Node): StepResult; + /** + * Applies this step to the given document, returning a result + * object that either indicates failure, if the step can not be + * applied to this document, or indicates success by containing a + * transformed document. + */ + apply(doc: ProsemirrorNode): StepResult; + /** + * Get the step map that represents the changes made by this step, + * and which can be used to transform between positions in the old + * and the new document. + */ getMap(): StepMap; - invert(doc: Node): Step; - map(mapping: Mappable): Step | null | undefined; - merge(other: Step): Step | null | undefined; - toJSON(): object; - static fromJSON(schema: Schema, json: object): Step; + /** + * Create an inverted version of this step. Needs the document as it + * was before the step as argument. + */ + invert(doc: ProsemirrorNode): Step; + /** + * Map this step through a mappable thing, returning either a + * version of that step with its positions adjusted, or `null` if + * the step was entirely deleted by the mapping. + */ + map(mapping: Mappable): Step | null | void; + /** + * Try to merge this step with another one, to be applied directly + * after it. Returns the merged step when possible, null if the + * steps can't be merged. + */ + merge(other: Step): Step | null | void; + /** + * Create a JSON-serializeable representation of this step. When + * defining this for a custom subclass, make sure the result object + * includes the step type's [JSON id](#transform.Step^jsonID) under + * the `stepType` property. + */ + toJSON(): { [key: string]: any }; + /** + * Deserialize a step from its JSON representation. Will call + * through to the step class' own implementation of this method. + */ + static fromJSON(schema: Schema, json: { [key: string]: any }): Step; + /** + * To be able to serialize steps to JSON, each step needs a string + * ID to attach to its JSON representation. Use this method to + * register an ID for your step classes. Try to pick something + * that's unlikely to clash with steps from other modules. + */ static jsonID(id: string, stepClass: { new(...args: any[]): Step }): void; } +/** + * The result of [applying](#transform.Step.apply) a step. Contains either a + * new document or a failure value. + */ export class StepResult { - doc?: Node | null; + /** + * The transformed document. + */ + doc?: ProsemirrorNode | null; + /** + * Text providing information about a failed step. + */ failed?: string | null; - static ok(doc: Node): StepResult; + /** + * Create a successful step result. + */ + static ok(doc: ProsemirrorNode): StepResult; + /** + * Create a failed step result. + */ static fail(message: string): StepResult; - static fromReplace(doc: Node, from: number, to: number, slice: Slice): StepResult; + /** + * Call [`Node.replace`](#model.Node.replace) with the given + * arguments. Create a successful result if it succeeds, and a + * failed one if it throws a `ReplaceError`. + */ + static fromReplace(doc: ProsemirrorNode, from: number, to: number, slice: Slice): StepResult; } -export function liftTarget(range: NodeRange): number | null | undefined; -export function findWrapping(range: NodeRange, nodeType: NodeType, attrs?: object): Array<{ type: NodeType, attrs?: object | null }> | null | undefined; -export function canSplit(doc: Node, pos: number, depth?: number, typesAfter?: Array<{ type: NodeType, attrs?: object | null }>): boolean; -export function canJoin(doc: Node, pos: number): boolean; -export function joinPoint(doc: Node, pos: number, dir?: number): number | null | undefined; -export function insertPoint(doc: Node, pos: number, nodeType: NodeType, attrs?: object): number | null | undefined; +/** + * Try to find a target depth to which the content in the given range + * can be lifted. Will not go across + * [isolating](#model.NodeSpec.isolating) parent nodes. + */ +export function liftTarget(range: NodeRange): number | null | void; +/** + * Try to find a valid way to wrap the content in the given range in a + * node of the given type. May introduce extra nodes around and inside + * the wrapper node, if necessary. Returns null if no valid wrapping + * could be found. + */ +export function findWrapping(range: NodeRange, nodeType: NodeType, attrs?: { [key: string]: any }): Array<{ type: NodeType, attrs?: { [key: string]: any } | null }> | null | void; +/** + * Check whether splitting at the given position is allowed. + */ +export function canSplit(doc: ProsemirrorNode, pos: number, depth?: number, typesAfter?: Array<{ type: NodeType, attrs?: { [key: string]: any } | null }>): boolean; +/** + * Test whether the blocks before and after a given position can be + * joined. + */ +export function canJoin(doc: ProsemirrorNode, pos: number): boolean; +/** + * Find an ancestor of the given position that can be joined to the + * block before (or after if `dir` is positive). Returns the joinable + * point, if any. + */ +export function joinPoint(doc: ProsemirrorNode, pos: number, dir?: number): number | null | void; +/** + * Try to find a point where a node of the given type can be inserted + * near `pos`, by searching up the node hierarchy when `pos` itself + * isn't a valid place but is at the start or end of a node. Return + * null if no position was found. + */ +export function insertPoint(doc: ProsemirrorNode, pos: number, nodeType: NodeType): number | null | void; diff --git a/types/prosemirror-view/dom.d.ts b/types/prosemirror-view/dom.d.ts deleted file mode 100644 index b4b02d1c24..0000000000 --- a/types/prosemirror-view/dom.d.ts +++ /dev/null @@ -1,21 +0,0 @@ -export type DOMDataTransfer = DataTransfer; -export type DOMDocument = Document; -export type DOMElement = HTMLElement; -export type DOMEvent = Event; -export type DOMFragment = DocumentFragment; -export type DOMKeyboardEvent = KeyboardEvent; -export type DOMMouseEvent = MouseEvent; -export type DOMMutationRecord = MutationRecord; -export type DOMNode = Node; - -export { - DOMDataTransfer as DataTransfer, - DOMDocument as Document, - DOMElement as Element, - DOMEvent as Event, - DOMFragment as DocumentFragment, - DOMKeyboardEvent as KeyboardEvent, - DOMMouseEvent as MouseEvent, - DOMMutationRecord as MutationRecord, - DOMNode as Node, -}; diff --git a/types/prosemirror-view/index.d.ts b/types/prosemirror-view/index.d.ts index bad46cd6ef..0ce2e37794 100644 --- a/types/prosemirror-view/index.d.ts +++ b/types/prosemirror-view/index.d.ts @@ -1,93 +1,518 @@ -// Type definitions for prosemirror-view 0.24 +// Type definitions for prosemirror-view 1.0 // Project: https://github.com/ProseMirror/prosemirror-view // Definitions by: Bradley Ayers // David Hahn +// Tim Baumann // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped -// TypeScript Version: 2.3 +// TypeScript Version: 2.1 -import { DOMParser, DOMSerializer, Node, ResolvedPos, Slice } from 'prosemirror-model'; +// IMPORTANT +// This file was generated by https://github.com/bradleyayers/getdocs2ts. Please do not edit manually. +// When you find an error in these declarations, fix the getdocs comment upstream or 'getdocs2ts', then regenerate. + +import { DOMParser, DOMSerializer, Node as ProsemirrorNode, ResolvedPos, Slice } from 'prosemirror-model'; import { EditorState, Selection, Transaction } from 'prosemirror-state'; import { Mapping } from 'prosemirror-transform'; -import * as dom from './dom'; +/** + * Decoration objects can be provided to the view through the + * [`decorations` prop](#view.EditorProps.decorations). They come in + * several variants—see the static members of this class for details. + */ export class Decoration { - spec: object; - static widget(pos: number, dom: dom.Node, spec?: { side?: number | null, stopEvent?: ((event: Event) => boolean) | null, key?: string | null }): Decoration; + /** + * The start position of the decoration. + */ + from: number; + /** + * The end position. Will be the same as `from` for [widget + * decorations](#view.Decoration^widget). + */ + to: number; + /** + * The spec provided when creating this decoration. Can be useful + * if you've stored extra information in that object. + */ + spec: { [key: string]: any }; + /** + * Creates a widget decoration, which is a DOM node that's shown in + * the document at the given position. + */ + static widget(pos: number, dom: Node, spec?: { side?: number | null, stopEvent?: ((event: Event) => boolean) | null, key?: string | null }): Decoration; + /** + * Creates an inline decoration, which adds the given attributes to + * each inline node between `from` and `to`. + */ static inline(from: number, to: number, attrs: DecorationAttrs, spec?: { inclusiveStart?: boolean | null, inclusiveEnd?: boolean | null }): Decoration; - static node(from: number, to: number, attrs: DecorationAttrs, spec?: object): Decoration; + /** + * Creates a node decoration. `from` and `to` should point precisely + * before and after a node in the document. That node, and only that + * node, will receive the given attributes. + */ + static node(from: number, to: number, attrs: DecorationAttrs, spec?: { [key: string]: any }): Decoration; } +/** + * A set of attributes to add to a decorated node. Most properties + * simply directly correspond to DOM attributes of the same name, + * which will be set to the property's value. These are exceptions: + */ export interface DecorationAttrs { + /** + * A CSS class name or a space-separated set of class names to be + * _added_ to the classes that the node already had. + */ class?: string | null; + /** + * A string of CSS to be _added_ to the node's existing `style` property. + */ style?: string | null; + /** + * When non-null, the target node is wrapped in a DOM element of + * this type (and the other attributes are applied to this element). + */ nodeName?: string | null; } +/** + * A collection of [decorations](#view.Decoration), organized in + * such a way that the drawing algorithm can efficiently use and + * compare them. This is a persistent data structure—it is not + * modified, updates create a new value. + */ export class DecorationSet { - find(start?: number, end?: number, predicate?: ((spec: object) => boolean) | null): Decoration[]; - map(mapping: Mapping, doc: Node, options?: { onRemove?: ((decorationSpec: object) => void) | null }): DecorationSet; - add(doc: Node, decorations: Decoration[]): DecorationSet; + /** + * Find all decorations in this set which touch the given range + * (including decorations that start or end directly at the + * boundaries) and match the given predicate on their spec. When + * `start` and `end` are omitted, all decorations in the set are + * considered. When `predicate` isn't given, all decorations are + * asssumed to match. + */ + find(start?: number, end?: number, predicate?: (spec: { [key: string]: any }) => boolean): Decoration[]; + /** + * Map the set of decorations in response to a change in the + * document. + */ + map(mapping: Mapping, doc: ProsemirrorNode, options?: { onRemove?: ((decorationSpec: { [key: string]: any }) => void) | null }): DecorationSet; + /** + * Add the given array of decorations to the ones in the set, + * producing a new set. Needs access to the current document to + * create the appropriate tree structure. + */ + add(doc: ProsemirrorNode, decorations: Decoration[]): DecorationSet; + /** + * Create a new set that contains the decorations in this set, minus + * the ones in the given array. + */ remove(decorations: Decoration[]): DecorationSet; - static create(doc: Node, decorations: Decoration[]): DecorationSet; + /** + * Create a set of decorations, using the structure of the given + * document. + */ + static create(doc: ProsemirrorNode, decorations: Decoration[]): DecorationSet; + /** + * The empty set of decorations. + */ static empty: DecorationSet; } +/** + * An editor view manages the DOM structure that represents an + * editable document. Its state and behavior are determined by its + * [props](#view.DirectEditorProps). + */ export class EditorView { - constructor(place: dom.Node | ((p: dom.Node) => void) | { mount: dom.Node } | undefined, props: EditorProps) + /** + * Create a view. `place` may be a DOM node that the editor should + * be appended to, a function that will place it into the document, + * or an object whose `mount` property holds the node to use as the + * document container. If it is `null`, the editor will not be added + * to the document. + */ + constructor(place: Node | ((p: Node) => void) | { mount: Node } | undefined, props: DirectEditorProps); + /** + * The view's current [state](#state.EditorState). + */ state: EditorState; + /** + * An editable DOM node containing the document. (You probably + * should not directly interfere with its content.) + */ dom: Element; - props: EditorProps; - update(props: EditorProps): void; - setProps(props: EditorProps): void; + /** + * When editor content is being dragged, this object contains + * information about the dragged slice and whether it is being + * copied or moved. At any other time, it is null. + */ + dragging?: { slice: Slice, move: boolean } | null; + /** + * The view's current [props](#view.EditorProps). + */ + props: DirectEditorProps; + /** + * Update the view's props. Will immediately cause an update to + * the DOM. + */ + update(props: DirectEditorProps): void; + /** + * Update the view by updating existing props object with the object + * given as argument. Equivalent to `view.update(Object.assign({}, + * view.props, props))`. + */ + setProps(props: DirectEditorProps): void; + /** + * Update the editor's `state` prop, without touching any of the + * other props. + */ updateState(state: EditorState): void; + /** + * Goes over the values of a prop, first those provided directly, + * then those from plugins (in order), and calls `f` every time a + * non-undefined value is found. When `f` returns a truthy value, + * that is immediately returned. When `f` isn't provided, it is + * treated as the identity function (the prop value is returned + * directly). + */ + someProp(propName: string, f?: (prop: any) => any): any; + /** + * Query whether the view has focus. + */ hasFocus(): boolean; - someProp(propName: string, f: (prop: any) => any): any; + /** + * Focus the editor. + */ focus(): void; + /** + * Get the document root in which the editor exists. This will + * usually be the top-level `document`, but might be a [shadow + * DOM](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Shadow_DOM) + * root if the editor is inside one. + */ root: Document | DocumentFragment; - posAtCoords(coords: { left: number, top: number }): { pos: number, inside: number } | null | undefined; + /** + * Given a pair of viewport coordinates, return the document + * position that corresponds to them. May return null if the given + * coordinates aren't inside of the visible editor. When an object + * is returned, its `pos` property is the position nearest to the + * coordinates, and its `inside` property holds the position of the + * inner node that the position falls inside of, or -1 if it is at + * the top level, not in any node. + */ + posAtCoords(coords: { left: number, top: number }): { pos: number, inside: number } | null | void; + /** + * Returns the viewport rectangle at a given document position. `left` + * and `right` will be the same number, as this returns a flat + * cursor-ish rectangle. + */ coordsAtPos(pos: number): { left: number, right: number, top: number, bottom: number }; - domAtPos(pos: number): { node: dom.Node; offset: number }; - endOfTextblock(dir: 'up' | 'down' | 'left' | 'right' | 'forward' | 'backward', state?: EditorState): boolean; + /** + * Find the DOM position that corresponds to the given document + * position. Note that you should **not** mutate the editor's + * internal DOM, only inspect it (and even that is usually not + * necessary). + */ + domAtPos(pos: number): { node: Node, offset: number }; + /** + * Find out whether the selection is at the end of a textblock when + * moving in a given direction. When, for example, given `"left"`, + * it will return true if moving left from the current cursor + * position would leave that position's parent textblock. Will apply + * to the view's current state by default, but it is possible to + * pass a different state. + */ + endOfTextblock(dir: "up" | "down" | "left" | "right" | "forward" | "backward", state?: EditorState): boolean; + /** + * Removes the editor from the DOM and destroys all [node + * views](#view.NodeView). + */ destroy(): void; + /** + * Dispatch a transaction. Will call + * [`dispatchTransaction`](#view.DirectEditorProps.dispatchTransaction) + * when given, and otherwise defaults to applying the transaction to + * the current state and calling + * [`updateState`](#view.EditorView.updateState) with the result. + * This method is bound to the view instance, so that it can be + * easily passed around. + */ dispatch(tr: Transaction): void; } +/** + * Props are configuration values that can be passed to an editor view + * or included in a plugin. This interface lists the supported props. + * + * The various event-handling functions may all return `true` to + * indicate that they handled the given event. The view will then take + * care to call `preventDefault` on the event, except with + * `handleDOMEvents`, where the handler itself is responsible for that. + * + * How a prop is resolved depends on the prop. Handler functions are + * called one at a time, starting with the base props and then + * searching through the plugins (in order of appearance) until one of + * them returns true. For some props, the first plugin that yields a + * value gets precedence. + */ export interface EditorProps { - state: EditorState; - dispatchTransaction?: ((tr: Transaction) => void) | null; + /** + * Can be an object mapping DOM event type names to functions that + * handle them. Such functions will be called before any handling + * ProseMirror does of events fired on the editable DOM element. + * Contrary to the other event handling props, when returning true + * from such a function, you are responsible for calling + * `preventDefault` yourself (or not, if you want to allow the + * default behavior). + */ handleDOMEvents?: { [name: string]: (view: EditorView, event: Event) => boolean } | null; + /** + * Called when the editor receives a `keydown` event. + */ handleKeyDown?: ((view: EditorView, event: KeyboardEvent) => boolean) | null; + /** + * Handler for `keypress` events. + */ handleKeyPress?: ((view: EditorView, event: KeyboardEvent) => boolean) | null; + /** + * Whenever the user directly input text, this handler is called + * before the input is applied. If it returns `true`, the default + * behavior of actually inserting the text is suppressed. + */ handleTextInput?: ((view: EditorView, from: number, to: number, text: string) => boolean) | null; - handleClickOn?: ((view: EditorView, pos: number, node: Node, nodePos: number, event: MouseEvent, direct: boolean) => boolean) | null; + /** + * Called for each node around a click, from the inside out. The + * `direct` flag will be true for the inner node. + */ + handleClickOn?: ((view: EditorView, pos: number, node: ProsemirrorNode, nodePos: number, event: MouseEvent, direct: boolean) => boolean) | null; + /** + * Called when the editor is clicked, after `handleClickOn` handlers + * have been called. + */ handleClick?: ((view: EditorView, pos: number, event: MouseEvent) => boolean) | null; - handleDoubleClickOn?: ((view: EditorView, pos: number, node: Node, nodePos: number, event: MouseEvent, direct: boolean) => boolean) | null; + /** + * Called for each node around a double click. + */ + handleDoubleClickOn?: ((view: EditorView, pos: number, node: ProsemirrorNode, nodePos: number, event: MouseEvent, direct: boolean) => boolean) | null; + /** + * Called when the editor is double-clicked, after `handleDoubleClickOn`. + */ handleDoubleClick?: ((view: EditorView, pos: number, event: MouseEvent) => boolean) | null; - handleTripleClickOn?: ((view: EditorView, pos: number, node: Node, nodePos: number, event: MouseEvent, direct: boolean) => boolean) | null; + /** + * Called for each node around a triple click. + */ + handleTripleClickOn?: ((view: EditorView, pos: number, node: ProsemirrorNode, nodePos: number, event: MouseEvent, direct: boolean) => boolean) | null; + /** + * Called when the editor is triple-clicked, after `handleTripleClickOn`. + */ handleTripleClick?: ((view: EditorView, pos: number, event: MouseEvent) => boolean) | null; + /** + * Can be used to override the behavior of pasting. `slice` is the + * pasted content parsed by the editor, but you can directly access + * the event to get at the raw content. + */ handlePaste?: ((view: EditorView, event: Event, slice: Slice) => boolean) | null; + /** + * Called when something is dropped on the editor. `moved` will be + * true if this drop moves from the current selection (which should + * thus be deleted). + */ handleDrop?: ((view: EditorView, event: Event, slice: Slice, moved: boolean) => boolean) | null; + /** + * Called when the view, after updating its state, tries to scroll + * the selection into view. A handler function may return false to + * indicate that it did not handle the scrolling and further + * handlers or the default behavior should be tried. + */ handleScrollToSelection?: ((view: EditorView) => boolean) | null; - createSelectionBetween?: ((view: EditorView, anchor: ResolvedPos, head: ResolvedPos) => Selection | null | undefined) | null; + /** + * Can be used to override the way a selection is created when + * reading a DOM selection between the given anchor and head. + */ + createSelectionBetween?: ((view: EditorView, anchor: ResolvedPos, head: ResolvedPos) => Selection | null | void) | null; + /** + * The [parser](#model.DOMParser) to use when reading editor changes + * from the DOM. Defaults to calling + * [`DOMParser.fromSchema`](#model.DOMParser^fromSchema) on the + * editor's schema. + */ domParser?: DOMParser | null; + /** + * Can be used to transform pasted HTML text, _before_ it is parsed, + * for example to clean it up. + */ + transformPastedHTML?: ((html: string) => string) | null; + /** + * The [parser](#model.DOMParser) to use when reading content from + * the clipboard. When not given, the value of the + * [`domParser`](#view.EditorProps.domParser) prop is used. + */ clipboardParser?: DOMParser | null; - clipboardTextParser?: ((p: string, $context: ResolvedPos) => Slice) | null; + /** + * Transform pasted plain text. + */ + transformPastedText?: ((text: string) => string) | null; + /** + * A function to parse text from the clipboard into a document + * slice. Called after + * [`transformPastedText`](#view.EditorProps.transformPastedText). + * The default behavior is to split the text into lines, wrap them + * in `

      ` tags, and call + * [`clipboardParser`](#view.EditorProps.clipboardParser) on it. + */ + clipboardTextParser?: ((text: string, $context: ResolvedPos) => Slice) | null; + /** + * Can be used to transform pasted content before it is applied to + * the document. + */ transformPasted?: ((p: Slice) => Slice) | null; - transformPastedHTML?: ((p: string) => string) | null; - transformPastedText?: ((p: string) => string) | null; - nodeViews?: { [name: string]: (node: Node, view: EditorView, getPos: () => number, decorations: Decoration[]) => NodeView } | null; + /** + * Allows you to pass custom rendering and behavior logic for nodes + * and marks. Should map node and mark names to constructor + * functions that produce a [`NodeView`](#view.NodeView) object + * implementing the node's display behavior. `getPos` is a function + * that can be called to get the node's current position, which can + * be useful when creating transactions to update it. + * + * `decorations` is an array of node or inline decorations that are + * active around the node. They are automatically drawn in the + * normal way, and you will usually just want to ignore this, but + * they can also be used as a way to provide context information to + * the node view without adding it to the document itself. + */ + nodeViews?: { [name: string]: (node: ProsemirrorNode, view: EditorView, getPos: () => number, decorations: Decoration[]) => NodeView } | null; + /** + * The DOM serializer to use when putting content onto the + * clipboard. If not given, the result of + * [`DOMSerializer.fromSchema`](#model.DOMSerializer^fromSchema) + * will be used. + */ clipboardSerializer?: DOMSerializer | null; - clipboardTextSerializer?: ((slice: Slice) => string) | null; - decorations?: ((p: EditorState) => DecorationSet | null | undefined) | null; - editable?: ((p: EditorState) => boolean) | null; - attributes?: { [name: string]: string } | ((p: EditorState) => { [name: string]: string } | null | undefined) | null; + /** + * A function that will be called to get the text for the current + * selection when copying text to the clipboard. By default, the + * editor will use [`textBetween`](#model.Node.textBetween) on the + * selected range. + */ + clipboardTextSerializer?: ((p: Slice) => string) | null; + /** + * A set of [document decorations](#view.Decoration) to show in the + * view. + */ + decorations?: ((state: EditorState) => DecorationSet | null | void) | null; + /** + * When this returns false, the content of the view is not directly + * editable. + */ + editable?: ((state: EditorState) => boolean) | null; + /** + * Control the DOM attributes of the editable element. May be either + * an object or a function going from an editor state to an object. + * By default, the element will get a class `"ProseMirror"`, and + * will have its `contentEditable` attribute determined by the + * [`editable` prop](#view.EditorProps.editable). Additional classes + * provided here will be added to the class. For other attributes, + * the value provided first (as in + * [`someProp`](#view.EditorView.someProp)) will be used. + */ + attributes?: { [name: string]: string } | ((p: EditorState) => { [name: string]: string } | null | void) | null; + /** + * Determines the distance (in pixels) between the cursor and the + * end of the visible viewport at which point, when scrolling the + * cursor into view, scrolling takes place. Defaults to 0. + */ scrollThreshold?: number | null; + /** + * Determines the extra space (in pixels) that is left above or + * below the cursor when it is scrolled into view. Defaults to 5. + */ scrollMargin?: number | null; } +/** + * The props object given directly to the editor view supports two + * fields that can't be used in plugins: + */ +export interface DirectEditorProps extends EditorProps { + /** + * The current state of the editor. + */ + state: EditorState; + /** + * The callback over which to send transactions (state updates) + * produced by the view. If you specify this, you probably want to + * make sure this ends up calling the view's + * [`updateState`](#view.EditorView.updateState) method with a new + * state that has the transaction + * [applied](#state.EditorState.apply). + */ + dispatchTransaction?: ((tr: Transaction) => void) | null; +} +/** + * By default, document nodes are rendered using the result of the + * [`toDOM`](#model.NodeSpec.toDOM) method of their spec, and managed + * entirely by the editor. For some use cases, such as embedded + * node-specific editing interfaces, you want more control over + * the behavior of a node's in-editor representation, and need to + * [define](#view.EditorProps.nodeViews) a custom node view. + * + * Objects returned as node views must conform to this interface. + */ export interface NodeView { - dom?: dom.Node | null; - contentDOM?: dom.Node | null; - update?: ((node: Node, decorations: Decoration[]) => boolean) | null; + /** + * The outer DOM node that represents the document node. When not + * given, the default strategy is used to create a DOM node. + */ + dom?: Node | null; + /** + * The DOM node that should hold the node's content. Only meaningful + * if the node view also defines a `dom` property and if its node + * type is not a leaf node type. When this is present, ProseMirror + * will take care of rendering the node's children into it. When it + * is not present, the node view itself is responsible for rendering + * (or deciding not to render) its child nodes. + */ + contentDOM?: Node | null; + /** + * When given, this will be called when the view is updating itself. + * It will be given a node (possibly of a different type), and an + * array of active decorations (which are automatically drawn, and + * the node view may ignore if it isn't interested in them), and + * should return true if it was able to update to that node, and + * false otherwise. If the node view has a `contentDOM` property (or + * no `dom` property), updating its child nodes will be handled by + * ProseMirror. + */ + update?: ((node: ProsemirrorNode, decorations: Decoration[]) => boolean) | null; + /** + * Can be used to override the way the node's selected status (as a + * node selection) is displayed. + */ selectNode?: (() => void) | null; + /** + * When defining a `selectNode` method, you should also provide a + * `deselectNode` method to remove the effect again. + */ deselectNode?: (() => void) | null; + /** + * This will be called to handle setting the selection inside the + * node. The `anchor` and `head` positions are relative to the start + * of the node. By default, a DOM selection will be created between + * the DOM positions corresponding to those positions, but if you + * override it you can do something else. + */ setSelection?: ((anchor: number, head: number, root: Document) => void) | null; + /** + * Can be used to prevent the editor view from trying to handle some + * or all DOM events that bubble up from the node view. Events for + * which this returns true are not handled by the editor. + */ stopEvent?: ((event: Event) => boolean) | null; + /** + * Called when a DOM + * [mutation](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) + * happens within the view. Return false if the editor should + * re-parse the range around the mutation, true if it can safely be + * ignored. + */ ignoreMutation?: ((p: MutationRecord) => boolean) | null; + /** + * Called when the node view is removed from the editor or the whole + * editor is destroyed. + */ destroy?: (() => void) | null; }