From a6c1e2e20fa022b20274845e45302d14deb314b6 Mon Sep 17 00:00:00 2001 From: Hans Pagel Date: Wed, 10 Feb 2021 23:19:34 +0100 Subject: [PATCH 01/47] remove details attribute, use node view state instead --- docs/src/demos/Experiments/Details/details.ts | 75 +++++++------------ 1 file changed, 27 insertions(+), 48 deletions(-) diff --git a/docs/src/demos/Experiments/Details/details.ts b/docs/src/demos/Experiments/Details/details.ts index 32103ccbd..a58dadf75 100644 --- a/docs/src/demos/Experiments/Details/details.ts +++ b/docs/src/demos/Experiments/Details/details.ts @@ -1,4 +1,5 @@ import { Node, mergeAttributes } from '@tiptap/core' +// import { update } from 'cypress/types/lodash' export interface DetailsOptions { HTMLAttributes: { @@ -17,28 +18,6 @@ export default Node.create({ 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', @@ -51,32 +30,26 @@ export default Node.create({ addNodeView() { return ({ - node, HTMLAttributes, - getPos, - editor, }) => { - const { view } = editor const item = document.createElement('details') + let open = false item.addEventListener('click', event => { - // @ts-ignore - const { open } = event.target.parentElement as HTMLElement // @ts-ignore const { localName } = event.target - if (typeof getPos === 'function' && localName === 'summary') { - view.dispatch(view.state.tr.setNodeMarkup(getPos(), undefined, { - open: !open, - })) - editor.commands.focus() + if (localName === 'summary') { + open = !open + + if (open) { + item.setAttribute('open', 'open') + } else { + item.removeAttribute('open') + } } }) - if (node.attrs.open) { - item.setAttribute('open', 'open') - } - Object.entries(HTMLAttributes).forEach(([key, value]) => { item.setAttribute(key, value) }) @@ -84,19 +57,25 @@ export default Node.create({ return { dom: item, contentDOM: item, - update: updatedNode => { - if (updatedNode.type !== this.type) { - return false - } + ignoreMutation: (updatedNode: MutationRecord) => { + // @ts-ignore + console.log({ updatedNode }, 'ignoreMutation', updatedNode.attributeName === 'open') - if (updatedNode.attrs.open) { - item.setAttribute('open', 'open') - } else { - item.removeAttribute('open') - } - - return true + return updatedNode.attributeName === 'open' }, + // update: updatedNode => { + // if (updatedNode.type !== this.type) { + // return false + // } + + // if (updatedNode.attrs.open) { + // item.setAttribute('open', 'open') + // } else { + // item.removeAttribute('open') + // } + + // return true + // }, } } }, From bd6233a1a1ffbd1f990519c677591c0dfbfb8b97 Mon Sep 17 00:00:00 2001 From: Hans Pagel Date: Thu, 11 Feb 2021 00:15:35 +0100 Subject: [PATCH 02/47] improve details experiment --- docs/src/demos/Experiments/Details/details.ts | 21 +++---------------- docs/src/demos/Experiments/Details/index.vue | 2 +- 2 files changed, 4 insertions(+), 19 deletions(-) diff --git a/docs/src/demos/Experiments/Details/details.ts b/docs/src/demos/Experiments/Details/details.ts index a58dadf75..457a56b35 100644 --- a/docs/src/demos/Experiments/Details/details.ts +++ b/docs/src/demos/Experiments/Details/details.ts @@ -1,5 +1,4 @@ import { Node, mergeAttributes } from '@tiptap/core' -// import { update } from 'cypress/types/lodash' export interface DetailsOptions { HTMLAttributes: { @@ -33,7 +32,9 @@ export default Node.create({ HTMLAttributes, }) => { const item = document.createElement('details') - let open = false + + // TODO: Why does that have to be true? + let open = true item.addEventListener('click', event => { // @ts-ignore @@ -58,24 +59,8 @@ export default Node.create({ dom: item, contentDOM: item, ignoreMutation: (updatedNode: MutationRecord) => { - // @ts-ignore - console.log({ updatedNode }, 'ignoreMutation', updatedNode.attributeName === 'open') - return updatedNode.attributeName === 'open' }, - // update: updatedNode => { - // if (updatedNode.type !== this.type) { - // return false - // } - - // if (updatedNode.attrs.open) { - // item.setAttribute('open', 'open') - // } else { - // item.removeAttribute('open') - // } - - // return true - // }, } } }, diff --git a/docs/src/demos/Experiments/Details/index.vue b/docs/src/demos/Experiments/Details/index.vue index 37044446d..0a4dfa97d 100644 --- a/docs/src/demos/Experiments/Details/index.vue +++ b/docs/src/demos/Experiments/Details/index.vue @@ -31,7 +31,7 @@ export default { ], content: `

Here is a details list:

-
+
An open details tag

More info about the details.

From fd6b3467992ad2f8f260f8776acd93be8df867e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Thu, 11 Feb 2021 08:59:58 +0100 Subject: [PATCH 03/47] fix details --- .../Experiments/Details/details-summary.ts | 4 +- docs/src/demos/Experiments/Details/details.ts | 40 ++----------------- 2 files changed, 6 insertions(+), 38 deletions(-) diff --git a/docs/src/demos/Experiments/Details/details-summary.ts b/docs/src/demos/Experiments/Details/details-summary.ts index 03feeb490..e796bfb7d 100644 --- a/docs/src/demos/Experiments/Details/details-summary.ts +++ b/docs/src/demos/Experiments/Details/details-summary.ts @@ -11,7 +11,9 @@ export default Node.create({ content: 'inline*', - // group: 'block', + 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 a58dadf75..4dc8d02c3 100644 --- a/docs/src/demos/Experiments/Details/details.ts +++ b/docs/src/demos/Experiments/Details/details.ts @@ -29,26 +29,8 @@ export default Node.create({ }, addNodeView() { - return ({ - HTMLAttributes, - }) => { + return ({ HTMLAttributes }) => { const item = document.createElement('details') - let open = false - - item.addEventListener('click', event => { - // @ts-ignore - const { localName } = event.target - - if (localName === 'summary') { - open = !open - - if (open) { - item.setAttribute('open', 'open') - } else { - item.removeAttribute('open') - } - } - }) Object.entries(HTMLAttributes).forEach(([key, value]) => { item.setAttribute(key, value) @@ -57,25 +39,9 @@ export default Node.create({ return { dom: item, contentDOM: item, - ignoreMutation: (updatedNode: MutationRecord) => { - // @ts-ignore - console.log({ updatedNode }, 'ignoreMutation', updatedNode.attributeName === 'open') - - return updatedNode.attributeName === 'open' + ignoreMutation: (mutation: MutationRecord) => { + return !item.contains(mutation.target) || item === mutation.target }, - // update: updatedNode => { - // if (updatedNode.type !== this.type) { - // return false - // } - - // if (updatedNode.attrs.open) { - // item.setAttribute('open', 'open') - // } else { - // item.removeAttribute('open') - // } - - // return true - // }, } } }, From 0177742e55ab20b262cd849cdbbe143b34a8c272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Thu, 11 Feb 2021 09:15:52 +0100 Subject: [PATCH 04/47] refactoring --- docs/src/demos/Experiments/Details/details-summary.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/src/demos/Experiments/Details/details-summary.ts b/docs/src/demos/Experiments/Details/details-summary.ts index e796bfb7d..ef31184e6 100644 --- a/docs/src/demos/Experiments/Details/details-summary.ts +++ b/docs/src/demos/Experiments/Details/details-summary.ts @@ -9,7 +9,9 @@ export interface DetailsSummaryOptions { export default Node.create({ name: 'detailsSummary', - content: 'inline*', + content: 'text*', + + marks: '', group: 'block', From c879dc3a18e7ed7195b0ae494bb4e99a3b4e25f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Thu, 11 Feb 2021 09:30:05 +0100 Subject: [PATCH 05/47] fix ugly scroll animation for collab demo --- docs/src/demos/Examples/CollaborativeEditing/index.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/demos/Examples/CollaborativeEditing/index.vue b/docs/src/demos/Examples/CollaborativeEditing/index.vue index 8c9afaf57..1eefe5590 100644 --- a/docs/src/demos/Examples/CollaborativeEditing/index.vue +++ b/docs/src/demos/Examples/CollaborativeEditing/index.vue @@ -141,7 +141,7 @@ export default { .editor { display: flex; flex-direction: column; - max-height: 90vh; + max-height: 400px; color: #0D0D0D; background-color: $colorWhite; border: 3px solid #0D0D0D; From d75027a121c0fedcba641f022af235fbf986875b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Thu, 11 Feb 2021 09:35:46 +0100 Subject: [PATCH 06/47] improve demo error styling --- docs/src/components/Demo/index.vue | 9 +++------ docs/src/components/Demo/style.scss | 18 +++++++----------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/docs/src/components/Demo/index.vue b/docs/src/components/Demo/index.vue index 4377655b3..d81e7e064 100644 --- a/docs/src/components/Demo/index.vue +++ b/docs/src/components/Demo/index.vue @@ -29,12 +29,9 @@ - +
+ Could not find a demo called “{{ name }}”. +
diff --git a/docs/src/components/Demo/style.scss b/docs/src/components/Demo/style.scss index 1bd03c66f..6403afd08 100644 --- a/docs/src/components/Demo/style.scss +++ b/docs/src/components/Demo/style.scss @@ -89,16 +89,12 @@ } &__error { - padding: 1rem 1.5rem; - color: $colorRed; - background-color: rgba($colorRed, 0.1); - } - - &__skeleton { - border-top-left-radius: inherit; - border-top-right-radius: inherit; - background-color: $colorWhite; - min-height: 20rem; - opacity: 0.1; + padding: 1rem 1.25rem; + border-radius: 0.75rem; + border: 3px solid $colorBlack; + background-color: $colorRed; + font-size: 1.1rem; + font-weight: 700; + margin-bottom: 0.25rem; } } From 980e70e9c8dd97a875df28f06726d9a63a0c5eae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Thu, 11 Feb 2021 09:38:35 +0100 Subject: [PATCH 07/47] render demo client-only --- docs/src/components/Demo/index.vue | 62 +++++++++++++++--------------- 1 file changed, 32 insertions(+), 30 deletions(-) diff --git a/docs/src/components/Demo/index.vue b/docs/src/components/Demo/index.vue index d81e7e064..9c192d85e 100644 --- a/docs/src/components/Demo/index.vue +++ b/docs/src/components/Demo/index.vue @@ -1,38 +1,40 @@ - - diff --git a/docs/src/docPages/experiments.md b/docs/src/docPages/experiments.md index b19be9421..ecc42f16e 100644 --- a/docs/src/docPages/experiments.md +++ b/docs/src/docPages/experiments.md @@ -3,7 +3,6 @@ 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) 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/comments.md b/docs/src/docPages/experiments/comments.md index 42fda4361..0a051e83f 100644 --- a/docs/src/docPages/experiments/comments.md +++ b/docs/src/docPages/experiments/comments.md @@ -2,4 +2,4 @@ ⚠️ Experiment - + From 1f064b8600228393a32fef543267028e1ce7f5c0 Mon Sep 17 00:00:00 2001 From: Hans Pagel Date: Thu, 11 Feb 2021 22:47:32 +0100 Subject: [PATCH 21/47] remove the color experiment --- .../Experiments/Color/extension/Color.ts | 68 ----------------- .../Experiments/Color/extension/index.ts | 4 - docs/src/demos/Experiments/Color/index.vue | 76 ------------------- docs/src/docPages/experiments.md | 1 - docs/src/docPages/experiments/color.md | 5 -- 5 files changed, 154 deletions(-) delete mode 100644 docs/src/demos/Experiments/Color/extension/Color.ts delete mode 100644 docs/src/demos/Experiments/Color/extension/index.ts delete mode 100644 docs/src/demos/Experiments/Color/index.vue delete mode 100644 docs/src/docPages/experiments/color.md 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 0c5e98c66..000000000 --- a/docs/src/demos/Experiments/Color/extension/Color.ts +++ /dev/null @@ -1,68 +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) - }, - }, - }), - ] - }, -}) - -declare module '@tiptap/core' { - interface AllExtensions { - Color: typeof Color, - } -} 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/docPages/experiments.md b/docs/src/docPages/experiments.md index ecc42f16e..aeb02e6aa 100644 --- a/docs/src/docPages/experiments.md +++ b/docs/src/docPages/experiments.md @@ -4,7 +4,6 @@ Congratulations! You’ve found our playground with a list of experiments. Be aw ## New * [Linter](/experiments/linter) * [Comments](/experiments/comments) -* [Color](/experiments/color) * [Commands](/experiments/commands) * [Embeds](/experiments/embeds) * [Multiple editors](/experiments/multiple-editors) 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 - - From c13db6bc8e83cdac0b231aa3b61b09d3d427ba7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Thu, 11 Feb 2021 22:48:04 +0100 Subject: [PATCH 22/47] add annotation options --- .../Annotation/extension/AnnotationPlugin.ts | 11 ++++++-- .../Annotation/extension/annotation.ts | 25 ++++++++++++++++++- docs/src/demos/Experiments/Comments/index.vue | 1 + 3 files changed, 34 insertions(+), 3 deletions(-) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts index 0806f5345..29a382c48 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts @@ -1,10 +1,17 @@ -// @ts-nocheck 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: any, +} + +export const AnnotationPlugin = (options: AnnotationPluginOptions) => new Plugin({ key: AnnotationPluginKey, state: { init(_, state) { diff --git a/docs/src/demos/Experiments/Annotation/extension/annotation.ts b/docs/src/demos/Experiments/Annotation/extension/annotation.ts index 06c666b6b..019e685d9 100644 --- a/docs/src/demos/Experiments/Annotation/extension/annotation.ts +++ b/docs/src/demos/Experiments/Annotation/extension/annotation.ts @@ -11,6 +11,18 @@ export interface AnnotationOptions { [key: string]: any }, onUpdate: (items: [any?]) => {}, + /** + * An initialized Y.js document. + */ + document: any, + /** + * Name of a Y.js fragment, 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: any, } export const Annotation = Extension.create({ @@ -21,6 +33,9 @@ export const Annotation = Extension.create({ class: 'annotation', }, onUpdate: decorations => decorations, + document: null, + field: 'annotations', + map: null, }, addCommands() { @@ -57,8 +72,16 @@ export const Annotation = Extension.create({ }, addProseMirrorPlugins() { + const map = this.options.map + ? this.options.map + : this.options.document.getMap(this.options.field) + return [ - AnnotationPlugin(this.options), + AnnotationPlugin({ + HTMLAttributes: this.options.HTMLAttributes, + onUpdate: this.options.onUpdate, + map, + }), ] }, }) diff --git a/docs/src/demos/Experiments/Comments/index.vue b/docs/src/demos/Experiments/Comments/index.vue index c2388200d..9945c558a 100644 --- a/docs/src/demos/Experiments/Comments/index.vue +++ b/docs/src/demos/Experiments/Comments/index.vue @@ -74,6 +74,7 @@ export default { Bold, Heading, Annotation.configure({ + document: this.ydoc, onUpdate: items => { this.comments = items }, }), Collaboration.configure({ From 65b52afd5a653d30773d5a7ccb35c14de7f71501 Mon Sep 17 00:00:00 2001 From: Hans Pagel Date: Thu, 11 Feb 2021 23:10:56 +0100 Subject: [PATCH 23/47] docs: update content --- docs/src/docPages/experiments.md | 8 +-- docs/src/docPages/guide/configuration.md | 78 +++++++++++++++++++++++- 2 files changed, 79 insertions(+), 7 deletions(-) diff --git a/docs/src/docPages/experiments.md b/docs/src/docPages/experiments.md index aeb02e6aa..fbc633097 100644 --- a/docs/src/docPages/experiments.md +++ b/docs/src/docPages/experiments.md @@ -3,11 +3,11 @@ Congratulations! You’ve found our playground with a list of experiments. Be aw ## New * [Linter](/experiments/linter) -* [Comments](/experiments/comments) -* [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/comments) ## Waiting for approval * [@tiptap/extension-placeholder](/experiments/placeholder) 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. From 8a62339ab9625d15d4ecd65836e641c5997b94b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Thu, 11 Feb 2021 23:14:17 +0100 Subject: [PATCH 24/47] refactoring --- .../Annotation/extension/AnnotationPlugin.ts | 7 ++- .../Annotation/extension/AnnotationState.ts | 47 ++++++++++--------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts index 29a382c48..406889f61 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts @@ -14,8 +14,11 @@ export interface AnnotationPluginOptions { export const AnnotationPlugin = (options: AnnotationPluginOptions) => new Plugin({ key: AnnotationPluginKey, state: { - init(_, state) { - return AnnotationState.init(_, state) + init() { + return new AnnotationState({ + HTMLAttributes: options.HTMLAttributes, + map: options.map, + }) }, apply(transaction, pluginState, oldState, newState) { return pluginState.apply(transaction, newState) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts index a515826e1..587d22603 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts @@ -1,15 +1,23 @@ // @ts-nocheck -import * as Y from 'yjs' import { EditorState } from 'prosemirror-state' import { Decoration, DecorationSet } from 'prosemirror-view' import { ySyncPluginKey, relativePositionToAbsolutePosition, absolutePositionToRelativePosition } from 'y-prosemirror' import { AnnotationPluginKey } from './AnnotationPlugin' -export class AnnotationState { - private decorations: any +export interface AnnotationStateOptions { + HTMLAttributes: { + [key: string]: any + }, + map: any, +} - constructor(decorations: any) { - this.decorations = decorations +export class AnnotationState { + options: AnnotationStateOptions + + decorations = DecorationSet.empty + + constructor(options: AnnotationStateOptions) { + this.options = options } findAnnotation(id: number) { @@ -23,18 +31,18 @@ export class AnnotationState { } annotationsAt(position: number) { - return this.decorations.find(position, position) + return this.decorations?.find(position, position) } apply(transaction: any, state: EditorState) { const ystate = ySyncPluginKey.getState(state) - const decs = ystate.doc.getMap('annotations') + const decs = this.options.map const action = transaction.getMeta(AnnotationPluginKey) const actionType = action && action.type if (action) { - let { decorations } = this + const { decorations } = this if (actionType === 'addAnnotation') { decs.set(action.data.id, { @@ -51,18 +59,18 @@ export class AnnotationState { data: action.data, }) - decorations = decorations.add(transaction.doc, [ - Decoration.inline(action.from, action.to, { class: 'annotation' }, { data: action.data }), + this.decorations = decorations.add(transaction.doc, [ + Decoration.inline(action.from, action.to, this.options.HTMLAttributes, { data: action.data }), ]) } else if (actionType === 'deleteAnnotation') { decs.delete(action.id) - decorations = decorations.remove([ + this.decorations = decorations.remove([ this.findAnnotation(action.id), ]) } - return new AnnotationState(decorations) + return this } if (ystate && ystate.isChangeOrigin) { @@ -84,22 +92,19 @@ export class AnnotationState { dec.to, ystate.binding.mapping, ), - { class: 'annotation' }, + this.options.HTMLAttributes, { data: dec.data }, )) }) - return new AnnotationState(DecorationSet.create(state.doc, decorations)) + this.decorations = DecorationSet.create(state.doc, decorations) + + return this } // Apply ProseMirror mapping - const decorations = this.decorations.map(transaction.mapping, transaction.doc) - return new AnnotationState(decorations) - } + this.decorations = this.decorations.map(transaction.mapping, transaction.doc) - static init(config: any, state: EditorState) { - const decorations = DecorationSet.create(state.doc, []) - - return new AnnotationState(decorations) + return this } } From 2955ef274ae6a5e90dc7678d118d64d2782ceca6 Mon Sep 17 00:00:00 2001 From: Hans Pagel Date: Thu, 11 Feb 2021 23:23:46 +0100 Subject: [PATCH 25/47] annotations: add tasks to AnnotationState --- .../Experiments/Annotation/extension/AnnotationState.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts index 587d22603..2de4e2ede 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts @@ -18,9 +18,17 @@ export class AnnotationState { constructor(options: AnnotationStateOptions) { this.options = options + + // TODO: Observe Y.js changes and re-render decorations + // this.options.map.observe(e => { + // console.log('e', e) + // }) } findAnnotation(id: number) { + // TODO: Get from Y.js? + // this.decorations.get(id) + const current = this.decorations.find() for (let i = 0; i < current.length; i += 1) { From e94ed40ceb06fed7faed4985e29889205c0e5231 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Thu, 11 Feb 2021 23:25:21 +0100 Subject: [PATCH 26/47] add some types --- .../Experiments/Annotation/extension/AnnotationPlugin.ts | 4 ++-- .../Experiments/Annotation/extension/AnnotationState.ts | 3 ++- .../demos/Experiments/Annotation/extension/annotation.ts | 7 ++++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts index 406889f61..65a7440fc 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts @@ -1,3 +1,4 @@ +import * as Y from 'yjs' import { Plugin, PluginKey } from 'prosemirror-state' import { AnnotationState } from './AnnotationState' @@ -8,7 +9,7 @@ export interface AnnotationPluginOptions { [key: string]: any }, onUpdate: (items: [any?]) => {}, - map: any, + map: Y.Map, } export const AnnotationPlugin = (options: AnnotationPluginOptions) => new Plugin({ @@ -41,6 +42,5 @@ export const AnnotationPlugin = (options: AnnotationPluginOptions) => new Plugin return decorations }, - }, }) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts index 587d22603..13d752141 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts @@ -1,4 +1,5 @@ // @ts-nocheck +import * as Y from 'yjs' import { EditorState } from 'prosemirror-state' import { Decoration, DecorationSet } from 'prosemirror-view' import { ySyncPluginKey, relativePositionToAbsolutePosition, absolutePositionToRelativePosition } from 'y-prosemirror' @@ -8,7 +9,7 @@ export interface AnnotationStateOptions { HTMLAttributes: { [key: string]: any }, - map: any, + map: Y.Map, } export class AnnotationState { diff --git a/docs/src/demos/Experiments/Annotation/extension/annotation.ts b/docs/src/demos/Experiments/Annotation/extension/annotation.ts index 019e685d9..91f6a7fbe 100644 --- a/docs/src/demos/Experiments/Annotation/extension/annotation.ts +++ b/docs/src/demos/Experiments/Annotation/extension/annotation.ts @@ -1,3 +1,4 @@ +import * as Y from 'yjs' import { Extension, Command } from '@tiptap/core' import { AnnotationItem } from './AnnotationItem' import { AnnotationPlugin, AnnotationPluginKey } from './AnnotationPlugin' @@ -14,7 +15,7 @@ export interface AnnotationOptions { /** * An initialized Y.js document. */ - document: any, + document: Y.Doc | null, /** * Name of a Y.js fragment, can be changed to sync multiple fields with one Y.js document. */ @@ -22,7 +23,7 @@ export interface AnnotationOptions { /** * A raw Y.js map, can be used instead of `document` and `field`. */ - map: any, + map: Y.Map | null, } export const Annotation = Extension.create({ @@ -74,7 +75,7 @@ export const Annotation = Extension.create({ addProseMirrorPlugins() { const map = this.options.map ? this.options.map - : this.options.document.getMap(this.options.field) + : this.options.document?.getMap(this.options.field) as Y.Map return [ AnnotationPlugin({ From 44c1567a01fc36cd964fb3e07c461738be5c8590 Mon Sep 17 00:00:00 2001 From: Hans Pagel Date: Thu, 11 Feb 2021 23:37:41 +0100 Subject: [PATCH 27/47] docs: update content --- docs/src/docPages/api/commands.md | 23 +++++++++++++++++++++++ docs/src/docPages/api/extensions.md | 6 ++++-- docs/src/pages/index.vue | 14 +++++++------- 3 files changed, 34 insertions(+), 9 deletions(-) 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..022ec27f1 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. 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
From cb8d71dfe66109ac7d38cfd055075bf2e4e7b6e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Thu, 11 Feb 2021 23:47:18 +0100 Subject: [PATCH 28/47] refactoring --- .../Annotation/extension/AnnotationState.ts | 75 +++++++------------ 1 file changed, 29 insertions(+), 46 deletions(-) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts index 6789682e7..154f073f5 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts @@ -44,66 +44,49 @@ export class AnnotationState { } apply(transaction: any, state: EditorState) { + const { map, HTMLAttributes } = this.options const ystate = ySyncPluginKey.getState(state) - const decs = this.options.map - + const { doc, type, binding } = ystate const action = transaction.getMeta(AnnotationPluginKey) - const actionType = action && action.type - if (action) { - const { decorations } = this + if (action && action.type) { + const { from, to, data } = action - if (actionType === 'addAnnotation') { - decs.set(action.data.id, { - from: absolutePositionToRelativePosition( - action.from, - ystate.type, - ystate.binding.mapping, - ), - to: absolutePositionToRelativePosition( - action.to, - ystate.type, - ystate.binding.mapping, - ), - data: action.data, + if (action.type === 'addAnnotation') { + const absoluteFrom = absolutePositionToRelativePosition(from, type, binding.mapping) + const absoluteTo = absolutePositionToRelativePosition(to, type, binding.mapping) + + map.set(data.id, { + from: absoluteFrom, + to: absoluteTo, + data, }) - this.decorations = decorations.add(transaction.doc, [ - Decoration.inline(action.from, action.to, this.options.HTMLAttributes, { data: action.data }), - ]) - } else if (actionType === 'deleteAnnotation') { - decs.delete(action.id) + const decoration = Decoration.inline(from, to, HTMLAttributes, { data }) - this.decorations = decorations.remove([ - this.findAnnotation(action.id), - ]) + this.decorations = this.decorations.add(transaction.doc, [decoration]) + } + + if (action.type === 'deleteAnnotation') { + map.delete(action.id) + + const decoration = this.findAnnotation(action.id) + + this.decorations = this.decorations.remove([decoration]) } return this } - if (ystate && ystate.isChangeOrigin) { - const decorations = []; + if (ystate.isChangeOrigin) { - [...decs.keys()].forEach(id => { - const dec = decs.get(id) + const decorations = Array.from(map.keys()).map(id => { + const dec = map.get(id) + const from = relativePositionToAbsolutePosition(doc, type, dec.from, binding.mapping) + const to = relativePositionToAbsolutePosition(doc, type, dec.to, binding.mapping) + const decoration = Decoration.inline(from, to, HTMLAttributes, { data: dec.data }) - decorations.push(Decoration.inline( - relativePositionToAbsolutePosition( - ystate.doc, - ystate.type, - dec.from, - ystate.binding.mapping, - ), - relativePositionToAbsolutePosition( - ystate.doc, - ystate.type, - dec.to, - ystate.binding.mapping, - ), - this.options.HTMLAttributes, - { data: dec.data }, - )) + return decoration }) this.decorations = DecorationSet.create(state.doc, decorations) From c21b1d2cbc65648e89cc73f7e26feb104d3a4b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Fri, 12 Feb 2021 00:18:15 +0100 Subject: [PATCH 29/47] refactoring --- .../Annotation/extension/AnnotationPlugin.ts | 2 + .../Annotation/extension/AnnotationState.ts | 83 +++++++++++-------- .../Annotation/extension/annotation.ts | 21 ++++- 3 files changed, 70 insertions(+), 36 deletions(-) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts index 65a7440fc..68b08a80b 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts @@ -14,6 +14,7 @@ export interface AnnotationPluginOptions { export const AnnotationPlugin = (options: AnnotationPluginOptions) => new Plugin({ key: AnnotationPluginKey, + state: { init() { return new AnnotationState({ @@ -25,6 +26,7 @@ export const AnnotationPlugin = (options: AnnotationPluginOptions) => new Plugin return pluginState.apply(transaction, newState) }, }, + props: { decorations(state) { const { decorations } = this.getState(state) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts index 154f073f5..45c4073aa 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts @@ -1,8 +1,9 @@ // @ts-nocheck import * as Y from 'yjs' -import { EditorState } from 'prosemirror-state' +import { EditorState, Transaction } from 'prosemirror-state' import { Decoration, DecorationSet } from 'prosemirror-view' import { ySyncPluginKey, relativePositionToAbsolutePosition, absolutePositionToRelativePosition } from 'y-prosemirror' +import { AddAnnotationAction, DeleteAnnotationAction } from './annotation' import { AnnotationPluginKey } from './AnnotationPlugin' export interface AnnotationStateOptions { @@ -39,57 +40,72 @@ export class AnnotationState { } } + addAnnotation(action: AddAnnotationAction, state: EditorState) { + const ystate = ySyncPluginKey.getState(state) + const { type, binding } = ystate + const { map, HTMLAttributes } = this.options + const { from, to, data } = action + const absoluteFrom = absolutePositionToRelativePosition(from, type, binding.mapping) + const absoluteTo = absolutePositionToRelativePosition(to, type, binding.mapping) + + map.set(data.id, { + from: absoluteFrom, + to: absoluteTo, + data, + }) + + const decoration = Decoration.inline(from, to, HTMLAttributes, { data }) + + this.decorations = this.decorations.add(state.doc, [decoration]) + } + + deleteAnnotation(id: number) { + const { map } = this.options + const decoration = this.findAnnotation(id) + + map.delete(id) + this.decorations = this.decorations.remove([decoration]) + } + annotationsAt(position: number) { return this.decorations?.find(position, position) } - apply(transaction: any, state: EditorState) { + updateDecorations(state: EditorState) { const { map, HTMLAttributes } = this.options const ystate = ySyncPluginKey.getState(state) const { doc, type, binding } = ystate - const action = transaction.getMeta(AnnotationPluginKey) + + const decorations = Array.from(map.keys()).map(id => { + const dec = map.get(id) + const from = relativePositionToAbsolutePosition(doc, type, dec.from, binding.mapping) + const to = relativePositionToAbsolutePosition(doc, type, dec.to, binding.mapping) + const decoration = Decoration.inline(from, to, HTMLAttributes, { data: dec.data }) + + return decoration + }) + + this.decorations = DecorationSet.create(state.doc, decorations) + } + + apply(transaction: Transaction, state: EditorState) { + const ystate = ySyncPluginKey.getState(state) + const action = transaction.getMeta(AnnotationPluginKey) as AddAnnotationAction | DeleteAnnotationAction if (action && action.type) { - const { from, to, data } = action - if (action.type === 'addAnnotation') { - const absoluteFrom = absolutePositionToRelativePosition(from, type, binding.mapping) - const absoluteTo = absolutePositionToRelativePosition(to, type, binding.mapping) - - map.set(data.id, { - from: absoluteFrom, - to: absoluteTo, - data, - }) - - const decoration = Decoration.inline(from, to, HTMLAttributes, { data }) - - this.decorations = this.decorations.add(transaction.doc, [decoration]) + this.addAnnotation(action, state) } if (action.type === 'deleteAnnotation') { - map.delete(action.id) - - const decoration = this.findAnnotation(action.id) - - this.decorations = this.decorations.remove([decoration]) + this.deleteAnnotation(action.id) } return this } if (ystate.isChangeOrigin) { - - const decorations = Array.from(map.keys()).map(id => { - const dec = map.get(id) - const from = relativePositionToAbsolutePosition(doc, type, dec.from, binding.mapping) - const to = relativePositionToAbsolutePosition(doc, type, dec.to, binding.mapping) - const decoration = Decoration.inline(from, to, HTMLAttributes, { data: dec.data }) - - return decoration - }) - - this.decorations = DecorationSet.create(state.doc, decorations) + this.updateDecorations(state) return this } @@ -99,4 +115,5 @@ export class AnnotationState { return this } + } diff --git a/docs/src/demos/Experiments/Annotation/extension/annotation.ts b/docs/src/demos/Experiments/Annotation/extension/annotation.ts index 91f6a7fbe..7a6c92c04 100644 --- a/docs/src/demos/Experiments/Annotation/extension/annotation.ts +++ b/docs/src/demos/Experiments/Annotation/extension/annotation.ts @@ -7,6 +7,18 @@ function randomId() { return Math.floor(Math.random() * 0xffffffff) } +export interface AddAnnotationAction { + type: 'addAnnotation', + from: number, + to: number, + data: AnnotationItem, +} + +export interface DeleteAnnotationAction { + id: number, + type: 'deleteAnnotation', +} + export interface AnnotationOptions { HTMLAttributes: { [key: string]: any @@ -49,7 +61,7 @@ export const Annotation = Extension.create({ } if (dispatch && content) { - dispatch(state.tr.setMeta(AnnotationPluginKey, { + state.tr.setMeta(AnnotationPluginKey, { type: 'addAnnotation', from: selection.from, to: selection.to, @@ -57,14 +69,17 @@ export const Annotation = Extension.create({ randomId(), content, ), - })) + }) } return true }, deleteAnnotation: (id: number): Command => ({ dispatch, state }) => { if (dispatch) { - dispatch(state.tr.setMeta(AnnotationPluginKey, { type: 'deleteAnnotation', id })) + state.tr.setMeta(AnnotationPluginKey, { + type: 'deleteAnnotation', + id, + }) } return true From e3a34f78b88acb6e8a8a682905acbea0d8ec2d38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Fri, 12 Feb 2021 00:23:03 +0100 Subject: [PATCH 30/47] fix #155 --- packages/starter-kit/src/index.ts | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) 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, From 92d5b073aef0270c9552d95048402507f21b490f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Fri, 12 Feb 2021 10:18:37 +0100 Subject: [PATCH 31/47] fix types --- .../Annotation/extension/AnnotationItem.ts | 4 +-- .../Annotation/extension/AnnotationState.ts | 33 ++++++++++++------- .../Annotation/extension/annotation.ts | 6 ++-- 3 files changed, 27 insertions(+), 16 deletions(-) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationItem.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationItem.ts index 56b854598..8885247c8 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationItem.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationItem.ts @@ -1,9 +1,9 @@ export class AnnotationItem { - public id!: number + public id!: string public text!: string - constructor(id: number, text: string) { + constructor(id: string, text: string) { this.id = id this.text = text } diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts index 45c4073aa..df26363c1 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import * as Y from 'yjs' import { EditorState, Transaction } from 'prosemirror-state' import { Decoration, DecorationSet } from 'prosemirror-view' @@ -27,7 +26,7 @@ export class AnnotationState { // }) } - findAnnotation(id: number) { + findAnnotation(id: string) { // TODO: Get from Y.js? // this.decorations.get(id) @@ -59,11 +58,16 @@ export class AnnotationState { this.decorations = this.decorations.add(state.doc, [decoration]) } - deleteAnnotation(id: number) { + deleteAnnotation(id: string) { const { map } = this.options const decoration = this.findAnnotation(id) map.delete(id) + + if (!decoration) { + return + } + this.decorations = this.decorations.remove([decoration]) } @@ -75,15 +79,23 @@ export class AnnotationState { const { map, HTMLAttributes } = this.options const ystate = ySyncPluginKey.getState(state) const { doc, type, binding } = ystate + const decorations: Decoration[] = [] - const decorations = Array.from(map.keys()).map(id => { - const dec = map.get(id) - const from = relativePositionToAbsolutePosition(doc, type, dec.from, binding.mapping) - const to = relativePositionToAbsolutePosition(doc, type, dec.to, binding.mapping) - const decoration = Decoration.inline(from, to, HTMLAttributes, { data: dec.data }) + Array + .from(map.keys()) + .forEach(id => { + const dec = map.get(id) + const from = relativePositionToAbsolutePosition(doc, type, dec.from, binding.mapping) + const to = relativePositionToAbsolutePosition(doc, type, dec.to, binding.mapping) - return decoration - }) + if (!from || !to) { + return + } + + const decoration = Decoration.inline(from, to, HTMLAttributes, { data: dec.data }) + + return decorations.push(decoration) + }) this.decorations = DecorationSet.create(state.doc, decorations) } @@ -115,5 +127,4 @@ export class AnnotationState { return this } - } diff --git a/docs/src/demos/Experiments/Annotation/extension/annotation.ts b/docs/src/demos/Experiments/Annotation/extension/annotation.ts index 7a6c92c04..0d80f1c00 100644 --- a/docs/src/demos/Experiments/Annotation/extension/annotation.ts +++ b/docs/src/demos/Experiments/Annotation/extension/annotation.ts @@ -4,7 +4,7 @@ import { AnnotationItem } from './AnnotationItem' import { AnnotationPlugin, AnnotationPluginKey } from './AnnotationPlugin' function randomId() { - return Math.floor(Math.random() * 0xffffffff) + return Math.floor(Math.random() * 0xffffffff).toString() } export interface AddAnnotationAction { @@ -15,7 +15,7 @@ export interface AddAnnotationAction { } export interface DeleteAnnotationAction { - id: number, + id: string, type: 'deleteAnnotation', } @@ -74,7 +74,7 @@ export const Annotation = Extension.create({ return true }, - deleteAnnotation: (id: number): Command => ({ dispatch, state }) => { + deleteAnnotation: (id: string): Command => ({ dispatch, state }) => { if (dispatch) { state.tr.setMeta(AnnotationPluginKey, { type: 'deleteAnnotation', From 8b5dfe7c1cbf7a297abae109a3ec9b8ea67df4c8 Mon Sep 17 00:00:00 2001 From: Hans Pagel Date: Fri, 12 Feb 2021 10:36:58 +0100 Subject: [PATCH 32/47] annotations: update comments --- .../Experiments/Annotation/extension/AnnotationState.ts | 7 +++++-- .../demos/Experiments/Annotation/extension/annotation.ts | 6 +++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts index 45c4073aa..41d5d3192 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts @@ -89,7 +89,7 @@ export class AnnotationState { } apply(transaction: Transaction, state: EditorState) { - const ystate = ySyncPluginKey.getState(state) + // Add/Remove annotations const action = transaction.getMeta(AnnotationPluginKey) as AddAnnotationAction | DeleteAnnotationAction if (action && action.type) { @@ -104,13 +104,16 @@ export class AnnotationState { return this } + // Use Y.js to update positions + const ystate = ySyncPluginKey.getState(state) + if (ystate.isChangeOrigin) { this.updateDecorations(state) return this } - // Apply ProseMirror mapping + // Use ProseMirror to update positions this.decorations = this.decorations.map(transaction.mapping, transaction.doc) return this diff --git a/docs/src/demos/Experiments/Annotation/extension/annotation.ts b/docs/src/demos/Experiments/Annotation/extension/annotation.ts index 7a6c92c04..47e2905ad 100644 --- a/docs/src/demos/Experiments/Annotation/extension/annotation.ts +++ b/docs/src/demos/Experiments/Annotation/extension/annotation.ts @@ -4,6 +4,7 @@ import { AnnotationItem } from './AnnotationItem' import { AnnotationPlugin, AnnotationPluginKey } from './AnnotationPlugin' function randomId() { + // TODO: That seems … to simple. return Math.floor(Math.random() * 0xffffffff) } @@ -23,13 +24,16 @@ 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 fragment, can be changed to sync multiple fields with one Y.js document. + * Name of a Y.js map, can be changed to sync multiple fields with one Y.js document. */ field: string, /** From 39365c77cbf8ee81f766a3fe4e3081be7998cd01 Mon Sep 17 00:00:00 2001 From: Hans Pagel Date: Fri, 12 Feb 2021 10:45:41 +0100 Subject: [PATCH 33/47] annotations: remove comment --- .../demos/Experiments/Annotation/extension/AnnotationState.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts index 6f302127b..af8c7f72d 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts @@ -27,9 +27,6 @@ export class AnnotationState { } findAnnotation(id: string) { - // TODO: Get from Y.js? - // this.decorations.get(id) - const current = this.decorations.find() for (let i = 0; i < current.length; i += 1) { From 0697efef30476076efa90af2f5cb62bec58ec419 Mon Sep 17 00:00:00 2001 From: Hans Pagel Date: Fri, 12 Feb 2021 10:50:21 +0100 Subject: [PATCH 34/47] annotations: refactoring --- .../Experiments/Annotation/extension/AnnotationItem.ts | 6 +++--- .../Experiments/Annotation/extension/AnnotationState.ts | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationItem.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationItem.ts index 8885247c8..f0f0aba46 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationItem.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationItem.ts @@ -1,10 +1,10 @@ export class AnnotationItem { public id!: string - public text!: string + public content!: string - constructor(id: string, text: string) { + constructor(id: string, content: string) { this.id = id - this.text = text + this.content = content } } diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts index af8c7f72d..62a53621b 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts @@ -69,7 +69,7 @@ export class AnnotationState { } annotationsAt(position: number) { - return this.decorations?.find(position, position) + return this.decorations.find(position, position) } updateDecorations(state: EditorState) { @@ -89,9 +89,9 @@ export class AnnotationState { return } - const decoration = Decoration.inline(from, to, HTMLAttributes, { data: dec.data }) - - return decorations.push(decoration) + return decorations.push( + Decoration.inline(from, to, HTMLAttributes, { data: dec.data }), + ) }) this.decorations = DecorationSet.create(state.doc, decorations) From 41cb9924e5fe44f9361d5c1bf7f37d8e918bd136 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Fri, 12 Feb 2021 11:00:23 +0100 Subject: [PATCH 35/47] listen for map changes --- .../Annotation/extension/AnnotationState.ts | 11 ++++---- .../Annotation/extension/annotation.ts | 26 +++++++++++++++---- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts index df26363c1..96141de93 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts @@ -19,11 +19,6 @@ export class AnnotationState { constructor(options: AnnotationStateOptions) { this.options = options - - // TODO: Observe Y.js changes and re-render decorations - // this.options.map.observe(e => { - // console.log('e', e) - // }) } findAnnotation(id: string) { @@ -113,6 +108,12 @@ export class AnnotationState { this.deleteAnnotation(action.id) } + // @ts-ignore + if (action.type === 'updateAnnotations') { + console.log('updateAnnotations!') + this.updateDecorations(state) + } + return this } diff --git a/docs/src/demos/Experiments/Annotation/extension/annotation.ts b/docs/src/demos/Experiments/Annotation/extension/annotation.ts index 0d80f1c00..d24b36e36 100644 --- a/docs/src/demos/Experiments/Annotation/extension/annotation.ts +++ b/docs/src/demos/Experiments/Annotation/extension/annotation.ts @@ -38,6 +38,12 @@ export interface AnnotationOptions { map: Y.Map | null, } +function getMapFromOptions(options: AnnotationOptions): Y.Map { + return options.map + ? options.map + : options.document?.getMap(options.field) as Y.Map +} + export const Annotation = Extension.create({ name: 'annotation', @@ -51,6 +57,20 @@ export const Annotation = Extension.create({ map: null, }, + onCreate() { + const map = getMapFromOptions(this.options) + + map.observe(e => { + console.log('should update annotations', e) + + const transaction = this.editor.state.tr.setMeta(AnnotationPluginKey, { + type: 'updateAnnotations', + }) + + this.editor.view.dispatch(transaction) + }) + }, + addCommands() { return { addAnnotation: (content: any): Command => ({ dispatch, state }) => { @@ -88,15 +108,11 @@ export const Annotation = Extension.create({ }, addProseMirrorPlugins() { - const map = this.options.map - ? this.options.map - : this.options.document?.getMap(this.options.field) as Y.Map - return [ AnnotationPlugin({ HTMLAttributes: this.options.HTMLAttributes, onUpdate: this.options.onUpdate, - map, + map: getMapFromOptions(this.options), }), ] }, From 10fdb79a9d4a7dd0054b9050d1dedd187c4932f1 Mon Sep 17 00:00:00 2001 From: Hans Pagel Date: Fri, 12 Feb 2021 11:18:28 +0100 Subject: [PATCH 36/47] annotations: fix duplicates --- .../Annotation/extension/AnnotationState.ts | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts index e5e180e6c..2c0b566c9 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts @@ -34,7 +34,7 @@ export class AnnotationState { addAnnotation(action: AddAnnotationAction, state: EditorState) { const ystate = ySyncPluginKey.getState(state) const { type, binding } = ystate - const { map, HTMLAttributes } = this.options + const { map } = this.options const { from, to, data } = action const absoluteFrom = absolutePositionToRelativePosition(from, type, binding.mapping) const absoluteTo = absolutePositionToRelativePosition(to, type, binding.mapping) @@ -44,23 +44,12 @@ export class AnnotationState { to: absoluteTo, data, }) - - const decoration = Decoration.inline(from, to, HTMLAttributes, { data }) - - this.decorations = this.decorations.add(state.doc, [decoration]) } deleteAnnotation(id: string) { const { map } = this.options - const decoration = this.findAnnotation(id) map.delete(id) - - if (!decoration) { - return - } - - this.decorations = this.decorations.remove([decoration]) } annotationsAt(position: number) { From b7f25e131cef2f0840041fa81260806b3fac17e5 Mon Sep 17 00:00:00 2001 From: Hans Pagel Date: Fri, 12 Feb 2021 13:27:15 +0100 Subject: [PATCH 37/47] annotations: refactor annotation representation --- .../Annotation/extension/AnnotationItem.ts | 37 ++++++++++++++++--- .../Annotation/extension/AnnotationState.ts | 26 ++++++++----- .../Annotation/extension/annotation.ts | 31 ++++++++++------ .../demos/Experiments/Annotation/index.vue | 32 ++++++++-------- 4 files changed, 85 insertions(+), 41 deletions(-) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationItem.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationItem.ts index f0f0aba46..2f356c31a 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationItem.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationItem.ts @@ -1,10 +1,37 @@ export class AnnotationItem { - public id!: string + private decoration!: any - public content!: string + constructor(decoration: any) { + this.decoration = decoration + } - constructor(id: string, content: string) { - this.id = id - this.content = content + get id() { + return this.decoration.type.spec.id + } + + get from() { + return this.decoration.from + } + + get to() { + return this.decoration.to + } + + get content() { + return this.decoration.type.spec.content + } + + get HTMLAttributes() { + return this.decoration.type.attrs + } + + toString() { + return JSON.stringify({ + id: this.id, + content: this.content, + from: this.from, + to: this.to, + HTMLAttributes: this.HTMLAttributes, + }) } } diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts index 2c0b566c9..471d83636 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts @@ -4,6 +4,7 @@ import { Decoration, DecorationSet } from 'prosemirror-view' import { ySyncPluginKey, relativePositionToAbsolutePosition, absolutePositionToRelativePosition } from 'y-prosemirror' import { AddAnnotationAction, DeleteAnnotationAction } from './annotation' import { AnnotationPluginKey } from './AnnotationPlugin' +import { AnnotationItem } from './AnnotationItem' export interface AnnotationStateOptions { HTMLAttributes: { @@ -21,11 +22,16 @@ export class AnnotationState { 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.data.id === id) { + if (current[i].spec.id === id) { return current[i] } } @@ -35,14 +41,14 @@ export class AnnotationState { const ystate = ySyncPluginKey.getState(state) const { type, binding } = ystate const { map } = this.options - const { from, to, data } = action + const { from, to, content } = action const absoluteFrom = absolutePositionToRelativePosition(from, type, binding.mapping) const absoluteTo = absolutePositionToRelativePosition(to, type, binding.mapping) - map.set(data.id, { + map.set(this.randomId(), { from: absoluteFrom, to: absoluteTo, - data, + content, }) } @@ -53,7 +59,9 @@ export class AnnotationState { } annotationsAt(position: number) { - return this.decorations.find(position, position) + return this.decorations.find(position, position).map(decoration => { + return new AnnotationItem(decoration) + }) } updateDecorations(state: EditorState) { @@ -65,16 +73,16 @@ export class AnnotationState { Array .from(map.keys()) .forEach(id => { - const dec = map.get(id) - const from = relativePositionToAbsolutePosition(doc, type, dec.from, binding.mapping) - const to = relativePositionToAbsolutePosition(doc, type, dec.to, binding.mapping) + const decoration = map.get(id) + const from = relativePositionToAbsolutePosition(doc, type, decoration.from, binding.mapping) + const to = relativePositionToAbsolutePosition(doc, type, decoration.to, binding.mapping) if (!from || !to) { return } return decorations.push( - Decoration.inline(from, to, HTMLAttributes, { data: dec.data }), + Decoration.inline(from, to, HTMLAttributes, { id, content: decoration.content }), ) }) diff --git a/docs/src/demos/Experiments/Annotation/extension/annotation.ts b/docs/src/demos/Experiments/Annotation/extension/annotation.ts index be40a0047..1f9011f4d 100644 --- a/docs/src/demos/Experiments/Annotation/extension/annotation.ts +++ b/docs/src/demos/Experiments/Annotation/extension/annotation.ts @@ -1,23 +1,23 @@ import * as Y from 'yjs' import { Extension, Command } from '@tiptap/core' -import { AnnotationItem } from './AnnotationItem' import { AnnotationPlugin, AnnotationPluginKey } from './AnnotationPlugin' -function randomId() { - // TODO: That seems … to simple. - return Math.floor(Math.random() * 0xffffffff).toString() -} - export interface AddAnnotationAction { type: 'addAnnotation', + content: any, from: number, to: number, - data: AnnotationItem, +} + +export interface UpdateAnnotationAction { + type: 'updateAnnotation', + id: string, + content: any, } export interface DeleteAnnotationAction { - id: string, type: 'deleteAnnotation', + id: string, } export interface AnnotationOptions { @@ -89,10 +89,17 @@ export const Annotation = Extension.create({ type: 'addAnnotation', from: selection.from, to: selection.to, - data: new AnnotationItem( - randomId(), - content, - ), + content, + }) + } + + return true + }, + updateAnnotation: (id: string, content: any): Command => ({ dispatch, state }) => { + if (dispatch) { + state.tr.setMeta(AnnotationPluginKey, { + type: 'updateAnnotation', + content, }) } diff --git a/docs/src/demos/Experiments/Annotation/index.vue b/docs/src/demos/Experiments/Annotation/index.vue index 7ba445ae3..75036cebd 100644 --- a/docs/src/demos/Experiments/Annotation/index.vue +++ b/docs/src/demos/Experiments/Annotation/index.vue @@ -8,10 +8,14 @@ comment -
- {{ comment.type.spec.data }} +
+ {{ comment }} - + +
@@ -23,11 +27,6 @@ comment - -

- Y.js document -

- {{ json }}
@@ -108,19 +107,22 @@ export default { this.editor.commands.addAnnotation(content) }, - addAnotherComment() { - const content = prompt('Comment', '') + updateComment(id) { + const comment = this.comments.find(item => { + return id === item.id + }) - this.anotherEditor.commands.addAnnotation(content) + const content = prompt('Comment', comment.content) + + this.editor.commands.updateAnnotation(id, content) }, deleteComment(id) { this.editor.commands.deleteAnnotation(id) }, - }, + addAnotherComment() { + const content = prompt('Comment', '') - computed: { - json() { - return this.ydoc.toJSON() + this.anotherEditor.commands.addAnnotation(content) }, }, From 370d8deff758099178e71a020fe59eba2d9c1577 Mon Sep 17 00:00:00 2001 From: Hans Pagel Date: Fri, 12 Feb 2021 13:29:12 +0100 Subject: [PATCH 38/47] annotations: rename content to data --- .../Annotation/extension/AnnotationItem.ts | 6 +++--- .../Annotation/extension/AnnotationState.ts | 12 ++++++------ .../Experiments/Annotation/extension/annotation.ts | 14 +++++++------- docs/src/demos/Experiments/Annotation/index.vue | 12 ++++++------ 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationItem.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationItem.ts index 2f356c31a..dfcc92cd1 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationItem.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationItem.ts @@ -17,8 +17,8 @@ export class AnnotationItem { return this.decoration.to } - get content() { - return this.decoration.type.spec.content + get data() { + return this.decoration.type.spec.data } get HTMLAttributes() { @@ -28,7 +28,7 @@ export class AnnotationItem { toString() { return JSON.stringify({ id: this.id, - content: this.content, + data: this.data, from: this.from, to: this.to, HTMLAttributes: this.HTMLAttributes, diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts index 471d83636..9687266a6 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts @@ -41,14 +41,14 @@ export class AnnotationState { const ystate = ySyncPluginKey.getState(state) const { type, binding } = ystate const { map } = this.options - const { from, to, content } = action + 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, - content, + data, }) } @@ -73,16 +73,16 @@ export class AnnotationState { Array .from(map.keys()) .forEach(id => { - const decoration = map.get(id) - const from = relativePositionToAbsolutePosition(doc, type, decoration.from, binding.mapping) - const to = relativePositionToAbsolutePosition(doc, type, decoration.to, binding.mapping) + const annotation = map.get(id) + const from = relativePositionToAbsolutePosition(doc, type, annotation.from, binding.mapping) + const to = relativePositionToAbsolutePosition(doc, type, annotation.to, binding.mapping) if (!from || !to) { return } return decorations.push( - Decoration.inline(from, to, HTMLAttributes, { id, content: decoration.content }), + Decoration.inline(from, to, HTMLAttributes, { id, data: annotation.data }), ) }) diff --git a/docs/src/demos/Experiments/Annotation/extension/annotation.ts b/docs/src/demos/Experiments/Annotation/extension/annotation.ts index 1f9011f4d..6ccddb678 100644 --- a/docs/src/demos/Experiments/Annotation/extension/annotation.ts +++ b/docs/src/demos/Experiments/Annotation/extension/annotation.ts @@ -4,7 +4,7 @@ import { AnnotationPlugin, AnnotationPluginKey } from './AnnotationPlugin' export interface AddAnnotationAction { type: 'addAnnotation', - content: any, + data: any, from: number, to: number, } @@ -12,7 +12,7 @@ export interface AddAnnotationAction { export interface UpdateAnnotationAction { type: 'updateAnnotation', id: string, - content: any, + data: any, } export interface DeleteAnnotationAction { @@ -77,29 +77,29 @@ export const Annotation = Extension.create({ addCommands() { return { - addAnnotation: (content: any): Command => ({ dispatch, state }) => { + addAnnotation: (data: any): Command => ({ dispatch, state }) => { const { selection } = state if (selection.empty) { return false } - if (dispatch && content) { + if (dispatch && data) { state.tr.setMeta(AnnotationPluginKey, { type: 'addAnnotation', from: selection.from, to: selection.to, - content, + data, }) } return true }, - updateAnnotation: (id: string, content: any): Command => ({ dispatch, state }) => { + updateAnnotation: (id: string, data: any): Command => ({ dispatch, state }) => { if (dispatch) { state.tr.setMeta(AnnotationPluginKey, { type: 'updateAnnotation', - content, + data, }) } diff --git a/docs/src/demos/Experiments/Annotation/index.vue b/docs/src/demos/Experiments/Annotation/index.vue index 75036cebd..979bbc3fe 100644 --- a/docs/src/demos/Experiments/Annotation/index.vue +++ b/docs/src/demos/Experiments/Annotation/index.vue @@ -103,26 +103,26 @@ 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 content = prompt('Comment', comment.content) + const data = prompt('Comment', comment.data) - this.editor.commands.updateAnnotation(id, content) + this.editor.commands.updateAnnotation(id, data) }, deleteComment(id) { this.editor.commands.deleteAnnotation(id) }, addAnotherComment() { - const content = prompt('Comment', '') + const data = prompt('Comment', '') - this.anotherEditor.commands.addAnnotation(content) + this.anotherEditor.commands.addAnnotation(data) }, }, From e3c05aa9eb0687b6ccdb4aebc1c338e13173835e Mon Sep 17 00:00:00 2001 From: Hans Pagel Date: Fri, 12 Feb 2021 13:40:42 +0100 Subject: [PATCH 39/47] annotations: add updateAnnotations command --- .../Annotation/extension/AnnotationState.ts | 29 ++++++++++++++----- .../Annotation/extension/annotation.ts | 7 ++--- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts index 9687266a6..08e40771a 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts @@ -2,7 +2,7 @@ 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 } from './annotation' +import { AddAnnotationAction, DeleteAnnotationAction, UpdateAnnotationAction } from './annotation' import { AnnotationPluginKey } from './AnnotationPlugin' import { AnnotationItem } from './AnnotationItem' @@ -52,6 +52,18 @@ export class AnnotationState { }) } + 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 @@ -64,7 +76,7 @@ export class AnnotationState { }) } - updateDecorations(state: EditorState) { + createDecorations(state: EditorState) { const { map, HTMLAttributes } = this.options const ystate = ySyncPluginKey.getState(state) const { doc, type, binding } = ystate @@ -91,21 +103,24 @@ export class AnnotationState { apply(transaction: Transaction, state: EditorState) { // Add/Remove annotations - const action = transaction.getMeta(AnnotationPluginKey) as AddAnnotationAction | DeleteAnnotationAction + const action = transaction.getMeta(AnnotationPluginKey) as AddAnnotationAction | UpdateAnnotationAction | DeleteAnnotationAction if (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 === 'updateAnnotations') { - console.log('updateAnnotations!') - this.updateDecorations(state) + if (action.type === 'createDecorations') { + this.createDecorations(state) } return this @@ -115,7 +130,7 @@ export class AnnotationState { const ystate = ySyncPluginKey.getState(state) if (ystate.isChangeOrigin) { - this.updateDecorations(state) + this.createDecorations(state) return this } diff --git a/docs/src/demos/Experiments/Annotation/extension/annotation.ts b/docs/src/demos/Experiments/Annotation/extension/annotation.ts index 6ccddb678..dd94412bd 100644 --- a/docs/src/demos/Experiments/Annotation/extension/annotation.ts +++ b/docs/src/demos/Experiments/Annotation/extension/annotation.ts @@ -64,11 +64,9 @@ export const Annotation = Extension.create({ onCreate() { const map = getMapFromOptions(this.options) - map.observe(e => { - console.log('should update annotations', e) - + map.observe(() => { const transaction = this.editor.state.tr.setMeta(AnnotationPluginKey, { - type: 'updateAnnotations', + type: 'createDecorations', }) this.editor.view.dispatch(transaction) @@ -99,6 +97,7 @@ export const Annotation = Extension.create({ if (dispatch) { state.tr.setMeta(AnnotationPluginKey, { type: 'updateAnnotation', + id, data, }) } From 97450ebafdf277aba10f9b7c331539b7c874dfc4 Mon Sep 17 00:00:00 2001 From: Hans Pagel Date: Fri, 12 Feb 2021 14:17:08 +0100 Subject: [PATCH 40/47] annotations: add superb logging --- .../Annotation/extension/AnnotationPlugin.ts | 2 ++ .../Annotation/extension/AnnotationState.ts | 11 +++++++++++ .../Experiments/Annotation/extension/annotation.ts | 5 +++++ docs/src/demos/Experiments/Annotation/index.vue | 2 ++ 4 files changed, 20 insertions(+) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts index 68b08a80b..14ac17e36 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts @@ -10,6 +10,7 @@ export interface AnnotationPluginOptions { }, onUpdate: (items: [any?]) => {}, map: Y.Map, + instance: string, } export const AnnotationPlugin = (options: AnnotationPluginOptions) => new Plugin({ @@ -20,6 +21,7 @@ export const AnnotationPlugin = (options: AnnotationPluginOptions) => new Plugin return new AnnotationState({ HTMLAttributes: options.HTMLAttributes, map: options.map, + instance: options.instance, }) }, apply(transaction, pluginState, oldState, newState) { diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts index 08e40771a..eede1f3c7 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts @@ -11,6 +11,7 @@ export interface AnnotationStateOptions { [key: string]: any }, map: Y.Map, + instance: string, } export class AnnotationState { @@ -93,6 +94,12 @@ export class AnnotationState { 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) + } + return decorations.push( Decoration.inline(from, to, HTMLAttributes, { id, data: annotation.data }), ) @@ -106,6 +113,8 @@ export class AnnotationState { 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) } @@ -130,12 +139,14 @@ export class AnnotationState { 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/Annotation/extension/annotation.ts b/docs/src/demos/Experiments/Annotation/extension/annotation.ts index dd94412bd..12f500a9b 100644 --- a/docs/src/demos/Experiments/Annotation/extension/annotation.ts +++ b/docs/src/demos/Experiments/Annotation/extension/annotation.ts @@ -40,6 +40,7 @@ export interface AnnotationOptions { * 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 { @@ -59,12 +60,15 @@ export const Annotation = Extension.create({ 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', }) @@ -123,6 +127,7 @@ export const Annotation = Extension.create({ HTMLAttributes: this.options.HTMLAttributes, onUpdate: this.options.onUpdate, map: getMapFromOptions(this.options), + instance: this.options.instance, }), ] }, diff --git a/docs/src/demos/Experiments/Annotation/index.vue b/docs/src/demos/Experiments/Annotation/index.vue index 979bbc3fe..c2b30cf95 100644 --- a/docs/src/demos/Experiments/Annotation/index.vue +++ b/docs/src/demos/Experiments/Annotation/index.vue @@ -69,6 +69,7 @@ export default { Annotation.configure({ document: this.ydoc, onUpdate: items => { this.comments = items }, + instance: 'editor1', }), Collaboration.configure({ document: this.ydoc, @@ -93,6 +94,7 @@ export default { Heading, Annotation.configure({ document: this.ydoc, + instance: 'editor2', }), Collaboration.configure({ document: this.ydoc, From a69c522455730b4d1463972c14d55c0ec072d54d Mon Sep 17 00:00:00 2001 From: Hans Pagel Date: Fri, 12 Feb 2021 15:02:40 +0100 Subject: [PATCH 41/47] docs: update content --- .../Experiments/Annotation/extension/index.ts | 5 --- .../extension/AnnotationItem.ts | 0 .../extension/AnnotationPlugin.ts | 0 .../extension/AnnotationState.ts | 2 +- .../extension/collaboration-annotation.ts} | 4 +- .../extension/index.ts | 5 +++ .../index.spec.js | 0 .../index.vue | 6 +-- .../api/extensions/collaboration-cursor.md | 6 +-- .../docPages/api/extensions/font-family.md | 6 +-- docs/src/docPages/api/nodes/bullet-list.md | 6 +-- docs/src/docPages/api/nodes/emoji.md | 2 +- docs/src/docPages/api/nodes/hashtag.md | 2 +- docs/src/docPages/api/nodes/list-item.md | 6 +-- docs/src/docPages/api/nodes/ordered-list.md | 6 +-- docs/src/docPages/api/nodes/table-cell.md | 6 +-- docs/src/docPages/api/nodes/table-header.md | 6 +-- docs/src/docPages/api/nodes/table-row.md | 6 +-- docs/src/docPages/api/nodes/table.md | 6 +-- docs/src/docPages/api/nodes/task-item.md | 6 +-- docs/src/docPages/api/nodes/task-list.md | 6 +-- docs/src/docPages/experiments.md | 2 +- .../experiments/collaboration-annotation.md | 40 +++++++++++++++++++ docs/src/docPages/experiments/comments.md | 5 --- docs/src/docPages/guide/accessibility.md | 2 +- docs/src/docPages/guide/toolbar.md | 2 +- docs/src/docPages/introduction.md | 2 +- docs/src/docPages/sponsor.md | 6 +-- 28 files changed, 82 insertions(+), 69 deletions(-) delete mode 100644 docs/src/demos/Experiments/Annotation/extension/index.ts rename docs/src/demos/Experiments/{Annotation => CollaborationAnnotation}/extension/AnnotationItem.ts (100%) rename docs/src/demos/Experiments/{Annotation => CollaborationAnnotation}/extension/AnnotationPlugin.ts (100%) rename docs/src/demos/Experiments/{Annotation => CollaborationAnnotation}/extension/AnnotationState.ts (98%) rename docs/src/demos/Experiments/{Annotation/extension/annotation.ts => CollaborationAnnotation/extension/collaboration-annotation.ts} (96%) create mode 100644 docs/src/demos/Experiments/CollaborationAnnotation/extension/index.ts rename docs/src/demos/Experiments/{Annotation => CollaborationAnnotation}/index.spec.js (100%) rename docs/src/demos/Experiments/{Annotation => CollaborationAnnotation}/index.vue (95%) create mode 100644 docs/src/docPages/experiments/collaboration-annotation.md delete mode 100644 docs/src/docPages/experiments/comments.md diff --git a/docs/src/demos/Experiments/Annotation/extension/index.ts b/docs/src/demos/Experiments/Annotation/extension/index.ts deleted file mode 100644 index 7c86e27d9..000000000 --- a/docs/src/demos/Experiments/Annotation/extension/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Annotation } from './annotation' - -export * from './annotation' - -export default Annotation diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationItem.ts b/docs/src/demos/Experiments/CollaborationAnnotation/extension/AnnotationItem.ts similarity index 100% rename from docs/src/demos/Experiments/Annotation/extension/AnnotationItem.ts rename to docs/src/demos/Experiments/CollaborationAnnotation/extension/AnnotationItem.ts diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts b/docs/src/demos/Experiments/CollaborationAnnotation/extension/AnnotationPlugin.ts similarity index 100% rename from docs/src/demos/Experiments/Annotation/extension/AnnotationPlugin.ts rename to docs/src/demos/Experiments/CollaborationAnnotation/extension/AnnotationPlugin.ts diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts b/docs/src/demos/Experiments/CollaborationAnnotation/extension/AnnotationState.ts similarity index 98% rename from docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts rename to docs/src/demos/Experiments/CollaborationAnnotation/extension/AnnotationState.ts index eede1f3c7..88dfc4166 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts +++ b/docs/src/demos/Experiments/CollaborationAnnotation/extension/AnnotationState.ts @@ -2,7 +2,7 @@ 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 './annotation' +import { AddAnnotationAction, DeleteAnnotationAction, UpdateAnnotationAction } from './collaboration-annotation' import { AnnotationPluginKey } from './AnnotationPlugin' import { AnnotationItem } from './AnnotationItem' diff --git a/docs/src/demos/Experiments/Annotation/extension/annotation.ts b/docs/src/demos/Experiments/CollaborationAnnotation/extension/collaboration-annotation.ts similarity index 96% rename from docs/src/demos/Experiments/Annotation/extension/annotation.ts rename to docs/src/demos/Experiments/CollaborationAnnotation/extension/collaboration-annotation.ts index 12f500a9b..92f0a8d4e 100644 --- a/docs/src/demos/Experiments/Annotation/extension/annotation.ts +++ b/docs/src/demos/Experiments/CollaborationAnnotation/extension/collaboration-annotation.ts @@ -49,7 +49,7 @@ function getMapFromOptions(options: AnnotationOptions): Y.Map { : options.document?.getMap(options.field) as Y.Map } -export const Annotation = Extension.create({ +export const CollaborationAnnotation = Extension.create({ name: 'annotation', defaultOptions: { @@ -135,6 +135,6 @@ export const Annotation = Extension.create({ declare module '@tiptap/core' { interface AllExtensions { - Annotation: typeof Annotation, + Annotation: typeof CollaborationAnnotation, } } 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/Annotation/index.spec.js b/docs/src/demos/Experiments/CollaborationAnnotation/index.spec.js similarity index 100% rename from docs/src/demos/Experiments/Annotation/index.spec.js rename to docs/src/demos/Experiments/CollaborationAnnotation/index.spec.js diff --git a/docs/src/demos/Experiments/Annotation/index.vue b/docs/src/demos/Experiments/CollaborationAnnotation/index.vue similarity index 95% rename from docs/src/demos/Experiments/Annotation/index.vue rename to docs/src/demos/Experiments/CollaborationAnnotation/index.vue index c2b30cf95..97e490b56 100644 --- a/docs/src/demos/Experiments/Annotation/index.vue +++ b/docs/src/demos/Experiments/CollaborationAnnotation/index.vue @@ -40,7 +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 Annotation from './extension' +import CollaborationAnnotation from './extension' export default { components: { @@ -66,7 +66,7 @@ export default { Text, Bold, Heading, - Annotation.configure({ + CollaborationAnnotation.configure({ document: this.ydoc, onUpdate: items => { this.comments = items }, instance: 'editor1', @@ -92,7 +92,7 @@ export default { Text, Bold, Heading, - Annotation.configure({ + CollaborationAnnotation.configure({ document: this.ydoc, instance: 'editor2', }), diff --git a/docs/src/docPages/api/extensions/collaboration-cursor.md b/docs/src/docPages/api/extensions/collaboration-cursor.md index 5750ef317..2e808e5df 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 | | -------- | ---------- | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | 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 fbc633097..bb3f5e589 100644 --- a/docs/src/docPages/experiments.md +++ b/docs/src/docPages/experiments.md @@ -7,7 +7,7 @@ Congratulations! You’ve found our playground with a list of experiments. Be aw * [@tiptap/extension-slash-command?](/experiments/commands) * [@tiptap/extension-iframe?](/experiments/embeds) * [@tiptap/extension-toggle-list?](/experiments/details) -* [@tiptap/extension-collaboration-annotation?](/experiments/comments) +* [@tiptap/extension-collaboration-annotation](/experiments/collaboration-annotation) ## Waiting for approval * [@tiptap/extension-placeholder](/experiments/placeholder) diff --git a/docs/src/docPages/experiments/collaboration-annotation.md b/docs/src/docPages/experiments/collaboration-annotation.md new file mode 100644 index 000000000..e28b4a1b9 --- /dev/null +++ b/docs/src/docPages/experiments/collaboration-annotation.md @@ -0,0 +1,40 @@ +# 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 + + + +## 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/comments.md b/docs/src/docPages/experiments/comments.md deleted file mode 100644 index 0a051e83f..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/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/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) From 55ba1ea4f94f19e6ccda41bfd94c86f676157daf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Fri, 12 Feb 2021 15:12:52 +0100 Subject: [PATCH 42/47] refactoring --- .../demos/Experiments/Annotation/extension/AnnotationState.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts index eede1f3c7..c7615da88 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts @@ -100,7 +100,7 @@ export class AnnotationState { console.warn(`[${this.options.instance}] corrupt decoration `, annotation.from, from, annotation.to, to) } - return decorations.push( + decorations.push( Decoration.inline(from, to, HTMLAttributes, { id, data: annotation.data }), ) }) From 262a1c9815d52e8fe99622328a89116e397511ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Fri, 12 Feb 2021 15:13:40 +0100 Subject: [PATCH 43/47] set inclusiveEnd for decorations --- .../demos/Experiments/Annotation/extension/AnnotationState.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts index c7615da88..7127f042f 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts @@ -101,7 +101,7 @@ export class AnnotationState { } decorations.push( - Decoration.inline(from, to, HTMLAttributes, { id, data: annotation.data }), + Decoration.inline(from, to, HTMLAttributes, { id, data: annotation.data, inclusiveEnd: true }), ) }) From a34e3202e90345d7190a1f2be85ab86d63010718 Mon Sep 17 00:00:00 2001 From: Hans Pagel Date: Fri, 12 Feb 2021 15:18:30 +0100 Subject: [PATCH 44/47] annotations: set decorations to inclusiveEnd --- .../CollaborationAnnotation/extension/AnnotationState.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/src/demos/Experiments/CollaborationAnnotation/extension/AnnotationState.ts b/docs/src/demos/Experiments/CollaborationAnnotation/extension/AnnotationState.ts index 88dfc4166..d458e095a 100644 --- a/docs/src/demos/Experiments/CollaborationAnnotation/extension/AnnotationState.ts +++ b/docs/src/demos/Experiments/CollaborationAnnotation/extension/AnnotationState.ts @@ -101,7 +101,11 @@ export class AnnotationState { } return decorations.push( - Decoration.inline(from, to, HTMLAttributes, { id, data: annotation.data }), + Decoration.inline(from, to, HTMLAttributes, { + id, + data: annotation.data, + inclusiveEnd: true, + }), ) }) From cbb086e4dae792891d40ee43d587a4f6fe374930 Mon Sep 17 00:00:00 2001 From: Hans Pagel Date: Fri, 12 Feb 2021 15:33:58 +0100 Subject: [PATCH 45/47] docs: update content --- docs/src/docPages/api/extensions/collaboration-cursor.md | 2 ++ docs/src/docPages/api/extensions/collaboration.md | 1 + docs/src/docPages/experiments/collaboration-annotation.md | 2 ++ 3 files changed, 5 insertions(+) diff --git a/docs/src/docPages/api/extensions/collaboration-cursor.md b/docs/src/docPages/api/extensions/collaboration-cursor.md index 2e808e5df..271b584a8 100644 --- a/docs/src/docPages/api/extensions/collaboration-cursor.md +++ b/docs/src/docPages/api/extensions/collaboration-cursor.md @@ -40,4 +40,6 @@ This extension requires the [`Collaboration`](/api/extensions/collaboration) ext :::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/experiments/collaboration-annotation.md b/docs/src/docPages/experiments/collaboration-annotation.md index e28b4a1b9..1644d9933 100644 --- a/docs/src/docPages/experiments/collaboration-annotation.md +++ b/docs/src/docPages/experiments/collaboration-annotation.md @@ -4,6 +4,8 @@ ⚠️ 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. + From d7bee8bed9d80961f891d7669e60690fa5c824a9 Mon Sep 17 00:00:00 2001 From: Hans Pagel Date: Fri, 12 Feb 2021 15:40:22 +0100 Subject: [PATCH 46/47] docs: update content --- docs/src/docPages/api/extensions.md | 2 +- docs/src/docPages/guide/extend-extensions.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/docPages/api/extensions.md b/docs/src/docPages/api/extensions.md index 022ec27f1..61cf3a84c 100644 --- a/docs/src/docPages/api/extensions.md +++ b/docs/src/docPages/api/extensions.md @@ -52,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/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: From 34af078be69bd458b68b24770fffbbf82e95a7c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Fri, 12 Feb 2021 15:54:05 +0100 Subject: [PATCH 47/47] refactoring --- .../Annotation/extension/AnnotationState.ts | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts index 7127f042f..ed2cd1afd 100644 --- a/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts +++ b/docs/src/demos/Experiments/Annotation/extension/AnnotationState.ts @@ -83,27 +83,24 @@ export class AnnotationState { const { doc, type, binding } = ystate const decorations: Decoration[] = [] - Array - .from(map.keys()) - .forEach(id => { - const annotation = map.get(id) - const from = relativePositionToAbsolutePosition(doc, type, annotation.from, binding.mapping) - const to = relativePositionToAbsolutePosition(doc, type, annotation.to, binding.mapping) + 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 - } + if (!from || !to) { + return + } - console.log(`[${this.options.instance}] Decoration.inline()`, from, to, HTMLAttributes, { id, data: annotation.data }) + 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) - } + 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 }), - ) - }) + decorations.push( + Decoration.inline(from, to, HTMLAttributes, { id, data: annotation.data, inclusiveEnd: true }), + ) + }) this.decorations = DecorationSet.create(state.doc, decorations) }