+
+
+
+
+
diff --git a/docs/src/demos/Experiments/Placeholder/extension/placeholder.ts b/docs/src/demos/Experiments/Placeholder/extension/placeholder.ts
new file mode 100644
index 00000000..a26207e9
--- /dev/null
+++ b/docs/src/demos/Experiments/Placeholder/extension/placeholder.ts
@@ -0,0 +1,67 @@
+import { Extension } from '@tiptap/core'
+import { Decoration, DecorationSet } from 'prosemirror-view'
+import { Plugin } from 'prosemirror-state'
+
+export interface PlaceholderOptions {
+ emptyEditorClass: string,
+ emptyNodeClass: string,
+ placeholder: string | Function,
+ showOnlyWhenEditable: boolean,
+ showOnlyCurrent: boolean,
+}
+
+export default Extension.create({
+ name: 'placeholder',
+
+ defaultOptions: {
+ emptyEditorClass: 'is-editor-empty',
+ emptyNodeClass: 'is-empty',
+ placeholder: 'Write something …',
+ showOnlyWhenEditable: true,
+ showOnlyCurrent: true,
+ },
+
+ addProseMirrorPlugins() {
+ return [
+ new Plugin({
+ props: {
+ decorations: ({ doc, selection }) => {
+ const active = this.editor.isEditable || !this.options.showOnlyWhenEditable
+ const { anchor } = selection
+ const decorations: Decoration[] = []
+ const isEditorEmpty = doc.textContent.length === 0
+
+ if (!active) {
+ return
+ }
+
+ doc.descendants((node, pos) => {
+ const hasAnchor = anchor >= pos && anchor <= (pos + node.nodeSize)
+ const isNodeEmpty = node.content.size === 0
+
+ if ((hasAnchor || !this.options.showOnlyCurrent) && isNodeEmpty) {
+ const classes = [this.options.emptyNodeClass]
+
+ if (isEditorEmpty) {
+ classes.push(this.options.emptyEditorClass)
+ }
+
+ const decoration = Decoration.node(pos, pos + node.nodeSize, {
+ class: classes.join(' '),
+ 'data-empty-text': typeof this.options.placeholder === 'function'
+ ? this.options.placeholder(node)
+ : this.options.placeholder,
+ })
+ decorations.push(decoration)
+ }
+
+ return false
+ })
+
+ return DecorationSet.create(doc, decorations)
+ },
+ },
+ }),
+ ]
+ },
+})
diff --git a/docs/src/demos/Experiments/Placeholder/index.vue b/docs/src/demos/Experiments/Placeholder/index.vue
new file mode 100644
index 00000000..ee22bdd6
--- /dev/null
+++ b/docs/src/demos/Experiments/Placeholder/index.vue
@@ -0,0 +1,56 @@
+
+
+
+
+
+
+
diff --git a/docs/src/demos/Nodes/Image/index.vue b/docs/src/demos/Nodes/Image/index.vue
index 8c59b3bb..6a458dfc 100644
--- a/docs/src/demos/Nodes/Image/index.vue
+++ b/docs/src/demos/Nodes/Image/index.vue
@@ -31,7 +31,9 @@ export default {
addImage() {
const url = window.prompt('URL')
- this.editor.chain().focus().setImage({ src: url }).run()
+ if (url) {
+ this.editor.chain().focus().setImage({ src: url }).run()
+ }
},
},
@@ -68,6 +70,10 @@ export default {
img {
max-width: 100%;
height: auto;
+
+ &.ProseMirror-selectednode {
+ outline: 3px solid #68CEF8;
+ }
}
}
diff --git a/docs/src/docPages/examples/images.md b/docs/src/docPages/examples/images.md
new file mode 100644
index 00000000..28b75739
--- /dev/null
+++ b/docs/src/docPages/examples/images.md
@@ -0,0 +1,3 @@
+# Images
+
+
diff --git a/docs/src/docPages/experiments.md b/docs/src/docPages/experiments.md
index 89d5f090..615e04f6 100644
--- a/docs/src/docPages/experiments.md
+++ b/docs/src/docPages/experiments.md
@@ -7,6 +7,7 @@ Congratulations! You’ve found our secret playground with a list of experiments
* [Comments](/experiments/comments)
* [Color](/experiments/color)
* [Commands](/experiments/commands)
+* [Embeds](/experiments/embeds)
## Waiting for approval
-–
+* [Placeholder](/experiments/placeholder)
diff --git a/docs/src/docPages/experiments/embeds.md b/docs/src/docPages/experiments/embeds.md
new file mode 100644
index 00000000..2b3cb3e5
--- /dev/null
+++ b/docs/src/docPages/experiments/embeds.md
@@ -0,0 +1,5 @@
+# Embeds
+
+⚠️ Experiment
+
+
diff --git a/docs/src/docPages/experiments/placeholder.md b/docs/src/docPages/experiments/placeholder.md
new file mode 100644
index 00000000..fe2e669f
--- /dev/null
+++ b/docs/src/docPages/experiments/placeholder.md
@@ -0,0 +1,5 @@
+# Placeholder
+
+⚠️ Experiment
+
+
diff --git a/docs/src/docPages/guide/collaborative-editing.md b/docs/src/docPages/guide/collaborative-editing.md
index 6323579e..62442302 100644
--- a/docs/src/docPages/guide/collaborative-editing.md
+++ b/docs/src/docPages/guide/collaborative-editing.md
@@ -1,7 +1,7 @@
# Collaborative editing
-:::pro Become a sponsor
-Using collaborative editing in production? Do the right thing and [sponsor our work](/sponsor)!
+:::pro Professionals
+Using the collaborative editing commercially? [Become a sponsor](/sponsor) to fund its development!
:::
## toc
@@ -9,7 +9,7 @@ Using collaborative editing in production? Do the right thing and [sponsor our w
## Introduction
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](https://github.com/yjs/yjs). The following guide explains all things to take into account when you consider to make tiptap collaborative. Don’t worry, a production-grade setup doesn’t require much code.
-## Configure collaboration
+## Configure the editor
The underyling schema tiptap uses is an excellent foundation to sync documents. With the [`Collaboration`](/api/extensions/collaboration) you can tell tiptap to track changes to the document with [Y.js](https://github.com/yjs/yjs).
Y.js is a conflict-free replicated data types implementation, or in other words: It’s reaaally good in merging changes. And to achieve that, changes don’t have to come in order. It’s totally fine to change a document while being offline and merge the it with other changes when the device is online again.
@@ -209,17 +209,13 @@ All changes will be stored in the browser then, even if you close the tab, go of
Yes, it’s magic. As already mentioned, that is all based on the fantastic Y.js framework. And if you’re using it, or our integration, you should definitely [sponsor Kevin Jahns on GitHub](https://github.com/dmonad), he is the brain behind Y.js.
-## Store the content
+## A plug & play backend
Our collaborative editing backend is ready to handle advanced use cases, like authorization, persistence and scaling. Let’s go through a few common use cases here!
+### Where is it?
:::warning Work in progress
-Our plug & play collaboration backend hocuspocus is still work in progress. We’re setting up a dedicated website and documentation, and need to add one or two features before publishing it.
-
-If you want to give it a try, send us an email to humans@tiptap.dev to receive early access.
+Our plug & play collaboration backend hocuspocus is still work in progress. If you want to give it a try, send us an email to [humans@tiptap.dev](mailto:humans@tiptap.dev) to receive early access.
:::
-
### The document name
The document name is `'example-document'` in all examples here, but it could be any string. In a real-world app you’d probably add the name of your entity and the ID of the entity. Here is how that could look like:
diff --git a/docs/src/index.html b/docs/src/index.html
index 187c7f34..e175def8 100644
--- a/docs/src/index.html
+++ b/docs/src/index.html
@@ -7,6 +7,10 @@
${app}
${scripts}
+ ${process.env.NODE_ENV === 'production'
+ ? ''
+ : ''
+ }
${process.env.NODE_ENV === 'production'
? ''
: ''
diff --git a/docs/src/links.yaml b/docs/src/links.yaml
index 37fbafee..586a5b41 100644
--- a/docs/src/links.yaml
+++ b/docs/src/links.yaml
@@ -41,6 +41,9 @@
- title: Tables
link: /examples/tables
type: draft
+ - title: Images
+ link: /examples/images
+ type: draft
- title: Guide
items:
diff --git a/docs/src/pages/404.vue b/docs/src/pages/404.vue
index 5572250e..9784d8f9 100644
--- a/docs/src/pages/404.vue
+++ b/docs/src/pages/404.vue
@@ -1,17 +1,24 @@
- Oh no, page not found.
-
- → Back
-
+
+ Oh no, we can’t find this page.
+
+ → Go back
+
+