@tiptap/core
Advanced tools
Comparing version 2.9.1 to 2.10.0
@@ -1,2 +0,2 @@ | ||
import { ParseOptions } from '@tiptap/pm/model'; | ||
import { Fragment, Node as ProseMirrorNode, ParseOptions } from '@tiptap/pm/model'; | ||
import { Content, RawCommands } from '../types.js'; | ||
@@ -15,3 +15,3 @@ declare module '@tiptap/core' { | ||
*/ | ||
value: Content, | ||
value: Content | ProseMirrorNode | Fragment, | ||
/** | ||
@@ -18,0 +18,0 @@ * Optional options |
@@ -1,2 +0,2 @@ | ||
import { ParseOptions } from '@tiptap/pm/model'; | ||
import { Fragment, Node as ProseMirrorNode, ParseOptions } from '@tiptap/pm/model'; | ||
import { Content, Range, RawCommands } from '../types.js'; | ||
@@ -18,3 +18,3 @@ declare module '@tiptap/core' { | ||
*/ | ||
value: Content, | ||
value: Content | ProseMirrorNode | Fragment, | ||
/** | ||
@@ -21,0 +21,0 @@ * Optional options |
@@ -1,2 +0,2 @@ | ||
import { ParseOptions } from '@tiptap/pm/model'; | ||
import { Fragment, Node as ProseMirrorNode, ParseOptions } from '@tiptap/pm/model'; | ||
import { Content, RawCommands } from '../types.js'; | ||
@@ -17,3 +17,3 @@ declare module '@tiptap/core' { | ||
*/ | ||
content: Content, | ||
content: Content | Fragment | ProseMirrorNode, | ||
/** | ||
@@ -20,0 +20,0 @@ * Whether to emit an update event. |
@@ -9,2 +9,3 @@ type StringKeyOf<T> = Extract<keyof T, string>; | ||
off<EventName extends StringKeyOf<T>>(event: EventName, fn?: CallbackFunction<T, EventName>): this; | ||
once<EventName extends StringKeyOf<T>>(event: EventName, fn: CallbackFunction<T, EventName>): this; | ||
removeAllListeners(): void; | ||
@@ -11,0 +12,0 @@ } |
@@ -47,3 +47,3 @@ import { Plugin, Transaction } from '@tiptap/pm/state'; | ||
name: string; | ||
parent: Exclude<ParentConfig<ExtensionConfig<Options, Storage>>['addOptions'], undefined>; | ||
parent: ParentConfig<ExtensionConfig<Options, Storage>>['addOptions']; | ||
}) => Options; | ||
@@ -62,3 +62,3 @@ /** | ||
options: Options; | ||
parent: Exclude<ParentConfig<ExtensionConfig<Options, Storage>>['addStorage'], undefined>; | ||
parent: ParentConfig<ExtensionConfig<Options, Storage>>['addStorage']; | ||
}) => Storage; | ||
@@ -65,0 +65,0 @@ /** |
@@ -1,2 +0,2 @@ | ||
import { Node as ProseMirrorNode, ParseOptions, Schema } from '@tiptap/pm/model'; | ||
import { Fragment, Node as ProseMirrorNode, ParseOptions, Schema } from '@tiptap/pm/model'; | ||
import { Content } from '../types.js'; | ||
@@ -10,5 +10,5 @@ /** | ||
*/ | ||
export declare function createDocument(content: Content, schema: Schema, parseOptions?: ParseOptions, options?: { | ||
export declare function createDocument(content: Content | ProseMirrorNode | Fragment, schema: Schema, parseOptions?: ParseOptions, options?: { | ||
errorOnInvalidContent?: boolean; | ||
}): ProseMirrorNode; | ||
//# sourceMappingURL=createDocument.d.ts.map |
@@ -15,3 +15,3 @@ import { Fragment, Node as ProseMirrorNode, ParseOptions, Schema } from '@tiptap/pm/model'; | ||
*/ | ||
export declare function createNodeFromContent(content: Content, schema: Schema, options?: CreateNodeFromContentOptions): ProseMirrorNode | Fragment; | ||
export declare function createNodeFromContent(content: Content | ProseMirrorNode | Fragment, schema: Schema, options?: CreateNodeFromContentOptions): ProseMirrorNode | Fragment; | ||
//# sourceMappingURL=createNodeFromContent.d.ts.map |
import { MarkType, ResolvedPos } from '@tiptap/pm/model'; | ||
import { Range } from '../types.js'; | ||
export declare function getMarkRange($pos: ResolvedPos, type: MarkType, attributes?: Record<string, any>): Range | void; | ||
/** | ||
* Get the range of a mark at a resolved position. | ||
*/ | ||
export declare function getMarkRange( | ||
/** | ||
* The position to get the mark range for. | ||
*/ | ||
$pos: ResolvedPos, | ||
/** | ||
* The mark type to get the range for. | ||
*/ | ||
type: MarkType, | ||
/** | ||
* The attributes to match against. | ||
* If not provided, only the first mark at the position will be matched. | ||
*/ | ||
attributes?: Record<string, any>): Range | void; | ||
//# sourceMappingURL=getMarkRange.d.ts.map |
@@ -7,3 +7,3 @@ import { MarkType } from '@tiptap/pm/model'; | ||
* matched text is typed into it. | ||
* @see https://tiptap.dev/guide/custom-extensions/#input-rules | ||
* @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#input-rules | ||
*/ | ||
@@ -10,0 +10,0 @@ export declare function markInputRule(config: { |
@@ -7,3 +7,3 @@ import { NodeType } from '@tiptap/pm/model'; | ||
* matched text is typed into it. | ||
* @see https://tiptap.dev/guide/custom-extensions/#input-rules | ||
* @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#input-rules | ||
*/ | ||
@@ -10,0 +10,0 @@ export declare function nodeInputRule(config: { |
@@ -9,3 +9,3 @@ import { NodeType } from '@tiptap/pm/model'; | ||
* only occur at the start of a textblock. | ||
* @see https://tiptap.dev/guide/custom-extensions/#input-rules | ||
* @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#input-rules | ||
*/ | ||
@@ -12,0 +12,0 @@ export declare function textblockTypeInputRule(config: { |
@@ -5,3 +5,3 @@ import { InputRule, InputRuleFinder } from '../InputRule.js'; | ||
* matched text is typed into it. | ||
* @see https://tiptap.dev/guide/custom-extensions/#input-rules | ||
* @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#input-rules | ||
*/ | ||
@@ -8,0 +8,0 @@ export declare function textInputRule(config: { |
@@ -18,3 +18,3 @@ import { Node as ProseMirrorNode, NodeType } from '@tiptap/pm/model'; | ||
* return a boolean to indicate whether a join should happen. | ||
* @see https://tiptap.dev/guide/custom-extensions/#input-rules | ||
* @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#input-rules | ||
*/ | ||
@@ -21,0 +21,0 @@ export declare function wrappingInputRule(config: { |
@@ -47,3 +47,3 @@ import { DOMOutputSpec, Mark as ProseMirrorMark, MarkSpec, MarkType } from '@tiptap/pm/model'; | ||
name: string; | ||
parent: Exclude<ParentConfig<MarkConfig<Options, Storage>>['addOptions'], undefined>; | ||
parent: ParentConfig<MarkConfig<Options, Storage>>['addOptions']; | ||
}) => Options; | ||
@@ -62,3 +62,3 @@ /** | ||
options: Options; | ||
parent: Exclude<ParentConfig<MarkConfig<Options, Storage>>['addStorage'], undefined>; | ||
parent: ParentConfig<MarkConfig<Options, Storage>>['addStorage']; | ||
}) => Storage; | ||
@@ -65,0 +65,0 @@ /** |
@@ -47,3 +47,3 @@ import { DOMOutputSpec, Node as ProseMirrorNode, NodeSpec, NodeType } from '@tiptap/pm/model'; | ||
name: string; | ||
parent: Exclude<ParentConfig<NodeConfig<Options, Storage>>['addOptions'], undefined>; | ||
parent: ParentConfig<NodeConfig<Options, Storage>>['addOptions']; | ||
}) => Options; | ||
@@ -62,3 +62,3 @@ /** | ||
options: Options; | ||
parent: Exclude<ParentConfig<NodeConfig<Options, Storage>>['addStorage'], undefined>; | ||
parent: ParentConfig<NodeConfig<Options, Storage>>['addStorage']; | ||
}) => Storage; | ||
@@ -495,2 +495,18 @@ /** | ||
/** | ||
* Allows a **single** node to be set as linebreak equivalent (e.g. hardBreak). | ||
* When converting between block types that have whitespace set to "pre" | ||
* and don't support the linebreak node (e.g. codeBlock) and other block types | ||
* that do support the linebreak node (e.g. paragraphs) - this node will be used | ||
* as the linebreak instead of stripping the newline. | ||
* | ||
* See [linebreakReplacement](https://prosemirror.net/docs/ref/#model.NodeSpec.linebreakReplacement). | ||
*/ | ||
linebreakReplacement?: NodeSpec['linebreakReplacement'] | ((this: { | ||
name: string; | ||
options: Options; | ||
storage: Storage; | ||
parent: ParentConfig<NodeConfig<Options, Storage>>['linebreakReplacement']; | ||
editor?: Editor; | ||
}) => NodeSpec['linebreakReplacement']); | ||
/** | ||
* When enabled, enables both | ||
@@ -497,0 +513,0 @@ * [`definingAsContext`](https://prosemirror.net/docs/ref/#model.NodeSpec.definingAsContext) and |
@@ -14,3 +14,3 @@ import { EditorState, Plugin } from '@tiptap/pm/state'; | ||
* Paste rules are used to react to pasted content. | ||
* @see https://tiptap.dev/guide/custom-extensions/#paste-rules | ||
* @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#paste-rules | ||
*/ | ||
@@ -17,0 +17,0 @@ export declare class PasteRule { |
@@ -7,3 +7,3 @@ import { MarkType } from '@tiptap/pm/model'; | ||
* matched text is pasted into it. | ||
* @see https://tiptap.dev/guide/custom-extensions/#paste-rules | ||
* @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#paste-rules | ||
*/ | ||
@@ -10,0 +10,0 @@ export declare function markPasteRule(config: { |
@@ -7,3 +7,3 @@ import { NodeType } from '@tiptap/pm/model'; | ||
* matched text is pasted into it. | ||
* @see https://tiptap.dev/guide/custom-extensions/#paste-rules | ||
* @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#paste-rules | ||
*/ | ||
@@ -10,0 +10,0 @@ export declare function nodePasteRule(config: { |
@@ -5,3 +5,3 @@ import { PasteRule, PasteRuleFinder } from '../PasteRule.js'; | ||
* matched text is pasted into it. | ||
* @see https://tiptap.dev/guide/custom-extensions/#paste-rules | ||
* @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#paste-rules | ||
*/ | ||
@@ -8,0 +8,0 @@ export declare function textPasteRule(config: { |
{ | ||
"name": "@tiptap/core", | ||
"description": "headless rich text editor", | ||
"version": "2.9.1", | ||
"version": "2.10.0", | ||
"homepage": "https://tiptap.dev", | ||
@@ -35,3 +35,3 @@ "keywords": [ | ||
"devDependencies": { | ||
"@tiptap/pm": "^2.9.1" | ||
"@tiptap/pm": "^2.10.0" | ||
}, | ||
@@ -38,0 +38,0 @@ "peerDependencies": { |
@@ -1,2 +0,2 @@ | ||
import { ParseOptions } from '@tiptap/pm/model' | ||
import { Fragment, Node as ProseMirrorNode, ParseOptions } from '@tiptap/pm/model' | ||
@@ -17,3 +17,3 @@ import { Content, RawCommands } from '../types.js' | ||
*/ | ||
value: Content, | ||
value: Content | ProseMirrorNode | Fragment, | ||
@@ -27,3 +27,3 @@ /** | ||
*/ | ||
parseOptions?: ParseOptions | ||
parseOptions?: ParseOptions; | ||
@@ -33,8 +33,8 @@ /** | ||
*/ | ||
updateSelection?: boolean | ||
applyInputRules?: boolean | ||
applyPasteRules?: boolean | ||
}, | ||
) => ReturnType | ||
} | ||
updateSelection?: boolean; | ||
applyInputRules?: boolean; | ||
applyPasteRules?: boolean; | ||
} | ||
) => ReturnType; | ||
}; | ||
} | ||
@@ -41,0 +41,0 @@ } |
@@ -23,3 +23,3 @@ import { Fragment, Node as ProseMirrorNode, ParseOptions } from '@tiptap/pm/model' | ||
*/ | ||
value: Content, | ||
value: Content | ProseMirrorNode | Fragment, | ||
@@ -136,2 +136,12 @@ /** | ||
newContent = value.map(v => v.text || '').join('') | ||
} else if (value instanceof Fragment) { | ||
let text = '' | ||
value.forEach(node => { | ||
if (node.text) { | ||
text += node.text | ||
} | ||
}) | ||
newContent = text | ||
} else if (typeof value === 'object' && !!value && !!value.text) { | ||
@@ -138,0 +148,0 @@ newContent = value.text |
@@ -1,2 +0,2 @@ | ||
import { ParseOptions } from '@tiptap/pm/model' | ||
import { Fragment, Node as ProseMirrorNode, ParseOptions } from '@tiptap/pm/model' | ||
@@ -20,3 +20,3 @@ import { createDocument } from '../helpers/createDocument.js' | ||
*/ | ||
content: Content, | ||
content: Content | Fragment | ProseMirrorNode, | ||
@@ -41,6 +41,6 @@ /** | ||
*/ | ||
errorOnInvalidContent?: boolean | ||
}, | ||
) => ReturnType | ||
} | ||
errorOnInvalidContent?: boolean; | ||
} | ||
) => ReturnType; | ||
}; | ||
} | ||
@@ -71,10 +71,6 @@ } | ||
return commands.insertContentAt( | ||
{ from: 0, to: doc.content.size }, | ||
content, | ||
{ | ||
parseOptions, | ||
errorOnInvalidContent: options.errorOnInvalidContent ?? editor.options.enableContentCheck, | ||
}, | ||
) | ||
return commands.insertContentAt({ from: 0, to: doc.content.size }, content, { | ||
parseOptions, | ||
errorOnInvalidContent: options.errorOnInvalidContent ?? editor.options.enableContentCheck, | ||
}) | ||
} |
@@ -24,2 +24,9 @@ import { setBlockType } from '@tiptap/pm/commands' | ||
let attributesToCopy: Record<string, any> | undefined | ||
if (state.selection.$anchor.sameParent(state.selection.$head)) { | ||
// only copy attributes if the selection is pointing to a node of the same type | ||
attributesToCopy = state.selection.$anchor.parent.attrs | ||
} | ||
// TODO: use a fallback like insertContent? | ||
@@ -36,3 +43,3 @@ if (!type.isTextblock) { | ||
.command(({ commands }) => { | ||
const canSetBlock = setBlockType(type, attributes)(state) | ||
const canSetBlock = setBlockType(type, { ...attributesToCopy, ...attributes })(state) | ||
@@ -46,3 +53,3 @@ if (canSetBlock) { | ||
.command(({ state: updatedState }) => { | ||
return setBlockType(type, attributes)(updatedState, dispatch) | ||
return setBlockType(type, { ...attributesToCopy, ...attributes })(updatedState, dispatch) | ||
}) | ||
@@ -49,0 +56,0 @@ .run() |
@@ -1,2 +0,5 @@ | ||
import { MarkType, NodeType } from '@tiptap/pm/model' | ||
import { | ||
Mark, MarkType, Node, NodeType, | ||
} from '@tiptap/pm/model' | ||
import { SelectionRange } from '@tiptap/pm/state' | ||
@@ -33,2 +36,3 @@ import { getMarkType } from '../helpers/getMarkType.js' | ||
export const updateAttributes: RawCommands['updateAttributes'] = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => { | ||
let nodeType: NodeType | null = null | ||
@@ -55,10 +59,68 @@ let markType: MarkType | null = null | ||
if (dispatch) { | ||
tr.selection.ranges.forEach(range => { | ||
tr.selection.ranges.forEach((range: SelectionRange) => { | ||
const from = range.$from.pos | ||
const to = range.$to.pos | ||
state.doc.nodesBetween(from, to, (node, pos) => { | ||
if (nodeType && nodeType === node.type) { | ||
tr.setNodeMarkup(pos, undefined, { | ||
...node.attrs, | ||
let lastPos: number | undefined | ||
let lastNode: Node | undefined | ||
let trimmedFrom: number | ||
let trimmedTo: number | ||
if (tr.selection.empty) { | ||
state.doc.nodesBetween(from, to, (node: Node, pos: number) => { | ||
if (nodeType && nodeType === node.type) { | ||
trimmedFrom = Math.max(pos, from) | ||
trimmedTo = Math.min(pos + node.nodeSize, to) | ||
lastPos = pos | ||
lastNode = node | ||
} | ||
}) | ||
} else { | ||
state.doc.nodesBetween(from, to, (node: Node, pos: number) => { | ||
if (pos < from && nodeType && nodeType === node.type) { | ||
trimmedFrom = Math.max(pos, from) | ||
trimmedTo = Math.min(pos + node.nodeSize, to) | ||
lastPos = pos | ||
lastNode = node | ||
} | ||
if (pos >= from && pos <= to) { | ||
if (nodeType && nodeType === node.type) { | ||
tr.setNodeMarkup(pos, undefined, { | ||
...node.attrs, | ||
...attributes, | ||
}) | ||
} | ||
if (markType && node.marks.length) { | ||
node.marks.forEach((mark: Mark) => { | ||
if (markType === mark.type) { | ||
const trimmedFrom2 = Math.max(pos, from) | ||
const trimmedTo2 = Math.min(pos + node.nodeSize, to) | ||
tr.addMark( | ||
trimmedFrom2, | ||
trimmedTo2, | ||
markType.create({ | ||
...mark.attrs, | ||
...attributes, | ||
}), | ||
) | ||
} | ||
}) | ||
} | ||
} | ||
}) | ||
} | ||
if (lastNode) { | ||
if (lastPos !== undefined) { | ||
tr.setNodeMarkup(lastPos, undefined, { | ||
...lastNode.attrs, | ||
...attributes, | ||
@@ -68,8 +130,6 @@ }) | ||
if (markType && node.marks.length) { | ||
node.marks.forEach(mark => { | ||
if (markType && lastNode.marks.length) { | ||
lastNode.marks.forEach((mark: Mark) => { | ||
if (markType === mark.type) { | ||
const trimmedFrom = Math.max(pos, from) | ||
const trimmedTo = Math.min(pos + node.nodeSize, to) | ||
tr.addMark( | ||
@@ -86,3 +146,3 @@ trimmedFrom, | ||
} | ||
}) | ||
} | ||
}) | ||
@@ -89,0 +149,0 @@ } |
@@ -363,2 +363,7 @@ import { | ||
...this.options.editorProps, | ||
attributes: { | ||
// add `role="textbox"` to the editor element | ||
role: 'textbox', | ||
...this.options.editorProps?.attributes, | ||
}, | ||
dispatchTransaction: this.dispatchTransaction.bind(this), | ||
@@ -371,10 +376,2 @@ state: EditorState.create({ | ||
// add `role="textbox"` to the editor element | ||
this.view.dom.setAttribute('role', 'textbox') | ||
// add aria-label to the editor element | ||
if (!this.view.dom.getAttribute('aria-label')) { | ||
this.view.dom.setAttribute('aria-label', 'Rich-Text Editor') | ||
} | ||
// `editor.view` is not yet available at this time. | ||
@@ -381,0 +378,0 @@ // Therefore we will add all plugins and node views directly afterwards. |
@@ -49,2 +49,11 @@ type StringKeyOf<T> = Extract<keyof T, string> | ||
public once<EventName extends StringKeyOf<T>>(event: EventName, fn: CallbackFunction<T, EventName>): this { | ||
const onceFn = (...args: CallbackType<T, EventName>) => { | ||
this.off(event, onceFn) | ||
fn.apply(this, args) | ||
} | ||
return this.on(event, onceFn) | ||
} | ||
public removeAllListeners(): void { | ||
@@ -51,0 +60,0 @@ this.callbacks = {} |
@@ -64,3 +64,3 @@ import { Plugin, Transaction } from '@tiptap/pm/state' | ||
name: string | ||
parent: Exclude<ParentConfig<ExtensionConfig<Options, Storage>>['addOptions'], undefined> | ||
parent: ParentConfig<ExtensionConfig<Options, Storage>>['addOptions'] | ||
}) => Options | ||
@@ -80,3 +80,3 @@ | ||
options: Options | ||
parent: Exclude<ParentConfig<ExtensionConfig<Options, Storage>>['addStorage'], undefined> | ||
parent: ParentConfig<ExtensionConfig<Options, Storage>>['addStorage'] | ||
}) => Storage | ||
@@ -83,0 +83,0 @@ |
@@ -1,2 +0,4 @@ | ||
import { Node as ProseMirrorNode, ParseOptions, Schema } from '@tiptap/pm/model' | ||
import { | ||
Fragment, Node as ProseMirrorNode, ParseOptions, Schema, | ||
} from '@tiptap/pm/model' | ||
@@ -14,3 +16,3 @@ import { Content } from '../types.js' | ||
export function createDocument( | ||
content: Content, | ||
content: Content | ProseMirrorNode | Fragment, | ||
schema: Schema, | ||
@@ -17,0 +19,0 @@ parseOptions: ParseOptions = {}, |
@@ -26,6 +26,9 @@ import { | ||
export function createNodeFromContent( | ||
content: Content, | ||
content: Content | ProseMirrorNode | Fragment, | ||
schema: Schema, | ||
options?: CreateNodeFromContentOptions, | ||
): ProseMirrorNode | Fragment { | ||
if (content instanceof ProseMirrorNode || content instanceof Fragment) { | ||
return content | ||
} | ||
options = { | ||
@@ -32,0 +35,0 @@ slice: true, |
@@ -12,3 +12,10 @@ import { Mark as ProseMirrorMark, MarkType, ResolvedPos } from '@tiptap/pm/model' | ||
return marks.find(item => { | ||
return item.type === type && objectIncludes(item.attrs, attributes) | ||
return ( | ||
item.type === type | ||
&& objectIncludes( | ||
// Only check equality for the attributes that are provided | ||
Object.fromEntries(Object.keys(attributes).map(k => [k, item.attrs[k]])), | ||
attributes, | ||
) | ||
) | ||
}) | ||
@@ -25,6 +32,19 @@ } | ||
/** | ||
* Get the range of a mark at a resolved position. | ||
*/ | ||
export function getMarkRange( | ||
/** | ||
* The position to get the mark range for. | ||
*/ | ||
$pos: ResolvedPos, | ||
/** | ||
* The mark type to get the range for. | ||
*/ | ||
type: MarkType, | ||
attributes: Record<string, any> = {}, | ||
/** | ||
* The attributes to match against. | ||
* If not provided, only the first mark at the position will be matched. | ||
*/ | ||
attributes?: Record<string, any>, | ||
): Range | void { | ||
@@ -46,2 +66,5 @@ if (!$pos || !type) { | ||
// Default to only matching against the first mark's attributes | ||
attributes = attributes || start.node.marks[0]?.attrs | ||
// We now know that the cursor is either at the start, middle or end of a text node with the specified mark | ||
@@ -60,5 +83,6 @@ // so we can look it up on the targeted mark | ||
findMarkInSet([...start.node.marks], type, attributes) | ||
while (startIndex > 0 && mark.isInSet($pos.parent.child(startIndex - 1).marks)) { | ||
while ( | ||
startIndex > 0 | ||
&& isMarkInSet([...$pos.parent.child(startIndex - 1).marks], type, attributes) | ||
) { | ||
startIndex -= 1 | ||
@@ -65,0 +89,0 @@ startPos -= $pos.parent.child(startIndex).nodeSize |
@@ -81,2 +81,3 @@ import { | ||
whitespace: callOrReturn(getExtensionField<NodeConfig['whitespace']>(extension, 'whitespace', context)), | ||
linebreakReplacement: callOrReturn(getExtensionField<NodeConfig['linebreakReplacement']>(extension, 'linebreakReplacement', context)), | ||
defining: callOrReturn( | ||
@@ -83,0 +84,0 @@ getExtensionField<NodeConfig['defining']>(extension, 'defining', context), |
@@ -0,1 +1,2 @@ | ||
import { Fragment, Node as ProseMirrorNode } from '@tiptap/pm/model' | ||
import { EditorState, Plugin, TextSelection } from '@tiptap/pm/state' | ||
@@ -6,2 +7,3 @@ | ||
import { createChainableState } from './helpers/createChainableState.js' | ||
import { getHTMLFromFragment } from './helpers/getHTMLFromFragment.js' | ||
import { getTextContentFromNodes } from './helpers/getTextContentFromNodes.js' | ||
@@ -18,10 +20,10 @@ import { | ||
export type InputRuleMatch = { | ||
index: number | ||
text: string | ||
replaceWith?: string | ||
match?: RegExpMatchArray | ||
data?: Record<string, any> | ||
} | ||
index: number; | ||
text: string; | ||
replaceWith?: string; | ||
match?: RegExpMatchArray; | ||
data?: Record<string, any>; | ||
}; | ||
export type InputRuleFinder = RegExp | ((text: string) => InputRuleMatch | null) | ||
export type InputRuleFinder = RegExp | ((text: string) => InputRuleMatch | null); | ||
@@ -32,20 +34,20 @@ export class InputRule { | ||
handler: (props: { | ||
state: EditorState | ||
range: Range | ||
match: ExtendedRegExpMatchArray | ||
commands: SingleCommands | ||
chain: () => ChainedCommands | ||
can: () => CanCommands | ||
state: EditorState; | ||
range: Range; | ||
match: ExtendedRegExpMatchArray; | ||
commands: SingleCommands; | ||
chain: () => ChainedCommands; | ||
can: () => CanCommands; | ||
}) => void | null | ||
constructor(config: { | ||
find: InputRuleFinder | ||
find: InputRuleFinder; | ||
handler: (props: { | ||
state: EditorState | ||
range: Range | ||
match: ExtendedRegExpMatchArray | ||
commands: SingleCommands | ||
chain: () => ChainedCommands | ||
can: () => CanCommands | ||
}) => void | null | ||
state: EditorState; | ||
range: Range; | ||
match: ExtendedRegExpMatchArray; | ||
commands: SingleCommands; | ||
chain: () => ChainedCommands; | ||
can: () => CanCommands; | ||
}) => void | null; | ||
}) { | ||
@@ -91,8 +93,8 @@ this.find = config.find | ||
function run(config: { | ||
editor: Editor | ||
from: number | ||
to: number | ||
text: string | ||
rules: InputRule[] | ||
plugin: Plugin | ||
editor: Editor; | ||
from: number; | ||
to: number; | ||
text: string; | ||
rules: InputRule[]; | ||
plugin: Plugin; | ||
}): boolean { | ||
@@ -191,3 +193,3 @@ const { | ||
}, | ||
apply(tr, prev) { | ||
apply(tr, prev, state) { | ||
const stored = tr.getMeta(plugin) | ||
@@ -200,3 +202,8 @@ | ||
// if InputRule is triggered by insertContent() | ||
const simulatedInputMeta = tr.getMeta('applyInputRules') | ||
const simulatedInputMeta = tr.getMeta('applyInputRules') as | ||
| undefined | ||
| { | ||
from: number; | ||
text: string | ProseMirrorNode | Fragment; | ||
} | ||
const isSimulatedInput = !!simulatedInputMeta | ||
@@ -206,3 +213,11 @@ | ||
setTimeout(() => { | ||
const { from, text } = simulatedInputMeta | ||
let { text } = simulatedInputMeta | ||
if (typeof text === 'string') { | ||
text = text as string | ||
} else { | ||
text = getHTMLFromFragment(Fragment.from(text), state.schema) | ||
} | ||
const { from } = simulatedInputMeta | ||
const to = from + text.length | ||
@@ -209,0 +224,0 @@ |
@@ -11,3 +11,3 @@ import { MarkType } from '@tiptap/pm/model' | ||
* matched text is typed into it. | ||
* @see https://tiptap.dev/guide/custom-extensions/#input-rules | ||
* @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#input-rules | ||
*/ | ||
@@ -14,0 +14,0 @@ export function markInputRule(config: { |
@@ -10,3 +10,3 @@ import { NodeType } from '@tiptap/pm/model' | ||
* matched text is typed into it. | ||
* @see https://tiptap.dev/guide/custom-extensions/#input-rules | ||
* @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#input-rules | ||
*/ | ||
@@ -13,0 +13,0 @@ export function nodeInputRule(config: { |
@@ -12,3 +12,3 @@ import { NodeType } from '@tiptap/pm/model' | ||
* only occur at the start of a textblock. | ||
* @see https://tiptap.dev/guide/custom-extensions/#input-rules | ||
* @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#input-rules | ||
*/ | ||
@@ -15,0 +15,0 @@ export function textblockTypeInputRule(config: { |
@@ -6,3 +6,3 @@ import { InputRule, InputRuleFinder } from '../InputRule.js' | ||
* matched text is typed into it. | ||
* @see https://tiptap.dev/guide/custom-extensions/#input-rules | ||
* @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#input-rules | ||
*/ | ||
@@ -9,0 +9,0 @@ export function textInputRule(config: { |
@@ -22,3 +22,3 @@ import { Node as ProseMirrorNode, NodeType } from '@tiptap/pm/model' | ||
* return a boolean to indicate whether a join should happen. | ||
* @see https://tiptap.dev/guide/custom-extensions/#input-rules | ||
* @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#input-rules | ||
*/ | ||
@@ -25,0 +25,0 @@ export function wrappingInputRule(config: { |
@@ -67,3 +67,3 @@ import { | ||
name: string | ||
parent: Exclude<ParentConfig<MarkConfig<Options, Storage>>['addOptions'], undefined> | ||
parent: ParentConfig<MarkConfig<Options, Storage>>['addOptions'] | ||
}) => Options | ||
@@ -83,3 +83,3 @@ | ||
options: Options | ||
parent: Exclude<ParentConfig<MarkConfig<Options, Storage>>['addStorage'], undefined> | ||
parent: ParentConfig<MarkConfig<Options, Storage>>['addStorage'] | ||
}) => Storage | ||
@@ -86,0 +86,0 @@ |
@@ -68,3 +68,3 @@ import { | ||
name: string | ||
parent: Exclude<ParentConfig<NodeConfig<Options, Storage>>['addOptions'], undefined> | ||
parent: ParentConfig<NodeConfig<Options, Storage>>['addOptions'] | ||
}) => Options | ||
@@ -84,3 +84,3 @@ | ||
options: Options | ||
parent: Exclude<ParentConfig<NodeConfig<Options, Storage>>['addStorage'], undefined> | ||
parent: ParentConfig<NodeConfig<Options, Storage>>['addStorage'] | ||
}) => Storage | ||
@@ -601,2 +601,21 @@ | ||
/** | ||
* Allows a **single** node to be set as linebreak equivalent (e.g. hardBreak). | ||
* When converting between block types that have whitespace set to "pre" | ||
* and don't support the linebreak node (e.g. codeBlock) and other block types | ||
* that do support the linebreak node (e.g. paragraphs) - this node will be used | ||
* as the linebreak instead of stripping the newline. | ||
* | ||
* See [linebreakReplacement](https://prosemirror.net/docs/ref/#model.NodeSpec.linebreakReplacement). | ||
*/ | ||
linebreakReplacement?: | ||
| NodeSpec['linebreakReplacement'] | ||
| ((this: { | ||
name: string | ||
options: Options | ||
storage: Storage | ||
parent: ParentConfig<NodeConfig<Options, Storage>>['linebreakReplacement'] | ||
editor?: Editor | ||
}) => NodeSpec['linebreakReplacement']) | ||
/** | ||
* When enabled, enables both | ||
@@ -603,0 +622,0 @@ * [`definingAsContext`](https://prosemirror.net/docs/ref/#model.NodeSpec.definingAsContext) and |
@@ -0,1 +1,2 @@ | ||
import { Fragment, Node as ProseMirrorNode } from '@tiptap/pm/model' | ||
import { EditorState, Plugin } from '@tiptap/pm/state' | ||
@@ -6,2 +7,3 @@ | ||
import { createChainableState } from './helpers/createChainableState.js' | ||
import { getHTMLFromFragment } from './helpers/getHTMLFromFragment.js' | ||
import { | ||
@@ -18,14 +20,16 @@ CanCommands, | ||
export type PasteRuleMatch = { | ||
index: number | ||
text: string | ||
replaceWith?: string | ||
match?: RegExpMatchArray | ||
data?: Record<string, any> | ||
} | ||
index: number; | ||
text: string; | ||
replaceWith?: string; | ||
match?: RegExpMatchArray; | ||
data?: Record<string, any>; | ||
}; | ||
export type PasteRuleFinder = RegExp | ((text: string, event?: ClipboardEvent | null) => PasteRuleMatch[] | null | undefined) | ||
export type PasteRuleFinder = | ||
| RegExp | ||
| ((text: string, event?: ClipboardEvent | null) => PasteRuleMatch[] | null | undefined); | ||
/** | ||
* Paste rules are used to react to pasted content. | ||
* @see https://tiptap.dev/guide/custom-extensions/#paste-rules | ||
* @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#paste-rules | ||
*/ | ||
@@ -36,24 +40,24 @@ export class PasteRule { | ||
handler: (props: { | ||
state: EditorState | ||
range: Range | ||
match: ExtendedRegExpMatchArray | ||
commands: SingleCommands | ||
chain: () => ChainedCommands | ||
can: () => CanCommands | ||
pasteEvent: ClipboardEvent | null | ||
dropEvent: DragEvent | null | ||
state: EditorState; | ||
range: Range; | ||
match: ExtendedRegExpMatchArray; | ||
commands: SingleCommands; | ||
chain: () => ChainedCommands; | ||
can: () => CanCommands; | ||
pasteEvent: ClipboardEvent | null; | ||
dropEvent: DragEvent | null; | ||
}) => void | null | ||
constructor(config: { | ||
find: PasteRuleFinder | ||
find: PasteRuleFinder; | ||
handler: (props: { | ||
can: () => CanCommands | ||
chain: () => ChainedCommands | ||
commands: SingleCommands | ||
dropEvent: DragEvent | null | ||
match: ExtendedRegExpMatchArray | ||
pasteEvent: ClipboardEvent | null | ||
range: Range | ||
state: EditorState | ||
}) => void | null | ||
can: () => CanCommands; | ||
chain: () => ChainedCommands; | ||
commands: SingleCommands; | ||
dropEvent: DragEvent | null; | ||
match: ExtendedRegExpMatchArray; | ||
pasteEvent: ClipboardEvent | null; | ||
range: Range; | ||
state: EditorState; | ||
}) => void | null; | ||
}) { | ||
@@ -102,9 +106,9 @@ this.find = config.find | ||
function run(config: { | ||
editor: Editor | ||
state: EditorState | ||
from: number | ||
to: number | ||
rule: PasteRule | ||
pasteEvent: ClipboardEvent | null | ||
dropEvent: DragEvent | null | ||
editor: Editor; | ||
state: EditorState; | ||
from: number; | ||
to: number; | ||
rule: PasteRule; | ||
pasteEvent: ClipboardEvent | null; | ||
dropEvent: DragEvent | null; | ||
}): boolean { | ||
@@ -186,4 +190,10 @@ const { | ||
let pasteEvent = typeof ClipboardEvent !== 'undefined' ? new ClipboardEvent('paste') : null | ||
let dropEvent = typeof DragEvent !== 'undefined' ? new DragEvent('drop') : null | ||
let dropEvent: DragEvent | null | ||
try { | ||
dropEvent = typeof DragEvent !== 'undefined' ? new DragEvent('drop') : null | ||
} catch (e) { | ||
dropEvent = null | ||
} | ||
const processEvent = ({ | ||
@@ -196,7 +206,7 @@ state, | ||
}: { | ||
state: EditorState | ||
from: number | ||
to: { b: number } | ||
rule: PasteRule | ||
pasteEvt: ClipboardEvent | null | ||
state: EditorState; | ||
from: number; | ||
to: { b: number }; | ||
rule: PasteRule; | ||
pasteEvt: ClipboardEvent | null; | ||
}) => { | ||
@@ -223,3 +233,7 @@ const tr = state.tr | ||
dropEvent = typeof DragEvent !== 'undefined' ? new DragEvent('drop') : null | ||
try { | ||
dropEvent = typeof DragEvent !== 'undefined' ? new DragEvent('drop') : null | ||
} catch (e) { | ||
dropEvent = null | ||
} | ||
pasteEvent = typeof ClipboardEvent !== 'undefined' ? new ClipboardEvent('paste') : null | ||
@@ -276,3 +290,5 @@ | ||
// if PasteRule is triggered by insertContent() | ||
const simulatedPasteMeta = transaction.getMeta('applyPasteRules') | ||
const simulatedPasteMeta = transaction.getMeta('applyPasteRules') as | ||
| undefined | ||
| { from: number; text: string | ProseMirrorNode | Fragment } | ||
const isSimulatedPaste = !!simulatedPasteMeta | ||
@@ -286,4 +302,13 @@ | ||
if (isSimulatedPaste) { | ||
const { from, text } = simulatedPasteMeta | ||
let { text } = simulatedPasteMeta | ||
if (typeof text === 'string') { | ||
text = text as string | ||
} else { | ||
text = getHTMLFromFragment(Fragment.from(text), state.schema) | ||
} | ||
const { from } = simulatedPasteMeta | ||
const to = from + text.length | ||
const pasteEvt = createClipboardPasteEvent(text) | ||
@@ -290,0 +315,0 @@ |
@@ -11,3 +11,3 @@ import { MarkType } from '@tiptap/pm/model' | ||
* matched text is pasted into it. | ||
* @see https://tiptap.dev/guide/custom-extensions/#paste-rules | ||
* @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#paste-rules | ||
*/ | ||
@@ -14,0 +14,0 @@ export function markPasteRule(config: { |
@@ -10,3 +10,3 @@ import { NodeType } from '@tiptap/pm/model' | ||
* matched text is pasted into it. | ||
* @see https://tiptap.dev/guide/custom-extensions/#paste-rules | ||
* @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#paste-rules | ||
*/ | ||
@@ -13,0 +13,0 @@ export function nodePasteRule(config: { |
@@ -6,3 +6,3 @@ import { PasteRule, PasteRuleFinder } from '../PasteRule.js' | ||
* matched text is pasted into it. | ||
* @see https://tiptap.dev/guide/custom-extensions/#paste-rules | ||
* @see https://tiptap.dev/docs/editor/extensions/custom-extensions/extend-existing#paste-rules | ||
*/ | ||
@@ -9,0 +9,0 @@ export function textPasteRule(config: { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2501608
28625