diff --git a/docs/src/components/Demo/index.vue b/docs/src/components/Demo/index.vue index 4377655b3..9c192d85e 100644 --- a/docs/src/components/Demo/index.vue +++ b/docs/src/components/Demo/index.vue @@ -1,41 +1,40 @@ - - diff --git a/docs/src/demos/Experiments/CollaborationAnnotation/extension/AnnotationItem.ts b/docs/src/demos/Experiments/CollaborationAnnotation/extension/AnnotationItem.ts new file mode 100644 index 000000000..dfcc92cd1 --- /dev/null +++ b/docs/src/demos/Experiments/CollaborationAnnotation/extension/AnnotationItem.ts @@ -0,0 +1,37 @@ +export class AnnotationItem { + private decoration!: any + + constructor(decoration: any) { + this.decoration = decoration + } + + get id() { + return this.decoration.type.spec.id + } + + get from() { + return this.decoration.from + } + + get to() { + return this.decoration.to + } + + get data() { + return this.decoration.type.spec.data + } + + get HTMLAttributes() { + return this.decoration.type.attrs + } + + toString() { + return JSON.stringify({ + id: this.id, + data: this.data, + from: this.from, + to: this.to, + HTMLAttributes: this.HTMLAttributes, + }) + } +} diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts b/docs/src/demos/Experiments/CollaborationAnnotation/extension/AnnotationPlugin.ts similarity index 50% rename from docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts rename to docs/src/demos/Experiments/CollaborationAnnotation/extension/AnnotationPlugin.ts index 7542bc591..14ac17e36 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts +++ b/docs/src/demos/Experiments/CollaborationAnnotation/extension/AnnotationPlugin.ts @@ -1,16 +1,34 @@ +import * as Y from 'yjs' import { Plugin, PluginKey } from 'prosemirror-state' import { AnnotationState } from './AnnotationState' export const AnnotationPluginKey = new PluginKey('annotation') -export const AnnotationPlugin = (options: any) => new Plugin({ +export interface AnnotationPluginOptions { + HTMLAttributes: { + [key: string]: any + }, + onUpdate: (items: [any?]) => {}, + map: Y.Map, + instance: string, +} + +export const AnnotationPlugin = (options: AnnotationPluginOptions) => new Plugin({ key: AnnotationPluginKey, + state: { - init: AnnotationState.init, - apply(transaction, oldState) { - return oldState.apply(transaction) + init() { + return new AnnotationState({ + HTMLAttributes: options.HTMLAttributes, + map: options.map, + instance: options.instance, + }) + }, + apply(transaction, pluginState, oldState, newState) { + return pluginState.apply(transaction, newState) }, }, + props: { decorations(state) { const { decorations } = this.getState(state) @@ -28,6 +46,5 @@ export const AnnotationPlugin = (options: any) => new Plugin({ return decorations }, - }, }) diff --git a/docs/src/demos/Experiments/CollaborationAnnotation/extension/AnnotationState.ts b/docs/src/demos/Experiments/CollaborationAnnotation/extension/AnnotationState.ts new file mode 100644 index 000000000..016254808 --- /dev/null +++ b/docs/src/demos/Experiments/CollaborationAnnotation/extension/AnnotationState.ts @@ -0,0 +1,151 @@ +import * as Y from 'yjs' +import { EditorState, Transaction } from 'prosemirror-state' +import { Decoration, DecorationSet } from 'prosemirror-view' +import { ySyncPluginKey, relativePositionToAbsolutePosition, absolutePositionToRelativePosition } from 'y-prosemirror' +import { AddAnnotationAction, DeleteAnnotationAction, UpdateAnnotationAction } from './collaboration-annotation' +import { AnnotationPluginKey } from './AnnotationPlugin' +import { AnnotationItem } from './AnnotationItem' + +export interface AnnotationStateOptions { + HTMLAttributes: { + [key: string]: any + }, + map: Y.Map, + instance: string, +} + +export class AnnotationState { + options: AnnotationStateOptions + + decorations = DecorationSet.empty + + constructor(options: AnnotationStateOptions) { + this.options = options + } + + randomId() { + // TODO: That seems … to simple. + return Math.floor(Math.random() * 0xffffffff).toString() + } + + findAnnotation(id: string) { + const current = this.decorations.find() + + for (let i = 0; i < current.length; i += 1) { + if (current[i].spec.id === id) { + return current[i] + } + } + } + + addAnnotation(action: AddAnnotationAction, state: EditorState) { + const ystate = ySyncPluginKey.getState(state) + const { type, binding } = ystate + const { map } = this.options + const { from, to, data } = action + const absoluteFrom = absolutePositionToRelativePosition(from, type, binding.mapping) + const absoluteTo = absolutePositionToRelativePosition(to, type, binding.mapping) + + map.set(this.randomId(), { + from: absoluteFrom, + to: absoluteTo, + data, + }) + } + + updateAnnotation(action: UpdateAnnotationAction) { + const { map } = this.options + + const annotation = map.get(action.id) + + map.set(action.id, { + from: annotation.from, + to: annotation.to, + data: action.data, + }) + } + + deleteAnnotation(id: string) { + const { map } = this.options + + map.delete(id) + } + + annotationsAt(position: number) { + return this.decorations.find(position, position).map(decoration => { + return new AnnotationItem(decoration) + }) + } + + createDecorations(state: EditorState) { + const { map, HTMLAttributes } = this.options + const ystate = ySyncPluginKey.getState(state) + const { doc, type, binding } = ystate + const decorations: Decoration[] = [] + + map.forEach((annotation, id) => { + const from = relativePositionToAbsolutePosition(doc, type, annotation.from, binding.mapping) + const to = relativePositionToAbsolutePosition(doc, type, annotation.to, binding.mapping) + + if (!from || !to) { + return + } + + console.log(`[${this.options.instance}] Decoration.inline()`, from, to, HTMLAttributes, { id, data: annotation.data }) + + if (from === to) { + console.warn(`[${this.options.instance}] corrupt decoration `, annotation.from, from, annotation.to, to) + } + + decorations.push( + Decoration.inline(from, to, HTMLAttributes, { id, data: annotation.data, inclusiveEnd: true }), + ) + }) + + this.decorations = DecorationSet.create(state.doc, decorations) + } + + apply(transaction: Transaction, state: EditorState) { + // Add/Remove annotations + const action = transaction.getMeta(AnnotationPluginKey) as AddAnnotationAction | UpdateAnnotationAction | DeleteAnnotationAction + + if (action && action.type) { + console.log(`[${this.options.instance}] action: ${action.type}`) + + if (action.type === 'addAnnotation') { + this.addAnnotation(action, state) + } + + if (action.type === 'updateAnnotation') { + this.updateAnnotation(action) + } + + if (action.type === 'deleteAnnotation') { + this.deleteAnnotation(action.id) + } + + // @ts-ignore + if (action.type === 'createDecorations') { + this.createDecorations(state) + } + + return this + } + + // Use Y.js to update positions + const ystate = ySyncPluginKey.getState(state) + + if (ystate.isChangeOrigin) { + console.log(`[${this.options.instance}] isChangeOrigin: true → createDecorations`) + this.createDecorations(state) + + return this + } + + // Use ProseMirror to update positions + console.log(`[${this.options.instance}] isChangeOrigin: false → ProseMirror mapping`) + this.decorations = this.decorations.map(transaction.mapping, transaction.doc) + + return this + } +} diff --git a/docs/src/demos/Experiments/CollaborationAnnotation/extension/collaboration-annotation.ts b/docs/src/demos/Experiments/CollaborationAnnotation/extension/collaboration-annotation.ts new file mode 100644 index 000000000..e2bd1335e --- /dev/null +++ b/docs/src/demos/Experiments/CollaborationAnnotation/extension/collaboration-annotation.ts @@ -0,0 +1,144 @@ +import * as Y from 'yjs' +import { Extension, Command } from '@tiptap/core' +import { AnnotationPlugin, AnnotationPluginKey } from './AnnotationPlugin' + +export interface AddAnnotationAction { + type: 'addAnnotation', + data: any, + from: number, + to: number, +} + +export interface UpdateAnnotationAction { + type: 'updateAnnotation', + id: string, + data: any, +} + +export interface DeleteAnnotationAction { + type: 'deleteAnnotation', + id: string, +} + +export interface AnnotationOptions { + HTMLAttributes: { + [key: string]: any + }, + /** + * An event listener which receives annotations for the current selection. + */ + onUpdate: (items: [any?]) => {}, + /** + * An initialized Y.js document. + */ + document: Y.Doc | null, + /** + * Name of a Y.js map, can be changed to sync multiple fields with one Y.js document. + */ + field: string, + /** + * A raw Y.js map, can be used instead of `document` and `field`. + */ + map: Y.Map | null, + instance: string, +} + +function getMapFromOptions(options: AnnotationOptions): Y.Map { + return options.map + ? options.map + : options.document?.getMap(options.field) as Y.Map +} + +declare module '@tiptap/core' { + interface AllCommands { + annotation: { + addAnnotation: (data: any) => Command, + updateAnnotation: (id: string, data: any) => Command, + deleteAnnotation: (id: string) => Command, + } + } +} + +export const CollaborationAnnotation = Extension.create({ + name: 'annotation', + + defaultOptions: { + HTMLAttributes: { + class: 'annotation', + }, + onUpdate: decorations => decorations, + document: null, + field: 'annotations', + map: null, + instance: '', + }, + + onCreate() { + const map = getMapFromOptions(this.options) + + map.observe(() => { + console.log(`[${this.options.instance}] map updated → createDecorations`) + + const transaction = this.editor.state.tr.setMeta(AnnotationPluginKey, { + type: 'createDecorations', + }) + + this.editor.view.dispatch(transaction) + }) + }, + + addCommands() { + return { + addAnnotation: (data: any) => ({ dispatch, state }) => { + const { selection } = state + + if (selection.empty) { + return false + } + + if (dispatch && data) { + state.tr.setMeta(AnnotationPluginKey, { + type: 'addAnnotation', + from: selection.from, + to: selection.to, + data, + }) + } + + return true + }, + updateAnnotation: (id: string, data: any) => ({ dispatch, state }) => { + if (dispatch) { + state.tr.setMeta(AnnotationPluginKey, { + type: 'updateAnnotation', + id, + data, + }) + } + + return true + }, + deleteAnnotation: id => ({ dispatch, state }) => { + if (dispatch) { + state.tr.setMeta(AnnotationPluginKey, { + type: 'deleteAnnotation', + id, + }) + } + + return true + }, + } + }, + + addProseMirrorPlugins() { + return [ + AnnotationPlugin({ + HTMLAttributes: this.options.HTMLAttributes, + onUpdate: this.options.onUpdate, + map: getMapFromOptions(this.options), + instance: this.options.instance, + }), + ] + }, +}) diff --git a/docs/src/demos/Experiments/CollaborationAnnotation/extension/index.ts b/docs/src/demos/Experiments/CollaborationAnnotation/extension/index.ts new file mode 100644 index 000000000..b64dc6ea5 --- /dev/null +++ b/docs/src/demos/Experiments/CollaborationAnnotation/extension/index.ts @@ -0,0 +1,5 @@ +import { CollaborationAnnotation } from './collaboration-annotation' + +export * from './collaboration-annotation' + +export default CollaborationAnnotation diff --git a/docs/src/demos/Experiments/CollaborationAnnotation/index.spec.js b/docs/src/demos/Experiments/CollaborationAnnotation/index.spec.js new file mode 100644 index 000000000..f1b0a3aed --- /dev/null +++ b/docs/src/demos/Experiments/CollaborationAnnotation/index.spec.js @@ -0,0 +1,7 @@ +context('/demos/Experiments/Annotation', () => { + before(() => { + cy.visit('/demos/Experiments/Annotation') + }) + + // TODO: Write tests +}) diff --git a/docs/src/demos/Experiments/Comments/index.vue b/docs/src/demos/Experiments/CollaborationAnnotation/index.vue similarity index 65% rename from docs/src/demos/Experiments/Comments/index.vue rename to docs/src/demos/Experiments/CollaborationAnnotation/index.vue index c2388200d..97e490b56 100644 --- a/docs/src/demos/Experiments/Comments/index.vue +++ b/docs/src/demos/Experiments/CollaborationAnnotation/index.vue @@ -2,36 +2,30 @@

- Original + Original Editor

-
- {{ comment.type.spec.data }} +
+ {{ comment }} - + +
- - -
-

- Y.js document -

- {{ json }} - -
-

- Mirror + Another Editor

+
@@ -46,8 +40,7 @@ import Collaboration from '@tiptap/extension-collaboration' import Bold from '@tiptap/extension-bold' import Heading from '@tiptap/extension-heading' import * as Y from 'yjs' -import { yDocToProsemirrorJSON } from 'y-prosemirror' -import Annotation from '../Annotation/extension' +import CollaborationAnnotation from './extension' export default { components: { @@ -73,8 +66,10 @@ export default { Text, Bold, Heading, - Annotation.configure({ + CollaborationAnnotation.configure({ + document: this.ydoc, onUpdate: items => { this.comments = items }, + instance: 'editor1', }), Collaboration.configure({ document: this.ydoc, @@ -95,9 +90,12 @@ export default { Document, Paragraph, Text, - // Annotation.configure({ - // onUpdate: items => { this.comments = items }, - // }), + Bold, + Heading, + CollaborationAnnotation.configure({ + document: this.ydoc, + instance: 'editor2', + }), Collaboration.configure({ document: this.ydoc, }), @@ -107,26 +105,32 @@ export default { methods: { addComment() { - const content = prompt('Comment', '') + const data = prompt('Comment', '') - this.editor.commands.addAnnotation(content) + this.editor.commands.addAnnotation(data) + }, + updateComment(id) { + const comment = this.comments.find(item => { + return id === item.id + }) + + const data = prompt('Comment', comment.data) + + this.editor.commands.updateAnnotation(id, data) }, deleteComment(id) { this.editor.commands.deleteAnnotation(id) }, - }, + addAnotherComment() { + const data = prompt('Comment', '') - computed: { - rawDocument() { - return yDocToProsemirrorJSON(this.ydoc, 'default') - }, - json() { - return this.ydoc.toJSON() + this.anotherEditor.commands.addAnnotation(data) }, }, beforeDestroy() { this.editor.destroy() + this.anotherEditor.destroy() }, } diff --git a/docs/src/demos/Experiments/Color/extension/Color.ts b/docs/src/demos/Experiments/Color/extension/Color.ts deleted file mode 100644 index 9bf22475b..000000000 --- a/docs/src/demos/Experiments/Color/extension/Color.ts +++ /dev/null @@ -1,62 +0,0 @@ -// @ts-nocheck -import { Extension } from '@tiptap/core' -import { Decoration, DecorationSet } from 'prosemirror-view' -import { Plugin } from 'prosemirror-state' - -function detectColors(doc) { - const hexColor = /(#[0-9a-f]{3,6})\b/ig - const results = [] - const decorations: [any?] = [] - - doc.descendants((node: any, position: any) => { - if (!node.isText) { - return - } - - let matches - - // eslint-disable-next-line - while (matches = hexColor.exec(node.text)) { - results.push({ - color: matches[0], - from: position + matches.index, - to: position + matches.index + matches[0].length, - }) - } - }) - - results.forEach(issue => { - decorations.push(Decoration.inline(issue.from, issue.to, { - class: 'color', - style: `--color: ${issue.color}`, - })) - }) - - return DecorationSet.create(doc, decorations) -} - -export const Color = Extension.create({ - name: 'color', - - addProseMirrorPlugins() { - return [ - new Plugin({ - state: { - init(_, { doc }) { - return detectColors(doc) - }, - apply(transaction, oldState) { - return transaction.docChanged - ? detectColors(transaction.doc) - : oldState - }, - }, - props: { - decorations(state) { - return this.getState(state) - }, - }, - }), - ] - }, -}) diff --git a/docs/src/demos/Experiments/Color/extension/index.ts b/docs/src/demos/Experiments/Color/extension/index.ts deleted file mode 100644 index d73a0a1bf..000000000 --- a/docs/src/demos/Experiments/Color/extension/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Color } from './Color' - -export * from './Color' -export default Color diff --git a/docs/src/demos/Experiments/Color/index.vue b/docs/src/demos/Experiments/Color/index.vue deleted file mode 100644 index a46928315..000000000 --- a/docs/src/demos/Experiments/Color/index.vue +++ /dev/null @@ -1,76 +0,0 @@ - - - - - diff --git a/docs/src/demos/Experiments/Comments/index.spec.js b/docs/src/demos/Experiments/Comments/index.spec.js deleted file mode 100644 index 109134a01..000000000 --- a/docs/src/demos/Experiments/Comments/index.spec.js +++ /dev/null @@ -1,7 +0,0 @@ -context('/demos/Examples/Annotations', () => { - before(() => { - cy.visit('/demos/Examples/Annotations') - }) - - // TODO: Write tests -}) diff --git a/docs/src/demos/Experiments/Details/details-summary.ts b/docs/src/demos/Experiments/Details/details-summary.ts index de0972f69..9b4b403d4 100644 --- a/docs/src/demos/Experiments/Details/details-summary.ts +++ b/docs/src/demos/Experiments/Details/details-summary.ts @@ -9,9 +9,13 @@ export interface DetailsSummaryOptions { export default Node.create({ name: 'detailsSummary', - content: 'inline*', + content: 'text*', - // group: 'block', + marks: '', + + group: 'block', + + isolating: true, defaultOptions: { HTMLAttributes: {}, diff --git a/docs/src/demos/Experiments/Details/details.ts b/docs/src/demos/Experiments/Details/details.ts index 553954bb7..3535b7a17 100644 --- a/docs/src/demos/Experiments/Details/details.ts +++ b/docs/src/demos/Experiments/Details/details.ts @@ -1,4 +1,4 @@ -import { Node, mergeAttributes } from '@tiptap/core' +import { Node, mergeAttributes, Command } from '@tiptap/core' export interface DetailsOptions { HTMLAttributes: { @@ -6,6 +6,25 @@ export interface DetailsOptions { }, } +declare module '@tiptap/core' { + interface AllCommands { + details: { + /** + * Set a details node + */ + setDetails: () => Command, + /** + * Toggle a details node + */ + toggleDetails: () => Command, + /** + * Unset a details node + */ + unsetDetails: () => Command, + } + } +} + export default Node.create({ name: 'details', @@ -13,36 +32,21 @@ export default Node.create({ group: 'block', + // defining: true, + defaultOptions: { HTMLAttributes: {}, }, - addAttributes() { - return { - open: { - default: true, - parseHTML: element => { - return { - open: element.hasAttribute('open'), - } - }, - renderHTML: attributes => { - if (!attributes.open) { - return null - } - - return { - open: 'open', - } - }, - }, - } - }, - parseHTML() { - return [{ - tag: 'details', - }] + return [ + { + tag: 'details', + }, + { + tag: 'div[data-type="details"]', + }, + ] }, renderHTML({ HTMLAttributes }) { @@ -50,54 +54,54 @@ export default Node.create({ }, addNodeView() { - return ({ - node, - HTMLAttributes, - getPos, - editor, - }) => { - const { view } = editor - const item = document.createElement('details') + return ({ HTMLAttributes }) => { + const item = document.createElement('div') + item.setAttribute('data-type', 'details') - item.addEventListener('click', event => { - // @ts-ignore - const { open } = event.target.parentElement as HTMLElement - // @ts-ignore - const { localName } = event.target + const toggle = document.createElement('div') + toggle.setAttribute('data-type', 'detailsToggle') + item.append(toggle) - if (typeof getPos === 'function' && localName === 'summary') { - view.dispatch(view.state.tr.setNodeMarkup(getPos(), undefined, { - open: !open, - })) - editor.commands.focus() + const content = document.createElement('div') + content.setAttribute('data-type', 'detailsContent') + item.append(content) + + toggle.addEventListener('click', () => { + if (item.hasAttribute('open')) { + item.removeAttribute('open') + } else { + item.setAttribute('open', 'open') } }) - if (node.attrs.open) { - item.setAttribute('open', 'open') - } - Object.entries(HTMLAttributes).forEach(([key, value]) => { item.setAttribute(key, value) }) return { dom: item, - contentDOM: item, - update: updatedNode => { - if (updatedNode.type !== this.type) { - return false - } - - if (updatedNode.attrs.open) { - item.setAttribute('open', 'open') - } else { - item.removeAttribute('open') - } - - return true + contentDOM: content, + ignoreMutation: (mutation: MutationRecord) => { + return !item.contains(mutation.target) || item === mutation.target }, } } }, + + addCommands() { + return { + setDetails: () => ({ commands }) => { + // TODO: Doesn’t work + return commands.wrapIn('details') + }, + toggleDetails: () => ({ commands }) => { + // TODO: Doesn’t work + return commands.toggleWrap('details') + }, + unsetDetails: () => ({ commands }) => { + // TODO: Doesn’t work + return commands.lift('details') + }, + } + }, }) diff --git a/docs/src/demos/Experiments/Details/index.vue b/docs/src/demos/Experiments/Details/index.vue index 37044446d..e0f9d4021 100644 --- a/docs/src/demos/Experiments/Details/index.vue +++ b/docs/src/demos/Experiments/Details/index.vue @@ -1,6 +1,20 @@ @@ -31,7 +45,7 @@ export default { ], content: `

Here is a details list:

-
+
An open details tag

More info about the details.

@@ -39,6 +53,7 @@ export default { A closed details tag

More info about the details.

+

That’s it.

`, }) }, @@ -54,5 +69,31 @@ export default { > * + * { margin-top: 0.75em; } + + details, + [data-type="details"] { + display: flex; + + [data-type="detailsContent"] > *:not(summary) { + display: none; + } + + [data-type="detailsToggle"]::before { + cursor: pointer; + content: '▸'; + display: inline-block; + width: 1em; + } + + &[open] { + [data-type="detailsContent"] > *:not(summary) { + display: inherit; + } + + [data-type="detailsToggle"]::before { + content: '▾'; + } + } + } } diff --git a/docs/src/docPages/api/commands.md b/docs/src/docPages/api/commands.md index 5b01d12f7..afbe92a3d 100644 --- a/docs/src/docPages/api/commands.md +++ b/docs/src/docPages/api/commands.md @@ -186,6 +186,29 @@ Have a look at all of the core commands listed below. They should give you a goo | .selectNodeForward() | Select a node forward. | | .selectParentNode() | Select the parent node. | +## Example use cases + +### Quote a text +TODO + +Add a blockquote, with a specified text, add a paragraph below, set the cursor there. + +```js +// Untested, work in progress, likely to change +this.editor + .chain() + .focus() + .createParagraphNear() + .insertText(text) + .setBlockquote() + .insertHTML('

') + .createParagraphNear() + .unsetBlockquote() + .createParagraphNear() + .insertHTML('

') + .run() +``` + ## Add your own commands All extensions can add additional commands (and most do), check out the specific [documentation for the provided nodes](/api/nodes), [marks](/api/marks), and [extensions](/api/extensions) to learn more about those. diff --git a/docs/src/docPages/api/extensions.md b/docs/src/docPages/api/extensions.md index d008ac0ac..61cf3a84c 100644 --- a/docs/src/docPages/api/extensions.md +++ b/docs/src/docPages/api/extensions.md @@ -3,7 +3,9 @@ ## toc ## Introduction -Extensions add new capabilities to tiptap. [Nodes](/api/nodes) and [marks](/api/marks) are rendered in HTML. Extensions can’t add to the schema, but can add functionality or change the behaviour of the editor. +Extensions add new capabilities to tiptap and you’ll read the word extension here very often. Actually, there are literal Extensions. Those can’t add to the schema, but can add functionality or change the behaviour of the editor. + +There are also some extensions with more capabilities. We call them [nodes](/api/nodes) and [marks](/api/marks) which can render content in the editor. ## List of provided extensions | Title | Default Extension | Source Code | @@ -19,7 +21,7 @@ Extensions add new capabilities to tiptap. [Nodes](/api/nodes) and [marks](/api/ | [TextAlign](/api/extensions/text-align) | – | [GitHub](https://github.com/ueberdosis/tiptap-next/blob/main/packages/extension-text-align/) | | [Typography](/api/extensions/typography) | – | [GitHub](https://github.com/ueberdosis/tiptap-next/blob/main/packages/extension-typography/) | -You don’t have to use it, but we prepared a `@tiptap/starter-kit` which includes the most common extensions. See an example on [how to use `defaultExtensions()`](/examples/default). +You don’t have to use it, but we prepared a `@tiptap/starter-kit` which includes the most common extensions. Read more about [`defaultExtensions()`](/guide/configuration#default-extensions). ## How extensions work Although tiptap tries to hide most of the complexity of ProseMirror, it’s built on top of its APIs and we recommend you to read through the [ProseMirror Guide](https://ProseMirror.net/docs/guide/) for advanced usage. You’ll have a better understanding of how everything works under the hood and get more familiar with many terms and jargon used by tiptap. @@ -50,7 +52,7 @@ const editor = new Editor({ ], ``` -Learn [more about custom extensions in our guide](/guide/build-extensions). +Learn [more about custom extensions in our guide](/guide/extend-extensions). ### ProseMirror plugins ProseMirror has a fantastic eco system with many amazing plugins. If you want to use one of them, you can register them with tiptap like that: diff --git a/docs/src/docPages/api/extensions/collaboration-cursor.md b/docs/src/docPages/api/extensions/collaboration-cursor.md index 5750ef317..271b584a8 100644 --- a/docs/src/docPages/api/extensions/collaboration-cursor.md +++ b/docs/src/docPages/api/extensions/collaboration-cursor.md @@ -10,10 +10,6 @@ Open this page in multiple browser windows to test it. We kindly ask you to [sponsor our work](/sponsor) when using this extension in production. ::: -::: warning Use with Collaboration -This extension requires the [`Collaboration`](/api/extensions/collaboration) extension. -::: - ## Installation ```bash # with npm @@ -23,6 +19,8 @@ npm install @tiptap/extension-collaboration-cursor yarn add @tiptap/extension-collaboration-cursor ``` +This extension requires the [`Collaboration`](/api/extensions/collaboration) extension. + ## Settings | Option | Type | Default | Description | | -------- | ---------- | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -42,4 +40,6 @@ yarn add @tiptap/extension-collaboration-cursor :::warning Public The content of this editor is shared with other users. ::: + + diff --git a/docs/src/docPages/api/extensions/collaboration.md b/docs/src/docPages/api/extensions/collaboration.md index 674a92148..ed1365ddf 100644 --- a/docs/src/docPages/api/extensions/collaboration.md +++ b/docs/src/docPages/api/extensions/collaboration.md @@ -48,4 +48,5 @@ yarn add @tiptap/extension-collaboration yjs y-websocket :::warning Public The content of this editor is shared with other users. ::: + diff --git a/docs/src/docPages/api/extensions/font-family.md b/docs/src/docPages/api/extensions/font-family.md index 15c4817a1..bdf35062d 100644 --- a/docs/src/docPages/api/extensions/font-family.md +++ b/docs/src/docPages/api/extensions/font-family.md @@ -5,10 +5,6 @@ This extension enables you to set the font family in the editor. It uses the [`TextStyle`](/api/marks/text-style) mark, which renders a `` tag. The font family is applied as inline style, for example ``. ## Installation -::: warning Use with TextStyle -This extension requires the [`TextStyle`](/api/marks/text-style) mark. -::: - ```bash # with npm npm install @tiptap/extension-text-style @tiptap/extension-font-family @@ -17,6 +13,8 @@ npm install @tiptap/extension-text-style @tiptap/extension-font-family yarn add @tiptap/extension-text-style @tiptap/extension-font-family ``` +This extension requires the [`TextStyle`](/api/marks/text-style) mark. + ## Settings | Option | Type | Default | Description | | ------ | ------- | --------------- | ------------------------------------------------------------------------ | diff --git a/docs/src/docPages/api/nodes/bullet-list.md b/docs/src/docPages/api/nodes/bullet-list.md index 1c6871159..eb3cc2b02 100644 --- a/docs/src/docPages/api/nodes/bullet-list.md +++ b/docs/src/docPages/api/nodes/bullet-list.md @@ -7,10 +7,6 @@ This extension enables you to use bullet lists in the editor. They are rendered Type , or at the beginning of a new line and it will magically transform to a bullet list. ## Installation -::: warning Use with ListItem -This extension requires the [`ListItem`](/api/nodes/list-item) node. -::: - ```bash # with npm npm install @tiptap/extension-bullet-list @tiptap/extension-list-item @@ -19,6 +15,8 @@ npm install @tiptap/extension-bullet-list @tiptap/extension-list-item yarn add @tiptap/extension-bullet-list @tiptap/extension-list-item ``` +This extension requires the [`ListItem`](/api/nodes/list-item) node. + ## Settings | Option | Type | Default | Description | | -------------- | -------- | ------- | --------------------------------------------------------------------- | diff --git a/docs/src/docPages/api/nodes/emoji.md b/docs/src/docPages/api/nodes/emoji.md index 689bba81f..0d085130c 100644 --- a/docs/src/docPages/api/nodes/emoji.md +++ b/docs/src/docPages/api/nodes/emoji.md @@ -1,7 +1,7 @@ # Emoji :::pro Fund the development ♥ -We need your support to maintain, update, support and develop tiptap 2. If you’re waiting for this extension, [become a sponsor and fund open source](/sponsor). +We need your support to maintain, update, support and develop tiptap 2. If you’re waiting for this extension, [become a sponsor and fund open-source](/sponsor). ::: TODO diff --git a/docs/src/docPages/api/nodes/hashtag.md b/docs/src/docPages/api/nodes/hashtag.md index a0f900ae6..00188637b 100644 --- a/docs/src/docPages/api/nodes/hashtag.md +++ b/docs/src/docPages/api/nodes/hashtag.md @@ -1,7 +1,7 @@ # Hashtag :::pro Fund the development ♥ -We need your support to maintain, update, support and develop tiptap 2. If you’re waiting for this extension, [become a sponsor and fund open source](/sponsor). +We need your support to maintain, update, support and develop tiptap 2. If you’re waiting for this extension, [become a sponsor and fund open-source](/sponsor). ::: TODO diff --git a/docs/src/docPages/api/nodes/list-item.md b/docs/src/docPages/api/nodes/list-item.md index 21cb2f8eb..355e7347b 100644 --- a/docs/src/docPages/api/nodes/list-item.md +++ b/docs/src/docPages/api/nodes/list-item.md @@ -5,10 +5,6 @@ The ListItem extension adds support for the `
  • ` HTML tag. It’s used for bullet lists and ordered lists and can’t really be used without them. ## Installation -::: warning Use with BulletList and/or OrderedList -This extension requires the [`BulletList`](/api/nodes/bullet-list) or [`OrderedList`](/api/nodes/ordered-list) node. -::: - ```bash # with npm npm install @tiptap/extension-list-item @@ -17,6 +13,8 @@ npm install @tiptap/extension-list-item yarn add @tiptap/extension-list-item ``` +This extension requires the [`BulletList`](/api/nodes/bullet-list) or [`OrderedList`](/api/nodes/ordered-list) node. + ## Settings | Option | Type | Default | Description | | -------------- | -------- | ------- | --------------------------------------------------------------------- | diff --git a/docs/src/docPages/api/nodes/ordered-list.md b/docs/src/docPages/api/nodes/ordered-list.md index c4bc77c7e..61617c00c 100644 --- a/docs/src/docPages/api/nodes/ordered-list.md +++ b/docs/src/docPages/api/nodes/ordered-list.md @@ -7,10 +7,6 @@ This extension enables you to use ordered lists in the editor. They are rendered Type 1.  (or any other number followed by a dot) at the beginning of a new line and it will magically transform to a ordered list. ## Installation -::: warning Use with ListItem -This extension requires the [`ListItem`](/api/nodes/list-item) node. -::: - ```bash # with npm npm install @tiptap/extension-ordered-list @tiptap/extension-list-item @@ -19,6 +15,8 @@ npm install @tiptap/extension-ordered-list @tiptap/extension-list-item yarn add @tiptap/extension-ordered-list @tiptap/extension-list-item ``` +This extension requires the [`ListItem`](/api/nodes/list-item) node. + ## Settings | Option | Type | Default | Description | | -------------- | -------- | ------- | --------------------------------------------------------------------- | diff --git a/docs/src/docPages/api/nodes/table-cell.md b/docs/src/docPages/api/nodes/table-cell.md index 51b4fd6ea..271dad1cd 100644 --- a/docs/src/docPages/api/nodes/table-cell.md +++ b/docs/src/docPages/api/nodes/table-cell.md @@ -5,10 +5,6 @@ Don’t try to use tables without table cells. It won’t be fun. ## Installation -::: warning Use with Table, TableRow and TableHeader -This extension requires the [`Table`](/api/nodes/table), [`TableRow`](/api/nodes/table-row) and [`TableHeader`](/api/nodes/table-header) nodes. -::: - ```bash # with npm npm install @tiptap/extension-table @tiptap/extension-table-row @tiptap/extension-table-header @tiptap/extension-table-cell @@ -17,6 +13,8 @@ npm install @tiptap/extension-table @tiptap/extension-table-row @tiptap/extensio yarn add @tiptap/extension-table @tiptap/extension-table-row @tiptap/extension-table-header @tiptap/extension-table-cell ``` +This extension requires the [`Table`](/api/nodes/table), [`TableRow`](/api/nodes/table-row) and [`TableHeader`](/api/nodes/table-header) nodes. + ## Source code [packages/extension-table-cell/](https://github.com/ueberdosis/tiptap-next/blob/main/packages/extension-table-cell/) diff --git a/docs/src/docPages/api/nodes/table-header.md b/docs/src/docPages/api/nodes/table-header.md index 916617a8e..8c55968cd 100644 --- a/docs/src/docPages/api/nodes/table-header.md +++ b/docs/src/docPages/api/nodes/table-header.md @@ -21,10 +21,6 @@ TableRow.extend({ ``` ## Installation -::: warning Use with Table, TableRow and TableCell -This extension requires the [`Table`](/api/nodes/table), [`TableRow`](/api/nodes/table-row) and [`TableCell`](/api/nodes/table-cell) nodes. -::: - ```bash # with npm npm install @tiptap/extension-table @tiptap/extension-table-row @tiptap/extension-table-header @tiptap/extension-table-cell @@ -33,6 +29,8 @@ npm install @tiptap/extension-table @tiptap/extension-table-row @tiptap/extensio yarn add @tiptap/extension-table @tiptap/extension-table-row @tiptap/extension-table-header @tiptap/extension-table-cell ``` +This extension requires the [`Table`](/api/nodes/table), [`TableRow`](/api/nodes/table-row) and [`TableCell`](/api/nodes/table-cell) nodes. + ## Source code [packages/extension-table-header/](https://github.com/ueberdosis/tiptap-next/blob/main/packages/extension-table-header/) diff --git a/docs/src/docPages/api/nodes/table-row.md b/docs/src/docPages/api/nodes/table-row.md index 7a993f804..fd93df5f2 100644 --- a/docs/src/docPages/api/nodes/table-row.md +++ b/docs/src/docPages/api/nodes/table-row.md @@ -5,10 +5,6 @@ What’s a table without rows? Add this extension to make your tables usable. ## Installation -::: warning Use with Table, TableHeader and TableCell -This extension requires the [`Table`](/api/nodes/table), [`TableHeader`](/api/nodes/table-header) and [`TableCell`](/api/nodes/table-cell) nodes. -::: - ```bash # with npm npm install @tiptap/extension-table @tiptap/extension-table-row @tiptap/extension-table-header @tiptap/extension-table-cell @@ -17,6 +13,8 @@ npm install @tiptap/extension-table @tiptap/extension-table-row @tiptap/extensio yarn add @tiptap/extension-table @tiptap/extension-table-row @tiptap/extension-table-header @tiptap/extension-table-cell ``` +This extension requires the [`Table`](/api/nodes/table), [`TableHeader`](/api/nodes/table-header) and [`TableCell`](/api/nodes/table-cell) nodes. + ## Source code [packages/extension-table-row/](https://github.com/ueberdosis/tiptap-next/blob/main/packages/extension-table-row/) diff --git a/docs/src/docPages/api/nodes/table.md b/docs/src/docPages/api/nodes/table.md index 666daf5a9..5a18537f6 100644 --- a/docs/src/docPages/api/nodes/table.md +++ b/docs/src/docPages/api/nodes/table.md @@ -7,10 +7,6 @@ Nothing is as much fun as a good old HTML table. The `Table` extension enables y Don’t forget to add a `spacer.gif`. (Just joking. If you don’t know what that is, don’t listen.) ## Installation -::: warning Use with TableRow, TableHeader and TableCell -This extension requires the [`TableRow`](/api/nodes/table-row), [`TableHeader`](/api/nodes/table-header) and [`TableCell`](/api/nodes/table-cell) nodes. -::: - ```bash # with npm npm install @tiptap/extension-table @tiptap/extension-table-row @tiptap/extension-table-header @tiptap/extension-table-cell @@ -19,6 +15,8 @@ npm install @tiptap/extension-table @tiptap/extension-table-row @tiptap/extensio yarn add @tiptap/extension-table @tiptap/extension-table-row @tiptap/extension-table-header @tiptap/extension-table-cell ``` +This extension requires the [`TableRow`](/api/nodes/table-row), [`TableHeader`](/api/nodes/table-header) and [`TableCell`](/api/nodes/table-cell) nodes. + ## Settings | Option | Type | Default | Description | | ----------------------- | --------- | ----------- | --------------------------------------------------------------------- | diff --git a/docs/src/docPages/api/nodes/task-item.md b/docs/src/docPages/api/nodes/task-item.md index 241c9207d..223f33c1f 100644 --- a/docs/src/docPages/api/nodes/task-item.md +++ b/docs/src/docPages/api/nodes/task-item.md @@ -7,10 +7,6 @@ This extension renders a task item list element, which is a `
  • ` tag with a `d This extension doesn’t require any JavaScript framework, it’s based on plain JavaScript. ## Installation -::: warning Use with TaskList -This extension requires the [`TaskList`](/api/nodes/task-list) node. -::: - ```bash # With npm npm install @tiptap/extension-task-list @tiptap/extension-task-item @@ -19,6 +15,8 @@ npm install @tiptap/extension-task-list @tiptap/extension-task-item yarn add @tiptap/extension-task-list @tiptap/extension-task-item ``` +This extension requires the [`TaskList`](/api/nodes/task-list) node. + ## Settings | Option | Type | Default | Description | | -------------- | -------- | ------- | --------------------------------------------------------------------- | diff --git a/docs/src/docPages/api/nodes/task-list.md b/docs/src/docPages/api/nodes/task-list.md index 10d7d10d8..28f6e0702 100644 --- a/docs/src/docPages/api/nodes/task-list.md +++ b/docs/src/docPages/api/nodes/task-list.md @@ -7,10 +7,6 @@ This extension enables you to use task lists in the editor. They are rendered as Type [ ]  or [x]  at the beginning of a new line and it will magically transform to a task list. ## Installation -::: warning Use with TaskItem -This extension requires the [`TaskItem`](/api/nodes/task-item) extension. -::: - ```bash # with npm npm install @tiptap/extension-task-list @tiptap/extension-task-item @@ -19,6 +15,8 @@ npm install @tiptap/extension-task-list @tiptap/extension-task-item yarn add @tiptap/extension-task-list @tiptap/extension-task-item ``` +This extension requires the [`TaskItem`](/api/nodes/task-item) extension. + ## Settings | Option | Type | Default | Description | | -------------- | -------- | ------- | --------------------------------------------------------------------- | diff --git a/docs/src/docPages/experiments.md b/docs/src/docPages/experiments.md index b19be9421..bb3f5e589 100644 --- a/docs/src/docPages/experiments.md +++ b/docs/src/docPages/experiments.md @@ -3,13 +3,11 @@ Congratulations! You’ve found our playground with a list of experiments. Be aw ## New * [Linter](/experiments/linter) -* [Annotation](/experiments/annotation) -* [Comments](/experiments/comments) -* [Color](/experiments/color) -* [Commands](/experiments/commands) -* [Embeds](/experiments/embeds) * [Multiple editors](/experiments/multiple-editors) -* [Details](/experiments/details) +* [@tiptap/extension-slash-command?](/experiments/commands) +* [@tiptap/extension-iframe?](/experiments/embeds) +* [@tiptap/extension-toggle-list?](/experiments/details) +* [@tiptap/extension-collaboration-annotation](/experiments/collaboration-annotation) ## Waiting for approval * [@tiptap/extension-placeholder](/experiments/placeholder) diff --git a/docs/src/docPages/experiments/annotation.md b/docs/src/docPages/experiments/annotation.md deleted file mode 100644 index 4d4ebbe50..000000000 --- a/docs/src/docPages/experiments/annotation.md +++ /dev/null @@ -1,5 +0,0 @@ -# Annotation - -⚠️ Experiment - - diff --git a/docs/src/docPages/experiments/collaboration-annotation.md b/docs/src/docPages/experiments/collaboration-annotation.md new file mode 100644 index 000000000..1644d9933 --- /dev/null +++ b/docs/src/docPages/experiments/collaboration-annotation.md @@ -0,0 +1,42 @@ +# CollaborationAnnotation +[![Version](https://img.shields.io/npm/v/@tiptap/extension-collaboration-annotation.svg?label=version)](https://www.npmjs.com/package/@tiptap/extension-collaboration-annotation) +[![Downloads](https://img.shields.io/npm/dm/@tiptap/extension-collaboration-annotation.svg)](https://npmcharts.com/compare/@tiptap/extension-collaboration-annotation?minimal=true) + +⚠️ Experiment + +Annotations can be used to add additional information to the content, for example comments. They live on a different level than the actual editor content. + + + +## Installation +```bash +# with npm +npm install @tiptap/extension-collaboration-annotation + +# with Yarn +yarn add @tiptap/extension-collaboration-annotation +``` + +This extension requires the [`Collaboration`](/api/extensions/collaboration) extension. + +## Settings +| Option | Type | Default | Description | +| -------- | -------- | ----------- | ---------------------------------------------------------------------------------- | +| document | `Object` | `null` | An initialized Y.js document. | +| field | `String` | `'default'` | Name of a Y.js map, can be changed to sync multiple fields with one Y.js document. | +| map | `Object` | `null` | A raw Y.js map, can be used instead of `document` and `field`. | + +## Commands +| Command | Parameters | Description | +| ---------------- | ---------- | ------------------------------------------------------------------------- | +| addAnnotation | data | Adds an annotation to the current selection, takes a string or an object. | +| updateAnnotation | id, data | Update the data that’s associated with an annotation. | +| deleteAnnotation | id | Remove an annotation. | + +## Source code +[packages/extension-collaboration-annotation/](https://github.com/ueberdosis/tiptap-next/blob/main/packages/extension-collaboration-annotation/) + +## Usage + diff --git a/docs/src/docPages/experiments/color.md b/docs/src/docPages/experiments/color.md deleted file mode 100644 index 5cc460273..000000000 --- a/docs/src/docPages/experiments/color.md +++ /dev/null @@ -1,5 +0,0 @@ -# Color - -⚠️ Experiment - - diff --git a/docs/src/docPages/experiments/comments.md b/docs/src/docPages/experiments/comments.md deleted file mode 100644 index 42fda4361..000000000 --- a/docs/src/docPages/experiments/comments.md +++ /dev/null @@ -1,5 +0,0 @@ -# Comments - -⚠️ Experiment - - diff --git a/docs/src/docPages/guide/accessibility.md b/docs/src/docPages/guide/accessibility.md index 99af8dfef..b2ebea3c9 100644 --- a/docs/src/docPages/guide/accessibility.md +++ b/docs/src/docPages/guide/accessibility.md @@ -1,7 +1,7 @@ # Accessibility :::pro Fund the development ♥ -We need your support to maintain, update, support and develop tiptap 2. If you’re waiting for progress here, [become a sponsor and fund open source](/sponsor). +We need your support to maintain, update, support and develop tiptap 2. If you’re waiting for progress here, [become a sponsor and fund open-source](/sponsor). ::: ## toc diff --git a/docs/src/docPages/guide/configuration.md b/docs/src/docPages/guide/configuration.md index 0cefd0b85..1c43fd9bc 100644 --- a/docs/src/docPages/guide/configuration.md +++ b/docs/src/docPages/guide/configuration.md @@ -37,8 +37,27 @@ This will do the following: 5. make the text editable (but that’s the default anyway), and 6. disable the loading of [the default CSS](https://github.com/ueberdosis/tiptap-next/tree/main/packages/core/src/style.ts) (which is not much anyway). -## Configure extensions -A lot of the extension can be configured, too. Add an `.configure()` to the extension and pass an object to it. The following example will disable the default heading levels 4, 5 and 6: +## Nodes, marks and extensions +Most features are packed into [nodes](/api/nodes), [marks](/api/marks) and [extensions](/api/extensions). Import what you need and pass them as an Array to the editor and you are good to go. Here is the minimal setup with only three extensions: + +```js +import { Editor } from '@tiptap/core' +import Document from '@tiptap/extension-document' +import Paragraph from '@tiptap/extension-paragraph' +import Text from '@tiptap/extension-text' + +new Editor({ + element: document.querySelector('.element'), + extensions: [ + Document, + Paragraph, + Text, + ], +}) +``` + +### Configure an extensions +Most extensions can be configured. Add a `.configure()` to pass an object to it. The following example will disable the default heading levels 4, 5 and 6: ```js import { Editor } from '@tiptap/core' @@ -60,4 +79,57 @@ new Editor({ }) ``` -Have a look at the documentation of the extension you’re using to learn more about their settings. +Have a look at the documentation of the extension you use to learn more about their settings. + +### Default extensions +We have put together a few of the most common extensions and provide a `defaultExtensions()` helper to load them. Here is how you to use that: + +```js +import { Editor, defaultExtensions } from '@tiptap/starter-kit' + +new Editor({ + extensions: defaultExtensions(), +}) +``` + +And you can even pass configuration for all default extensions as an object. Just prefix the configuration with the extension name: + +```js +import { Editor, defaultExtensions } from '@tiptap/starter-kit' + +new Editor({ + extensions: defaultExtensions({ + heading: { + levels: [1, 2, 3] + }, + }), +}) +``` + +The `defaultExtensions()` function returns an array, so if you want to load them and add some custom extensions you could write it like that: + +```js +import { Editor, defaultExtensions } from '@tiptap/starter-kit' +import Strike from '@tiptap/extension-strike' + +new Editor({ + extensions: [ + ...defaultExtensions(), + Strike, + ], +}) +``` + +Don’t want to load a specific extension? Just filter it out: + +```js +import { Editor, defaultExtensions } from '@tiptap/starter-kit' + +new Editor({ + extensions: [ + ...defaultExtensions().filter(extension => extension.config.name !== 'history'), + ] +}) +``` + +You’ll probably see something like that in collaborative editing examples. The [`Collaboration`](/api/extensions/collaboration) comes with its own history extension, you need to remove the default [`History`](/api/extensions/history) extension to avoid conflicts. diff --git a/docs/src/docPages/guide/extend-extensions.md b/docs/src/docPages/guide/extend-extensions.md index 531f351c4..05a39aef3 100644 --- a/docs/src/docPages/guide/extend-extensions.md +++ b/docs/src/docPages/guide/extend-extensions.md @@ -6,7 +6,7 @@ One of the strength of tiptap is it’s extendability. You don’t depend on the provided extensions, it’s intended to extend the editor to your liking. With custom extensions you can add new content types and new functionalities, on top of what already exists or from scratch. ## Customize existing extensions -Let’s say you want to change the keyboard shortcuts for the bullet list. You should start by looking at [the source code of the `BulletList` extension](https://github.com/ueberdosis/tiptap-next/blob/main/packages/extension-bullet-list/index.ts) and find the part you would like to change. In that case, the keyboard shortcut, and just that. +Let’s say you want to change the keyboard shortcuts for the bullet list. You should start by looking at [the source code of the `BulletList` extension](https://github.com/ueberdosis/tiptap-next/blob/main/packages/extension-bullet-list/src/bullet-list.ts) and find the part you would like to change. In that case, the keyboard shortcut, and just that. Every extension has an `extend()` method, which takes an object with everything you want to change or add to it. For the bespoken example, your code could like that: diff --git a/docs/src/docPages/guide/node-views.md b/docs/src/docPages/guide/node-views.md index e6fb1ee17..a18318b19 100644 --- a/docs/src/docPages/guide/node-views.md +++ b/docs/src/docPages/guide/node-views.md @@ -146,3 +146,32 @@ export default { ``` + +## Reference + +### dom: ?⁠dom.Node +> The outer DOM node that represents the document node. When not given, the default strategy is used to create a DOM node. + +### contentDOM: ?⁠dom.Node +> 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. + +### update: ?⁠fn(node: Node, decorations: [Decoration]) → bool +> 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. + +### selectNode: ?⁠fn() +> Can be used to override the way the node's selected status (as a node selection) is displayed. + +### deselectNode: ?⁠fn() +> When defining a selectNode method, you should also provide a deselectNode method to remove the effect again. + +### setSelection: ?⁠fn(anchor: number, head: number, root: dom.Document) +> 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. + +### stopEvent: ?⁠fn(event: dom.Event) → bool +> 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. + +### ignoreMutation: ?⁠fn(dom.MutationRecord) → bool +> Called when a DOM mutation or a selection change happens within the view. When the change is a selection change, the record will have a type property of "selection" (which doesn't occur for native mutation records). Return false if the editor should re-read the selection or re-parse the range around the mutation, true if it can safely be ignored. + +### destroy: ?⁠fn() +> Called when the node view is removed from the editor or the whole editor is destroyed. diff --git a/docs/src/docPages/guide/toolbar.md b/docs/src/docPages/guide/toolbar.md index 58f76c780..724980404 100644 --- a/docs/src/docPages/guide/toolbar.md +++ b/docs/src/docPages/guide/toolbar.md @@ -63,7 +63,7 @@ editor.isActive({ textAlign: 'right' }) If your selection spans multiple nodes or marks, or only part of the selection has a mark, `isActive()` will return `false` and indicate nothing is active. That is how it is supposed to be, because it allows people to apply a new node or mark to that selection right-away. ## Icons -Most editor toolbars use icons for their buttons. In some of our demos, we use the open source icon set [Remix Icon](https://remixicon.com/), that’s free to use. But it’s totally up to you what you use. Here are a few icon sets you can consider: +Most editor toolbars use icons for their buttons. In some of our demos, we use the open-source icon set [Remix Icon](https://remixicon.com/), that’s free to use. But it’s totally up to you what you use. Here are a few icon sets you can consider: * [Remix Icon](https://remixicon.com/#editor) * [Font Awesome](https://fontawesome.com/icons?c=editors) diff --git a/docs/src/docPages/installation/next.md b/docs/src/docPages/installation/next.md index 10ad2d60a..a71e9336c 100644 --- a/docs/src/docPages/installation/next.md +++ b/docs/src/docPages/installation/next.md @@ -7,4 +7,4 @@ The following guide describes how to integrate tiptap with your [Next.js](https: TODO - + diff --git a/docs/src/docPages/installation/react.md b/docs/src/docPages/installation/react.md index b7d6acfc7..511150c97 100644 --- a/docs/src/docPages/installation/react.md +++ b/docs/src/docPages/installation/react.md @@ -7,4 +7,4 @@ The following guide describes how to integrate tiptap with your [React](https:// TODO - + diff --git a/docs/src/docPages/introduction.md b/docs/src/docPages/introduction.md index adfb721d7..7d26f565b 100644 --- a/docs/src/docPages/introduction.md +++ b/docs/src/docPages/introduction.md @@ -10,7 +10,7 @@ title: Headless WYSIWYG Text Editor tiptap is a headless wrapper around [ProseMirror](https://ProseMirror.net) – a toolkit for building rich text WYSIWYG editors, which is already in use at many well-known companies such as *New York Times*, *The Guardian* or *Atlassian*. -Create exactly the rich text editor you want out of customizable building blocks. tiptap comes with sensible defaults, a lot of extensions and a friendly API to customize every aspect. It’s backed by a welcoming community, open source, and free. +Create exactly the rich text editor you want out of customizable building blocks. tiptap comes with sensible defaults, a lot of extensions and a friendly API to customize every aspect. It’s backed by a welcoming community, open-source, and free. ## Example diff --git a/docs/src/docPages/sponsor.md b/docs/src/docPages/sponsor.md index f6a852fe5..22fb90b3d 100644 --- a/docs/src/docPages/sponsor.md +++ b/docs/src/docPages/sponsor.md @@ -3,16 +3,16 @@ ## Introduction To deliver a top-notch developer experience and user experience, we put ~~hundreds~~ thousands of hours of unpaid work into tiptap. Your funding helps us to make this work more and more financially sustainable. This enables us to provide helpful support, maintain all our packages, keep everything up to date, and develop new features and extensions for tiptap. -Give back to the open source community and [sponsor us on GitHub](https://github.com/sponsors/ueberdosis)! ♥ +Give back to the open-source community and [sponsor us on GitHub](https://github.com/sponsors/ueberdosis)! ♥ ## Your benefits as a sponsor -* Give back to the open source community +* Give back to the open-source community * Get early access to private repositories * Ensure the further maintenace and development of tiptap * Your issues and pull requests get a `sponsor ♥` label * Get a sponsor badge in all your comments on GitHub * Show support in your GitHub profile -* Receive monthly reports about our open source work +* Receive monthly reports about our open-source work Does that sound good? [Sponsor us on GitHub!](https://github.com/sponsors/ueberdosis) diff --git a/docs/src/pages/index.vue b/docs/src/pages/index.vue index c8f188042..7b11e3523 100644 --- a/docs/src/pages/index.vue +++ b/docs/src/pages/index.vue @@ -35,7 +35,7 @@ Headless

    - We don’t tell you what a menu should look like or where it should be rendered in the DOM. That’s why tiptap is headless and comes without any CSS. You are in full control over markup, styling and behaviour. + It’s headless and comes without any CSS. You are in full control over markup, styling and behaviour.

    @@ -49,7 +49,7 @@ Framework-agnostic

    - No matter what framework you use, you’ll enjoy tiptap. Out of the box, it works with plain JavaScript and Vue.js, but it’s also possible to use it in React, Svelte and others. + Out of the box, tiptap works with plain JavaScript and Vue.js, but it’s also possible to use it in React, Svelte and others.

    @@ -63,7 +63,7 @@ TypeScript

    - tiptap 2 is written in TypeScript. That helps to find bugs early and gives a nice autocomplete for the API (if your IDE supports that) on top of the extensive human written documentation. + TypeScript helps to find bugs early and gives you a nice autocomplete for the API on top of the extensive human written documentation.

    @@ -77,7 +77,7 @@ Collaborative

    - Real-time collaboration, syncing between different devices and working offline used to be hard. We provide everything you need to keep everything in sync, conflict-free with the power of Y.js. + Real-time collaboration, syncing between different devices and working offline isn’t hard anymore. Keep everything in sync with the magic of Y.js.

    @@ -91,7 +91,7 @@ Community

    - Over the years, a lovely community has grown around tiptap. There’s so much content shared, so many people helping out in issues and a ton of community extensions, you’ll be surprised how much that can help. + There’s so much content shared, so many people helping out in issues and a ton of community extensions, you’ll be surprised how much that all can help.

    @@ -108,7 +108,7 @@ Quickstart

    - For quick demos or to give it just a spin, grab the latest build from a CDN. Here is a quick example to get you started with tiptap: + For quick demos or to give it just a spin, grab the latest build from a CDN. Here is an example to get you started with tiptap:

    <!DOCTYPE html> @@ -134,7 +134,7 @@
    - Learn More + Learn more
    diff --git a/packages/starter-kit/src/index.ts b/packages/starter-kit/src/index.ts index 23cd8ed64..9c8dbb968 100644 --- a/packages/starter-kit/src/index.ts +++ b/packages/starter-kit/src/index.ts @@ -18,21 +18,21 @@ import OrderedList, { OrderedListOptions } from '@tiptap/extension-ordered-list' import ListItem, { ListItemOptions } from '@tiptap/extension-list-item' export function defaultExtensions(options?: Partial<{ - dropursor: DropcursorOptions, - paragraph: ParagraphOptions, - history: HistoryOptions, - bold: BoldOptions, - italic: ItalicOptions, - code: CodeOptions, - codeBlock: CodeBlockOptions, - heading: HeadingOptions, - hardBreak: HardBreakOptions, - strike: StrikeOptions, - blockquote: BlockquoteOptions, - horizontalRule: HorizontalRuleOptions, - bulletList: BulletListOptions, - orderedList: OrderedListOptions, - listItem: ListItemOptions, + dropursor: Partial, + paragraph: Partial, + history: Partial, + bold: Partial, + italic: Partial, + code: Partial, + codeBlock: Partial, + heading: Partial, + hardBreak: Partial, + strike: Partial, + blockquote: Partial, + horizontalRule: Partial, + bulletList: Partial, + orderedList: Partial, + listItem: Partial, }>) { return [ Document,