mirror of
https://github.com/ueberdosis/tiptap.git
synced 2025-01-19 06:43:02 +08:00
docs: update content
This commit is contained in:
parent
4792fc3200
commit
e5866a08cf
@ -12,11 +12,7 @@ import Paragraph from '@tiptap/extension-paragraph'
|
||||
import Text from '@tiptap/extension-text'
|
||||
import Bold from '@tiptap/extension-bold'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
output: '',
|
||||
json: {
|
||||
const json = {
|
||||
type: 'doc',
|
||||
content: [
|
||||
{
|
||||
@ -38,12 +34,12 @@ export default {
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.output = generateHTML(this.json, [
|
||||
export default {
|
||||
computed: {
|
||||
output() {
|
||||
return generateHTML(json, [
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
@ -51,5 +47,6 @@ export default {
|
||||
// other extensions …
|
||||
])
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
77
docs/src/demos/Guide/NodeViews/JavaScript/Extension.js
Normal file
77
docs/src/demos/Guide/NodeViews/JavaScript/Extension.js
Normal file
@ -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
|
||||
/*
|
||||
<div class="node-view">
|
||||
<span class="label">Node view</span>
|
||||
|
||||
<div class="content">
|
||||
<button>
|
||||
This button has been clicked ${node.attrs.count} times.
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
*/
|
||||
|
||||
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,
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
@ -5,7 +5,7 @@
|
||||
<script>
|
||||
import { Editor, EditorContent } from '@tiptap/vue-2'
|
||||
import { defaultExtensions } from '@tiptap/starter-kit'
|
||||
import VueComponent from './index.js'
|
||||
import NodeView from './Extension.js'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@ -22,13 +22,13 @@ export default {
|
||||
this.editor = new Editor({
|
||||
extensions: [
|
||||
...defaultExtensions(),
|
||||
VueComponent,
|
||||
NodeView,
|
||||
],
|
||||
content: `
|
||||
<p>
|
||||
This is still the text editor you’re used to, but enriched with node views.
|
||||
</p>
|
||||
<node-view count="0"></node-view>
|
||||
<node-view></node-view>
|
||||
<p>
|
||||
Did you see that? That’s a JavaScript node view. We are really living in the future.
|
||||
</p>
|
||||
@ -52,7 +52,8 @@ export default {
|
||||
|
||||
::v-deep {
|
||||
.node-view {
|
||||
border: 1px solid #adb5bd;
|
||||
background: #FAF594;
|
||||
border: 3px solid #0D0D0D;
|
||||
border-radius: 0.5rem;
|
||||
margin: 1rem 0;
|
||||
position: relative;
|
||||
@ -60,7 +61,7 @@ export default {
|
||||
|
||||
.label {
|
||||
margin-left: 1rem;
|
||||
background-color: #adb5bd;
|
||||
background-color: #0D0D0D;
|
||||
font-size: 0.6rem;
|
||||
letter-spacing: 1px;
|
||||
font-weight: bold;
|
||||
@ -73,7 +74,8 @@ export default {
|
||||
}
|
||||
|
||||
.content {
|
||||
margin: 2.5rem 1rem 1rem;
|
||||
margin-top: 1.5rem;
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -5,15 +5,7 @@ export default Node.create({
|
||||
|
||||
group: 'block',
|
||||
|
||||
atom: true,
|
||||
|
||||
addAttributes() {
|
||||
return {
|
||||
count: {
|
||||
default: 0,
|
||||
},
|
||||
}
|
||||
},
|
||||
content: 'inline*',
|
||||
|
||||
parseHTML() {
|
||||
return [
|
||||
@ -29,32 +21,32 @@ export default Node.create({
|
||||
|
||||
addNodeView() {
|
||||
return () => {
|
||||
// Markup
|
||||
/*
|
||||
<div class="node-view">
|
||||
<span class="label">Node view</span>
|
||||
|
||||
<div class="content"></div>
|
||||
</div>
|
||||
*/
|
||||
|
||||
const dom = document.createElement('div')
|
||||
dom.classList.add('node-view')
|
||||
|
||||
const label = document.createElement('span')
|
||||
label.classList.add('label')
|
||||
label.innerHTML = 'Node View'
|
||||
label.innerHTML = 'Node view'
|
||||
label.contentEditable = false
|
||||
|
||||
const content = document.createElement('div')
|
||||
content.classList.add('content')
|
||||
content.innerHTML = 'I’m rendered with JavaScript.'
|
||||
|
||||
dom.append(label, content)
|
||||
|
||||
return {
|
||||
dom,
|
||||
contentDOM: content,
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
// <node-view-wrapper class="vue-component">
|
||||
// <span class="label">Vue Component</span>
|
||||
|
||||
// <div class="content">
|
||||
// <button @click="increase">
|
||||
// This button has been clicked {{ node.attrs.count }} times.
|
||||
// </button>
|
||||
// </div>
|
||||
// </node-view-wrapper>
|
85
docs/src/demos/Guide/NodeViews/JavaScriptContent/index.vue
Normal file
85
docs/src/demos/Guide/NodeViews/JavaScriptContent/index.vue
Normal file
@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<editor-content :editor="editor" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { Editor, EditorContent } from '@tiptap/vue-2'
|
||||
import { defaultExtensions } from '@tiptap/starter-kit'
|
||||
import NodeView from './Extension.js'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
EditorContent,
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
editor: null,
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.editor = new Editor({
|
||||
extensions: [
|
||||
...defaultExtensions(),
|
||||
NodeView,
|
||||
],
|
||||
content: `
|
||||
<p>
|
||||
This is still the text editor you’re used to, but enriched with node views.
|
||||
</p>
|
||||
<node-view>
|
||||
<p>This is editable.</p>
|
||||
</node-view>
|
||||
<p>
|
||||
Did you see that? That’s a JavaScript node view. We are really living in the future.
|
||||
</p>
|
||||
`,
|
||||
})
|
||||
},
|
||||
|
||||
beforeDestroy() {
|
||||
this.editor.destroy()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
/* Basic editor styles */
|
||||
.ProseMirror {
|
||||
> * + * {
|
||||
margin-top: 0.75em;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep {
|
||||
.node-view {
|
||||
background: #FAF594;
|
||||
border: 3px solid #0D0D0D;
|
||||
border-radius: 0.5rem;
|
||||
margin: 1rem 0;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.label {
|
||||
margin-left: 1rem;
|
||||
background-color: #0D0D0D;
|
||||
font-size: 0.6rem;
|
||||
letter-spacing: 1px;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
color: #fff;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
padding: 0.25rem 0.75rem;
|
||||
border-radius: 0 0 0.5rem 0.5rem;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin: 2.5rem 1rem 1rem;
|
||||
padding: 0.5rem;
|
||||
border: 2px dashed #0D0D0D20;
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -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
|
||||
<demo name="Guide/Content/GenerateHTML" highlight="6,43-48"/>
|
||||
<demo name="Guide/Content/GenerateHTML" highlight="6-7,42-48"/>
|
||||
|
@ -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.
|
||||
|
||||
<demo name="Guide/Content/GenerateHTML" highlight="6-7,46-52"/>
|
||||
<demo name="Guide/Content/GenerateHTML" highlight="6-7,42-48"/>
|
||||
|
||||
## 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.
|
||||
|
@ -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.
|
||||
|
||||
<demo name="Guide/NodeViews/JavaScript" />
|
||||
|
||||
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:
|
||||
|
||||
<demo name="Guide/NodeViews/JavaScriptContent" />
|
||||
|
||||
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
|
||||
|
@ -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
|
||||
|
||||
<demo name="Guide/NodeViews/VueComponent" />
|
||||
|
||||
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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user