From e5866a08cfc9e004a1c02e2ae5dce48307832f22 Mon Sep 17 00:00:00 2001 From: Hans Pagel Date: Sat, 3 Apr 2021 16:13:47 +0200 Subject: [PATCH] docs: update content --- .../Guide/Content/GenerateHTML/index.vue | 71 +++++++------ .../Guide/NodeViews/JavaScript/Extension.js | 77 +++++++++++++++ .../Guide/NodeViews/JavaScript/index.vue | 14 +-- .../Extension.js} | 34 +++---- .../NodeViews/JavaScriptContent/index.vue | 85 ++++++++++++++++ docs/src/docPages/api/utilities/html.md | 2 +- docs/src/docPages/guide/content.md | 2 +- docs/src/docPages/guide/node-views/js.md | 99 +++++++++++++++++-- docs/src/docPages/guide/node-views/vue.md | 8 +- docs/src/links.yaml | 2 +- 10 files changed, 314 insertions(+), 80 deletions(-) create mode 100644 docs/src/demos/Guide/NodeViews/JavaScript/Extension.js rename docs/src/demos/Guide/NodeViews/{JavaScript/index.js => JavaScriptContent/Extension.js} (58%) create mode 100644 docs/src/demos/Guide/NodeViews/JavaScriptContent/index.vue diff --git a/docs/src/demos/Guide/Content/GenerateHTML/index.vue b/docs/src/demos/Guide/Content/GenerateHTML/index.vue index cbc73cb9..1a1e597e 100644 --- a/docs/src/demos/Guide/Content/GenerateHTML/index.vue +++ b/docs/src/demos/Guide/Content/GenerateHTML/index.vue @@ -12,44 +12,41 @@ import Paragraph from '@tiptap/extension-paragraph' import Text from '@tiptap/extension-text' import Bold from '@tiptap/extension-bold' -export default { - data() { - return { - output: '', - json: { - type: 'doc', - content: [ - { - type: 'paragraph', - content: [ - { - type: 'text', - text: 'Example ', - }, - { - type: 'text', - marks: [ - { - type: 'bold', - }, - ], - text: 'Text', - }, - ], - }, - ], - }, - } - }, +const json = { + type: 'doc', + content: [ + { + type: 'paragraph', + content: [ + { + type: 'text', + text: 'Example ', + }, + { + type: 'text', + marks: [ + { + type: 'bold', + }, + ], + text: 'Text', + }, + ], + }, + ], +} - mounted() { - this.output = generateHTML(this.json, [ - Document, - Paragraph, - Text, - Bold, - // other extensions … - ]) +export default { + computed: { + output() { + return generateHTML(json, [ + Document, + Paragraph, + Text, + Bold, + // other extensions … + ]) + }, }, } diff --git a/docs/src/demos/Guide/NodeViews/JavaScript/Extension.js b/docs/src/demos/Guide/NodeViews/JavaScript/Extension.js new file mode 100644 index 00000000..f665e256 --- /dev/null +++ b/docs/src/demos/Guide/NodeViews/JavaScript/Extension.js @@ -0,0 +1,77 @@ +import { Node, mergeAttributes } from '@tiptap/core' + +export default Node.create({ + name: 'nodeView', + + group: 'block', + + atom: true, + + addAttributes() { + return { + count: { + default: 0, + }, + } + }, + + parseHTML() { + return [ + { + tag: 'node-view', + }, + ] + }, + + renderHTML({ HTMLAttributes }) { + return ['node-view', mergeAttributes(HTMLAttributes)] + }, + + addNodeView() { + return ({ editor, node, getPos }) => { + const { view } = editor + + // Markup + /* +
+ Node view + +
+ +
+
+ */ + + const dom = document.createElement('div') + dom.classList.add('node-view') + + const label = document.createElement('span') + label.classList.add('label') + label.innerHTML = 'Node view' + + const content = document.createElement('div') + content.classList.add('content') + + const button = document.createElement('button') + button.innerHTML = `This button has been clicked ${node.attrs.count} times.` + button.addEventListener('click', () => { + if (typeof getPos === 'function') { + view.dispatch(view.state.tr.setNodeMarkup(getPos(), undefined, { + count: node.attrs.count + 1, + })) + + editor.commands.focus() + } + }) + content.append(button) + + dom.append(label, content) + + return { + dom, + } + } + }, +}) diff --git a/docs/src/demos/Guide/NodeViews/JavaScript/index.vue b/docs/src/demos/Guide/NodeViews/JavaScript/index.vue index 53b723be..58cb9d7a 100644 --- a/docs/src/demos/Guide/NodeViews/JavaScript/index.vue +++ b/docs/src/demos/Guide/NodeViews/JavaScript/index.vue @@ -5,7 +5,7 @@ + + diff --git a/docs/src/docPages/api/utilities/html.md b/docs/src/docPages/api/utilities/html.md index 886f41a4..3ecbe958 100644 --- a/docs/src/docPages/api/utilities/html.md +++ b/docs/src/docPages/api/utilities/html.md @@ -8,4 +8,4 @@ The utility helps rendering JSON content as HTML without an editor instance, for [packages/html/](https://github.com/ueberdosis/tiptap-next/blob/main/packages/html/) ## Usage - + diff --git a/docs/src/docPages/guide/content.md b/docs/src/docPages/guide/content.md index 2d68bc80..4621311f 100644 --- a/docs/src/docPages/guide/content.md +++ b/docs/src/docPages/guide/content.md @@ -117,7 +117,7 @@ If you need to render the content on the server side, for example to generate th That’s what the `generateHTML()` is for. It’s a helper function which renders HTML without an actual editor instance. - + ## Migration If you’re migrating existing content to tiptap we would recommend to get your existing output to HTML. That’s probably the best format to get your initial content into tiptap, because ProseMirror ensures there is nothing wrong with it. Even if there are some tags or attributes that aren’t allowed (based on your configuration), tiptap just throws them away quietly. diff --git a/docs/src/docPages/guide/node-views/js.md b/docs/src/docPages/guide/node-views/js.md index 6aaa6da2..962cc803 100644 --- a/docs/src/docPages/guide/node-views/js.md +++ b/docs/src/docPages/guide/node-views/js.md @@ -3,15 +3,25 @@ ## toc ## Introduction -TODO +Using frameworks like Vue or React can feel too complex, if you’re used to work without those two. Good news: You can use plain JavaScript in your node views. There is just a little bit you need to know, but let’s go through this one by one. + +## Render a node view with JavaScript +Here is what you need to do to render a node view inside your editor: + +1. [Create a node extension](/guide/build-extensions) +2. Register a new node view with `addNodeView()` +3. Write your render function +4. [Configure tiptap to use your new node extension](/guide/configuration) + +This is how your node extension could look like: -## Code snippet ```js import { Node } from '@tiptap/core' -import { VueNodeViewRenderer } from '@tiptap/vue-2' import Component from './Component.vue' export default Node.create({ + // configuration … + addNodeView() { return ({ editor, node, getPos, HTMLAttributes, decorations, extension }) => { const dom = document.createElement('div') @@ -26,17 +36,88 @@ export default Node.create({ }) ``` -## Render markup +Got it? Let’s see it in action. Feel free to copy the below example to get started. + +That node view even interacts with the editor. Time to see how that is wired up. + ## Access node attributes -TODO +The editor passes a few helpful things to your render function. One of them is the the `node` prop. This one enables you to access node attributes in your node view. Let’s say you have [added an attribute](/guide/extend-extensions#attributes) named `count` to your node extension. You could access the attribute like this: + +```js +addNodeView() { + return ({ node }) => { + console.log(node.attrs.count) + + // … + } +} +``` + ## Update node attributes -TODO +You can even update node attributes from your node view, with the help of the `getPos` prop passed to your render function. Dispatch a new transaction with an object of the updated attributes: + +```js +addNodeView() { + return ({ editor, node, getPos }) => { + const { view } = editor + + // Create a button … + const button = document.createElement('button') + button.innerHTML = `This button has been clicked ${node.attrs.count} times.` + + // … and when it’s clicked … + button.addEventListener('click', () => { + if (typeof getPos === 'function') { + // … dispatch a transaction, for the current position in the document … + view.dispatch(view.state.tr.setNodeMarkup(getPos(), undefined, { + count: node.attrs.count + 1, + })) + + // … and set the focus back to the editor. + editor.commands.focus() + } + }) + + // … + } +} +``` + +Does seem a little bit too complex? Consider using [React](/guide/node-views/react) or [Vue](/guide/node-views/vue), if you have one of those in your project anyway. It get’s a little bit easier with those two. ## Adding a content editable -TODO +To add editable content to your node view, you need to pass a `contentDOM`, a container element for the content. Here is a simplified version of a node view with non-editable and editable text content: + +```js +// Create a container for the node view +const dom = document.createElement('div') + +// Give other elements containing text `contentEditable = false` +const label = document.createElement('span') +label.innerHTML = 'Node view' +label.contentEditable = false + +// Create a container for the content +const content = document.createElement('div') + +// Append all elements to the node view container +dom.append(label, content) + +return { + // Pass the node view container … + dom, + // … and the content container: + contentDOM: content, +} +``` + +Got it? You’re free to do anything you like, as long as you return a container for the node view and another one for the content. Here is the above example in action: + + + +Keep in mind that this content is rendered by tiptap. That means you need to tell what kind of content is allowed, for example with `content: 'inline*'` in your node extension (that’s what we use in the above example). + -## All available props -TODO diff --git a/docs/src/docPages/guide/node-views/vue.md b/docs/src/docPages/guide/node-views/vue.md index 682de487..2d1eb689 100644 --- a/docs/src/docPages/guide/node-views/vue.md +++ b/docs/src/docPages/guide/node-views/vue.md @@ -3,10 +3,10 @@ ## toc ## Introduction -Using Vanilla JavaScript can feel complex if you are used to work in Vue. Good news: You can use regular Vue components in your node views, too. There is just a little bit you need to know, but let’s go through this one by one. +Using plain JavaScript can feel complex if you are used to work in Vue. Good news: You can use regular Vue components in your node views, too. There is just a little bit you need to know, but let’s go through this one by one. ## Render a Vue component -Here is what you need to do to render Vue components inside your text editor: +Here is what you need to do to render Vue components inside your editor: 1. [Create a node extension](/guide/build-extensions) 2. Create a Vue component @@ -44,7 +44,7 @@ Got it? Let’s see it in action. Feel free to copy the below example to get sta -That component doesn’t interactive with the editor, though. Time to connect it to the editor output. +That component doesn’t interact with the editor, though. Time to wire it up. ## Access node attributes The `VueNodeViewRenderer` which you use in your node extension, passes a few very helpful props to your custom view component. One of them is the `node` prop. Add this snippet to your Vue component to directly access the node: @@ -58,7 +58,7 @@ props: { }, ``` -That makes it super easy to access node attributes in your Vue component. Let’s say you have [added an attribute](/guide/extend-extensions#attributes) named `count` to your node extension (like we did in the above example) you could access it like this: +That enables you to access node attributes in your Vue component. Let’s say you have [added an attribute](/guide/extend-extensions#attributes) named `count` to your node extension (like we did in the above example) you could access it like this: ```js this.node.attrs.count diff --git a/docs/src/links.yaml b/docs/src/links.yaml index 13327e77..c4169d2c 100644 --- a/docs/src/links.yaml +++ b/docs/src/links.yaml @@ -104,7 +104,7 @@ items: - title: With JavaScript link: /guide/node-views/js - type: draft + type: new - title: With React link: /guide/node-views/react type: draft