From 43320e51c74b775f5b0e4acce63f86c6f608c705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Wed, 24 Mar 2021 22:23:08 +0100 Subject: [PATCH 01/11] add isNodeEmpty helper method --- packages/core/src/Editor.ts | 8 +++----- packages/core/src/helpers/isNodeEmpty.ts | 8 ++++++++ packages/core/src/index.ts | 1 + 3 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 packages/core/src/helpers/isNodeEmpty.ts diff --git a/packages/core/src/Editor.ts b/packages/core/src/Editor.ts index 299f24f5..dbc818a5 100644 --- a/packages/core/src/Editor.ts +++ b/packages/core/src/Editor.ts @@ -7,6 +7,7 @@ import getMarkAttributes from './helpers/getMarkAttributes' import isActive from './helpers/isActive' import removeElement from './utilities/removeElement' import getHTMLFromFragment from './helpers/getHTMLFromFragment' +import isNodeEmpty from './helpers/isNodeEmpty' import createStyleTag from './utilities/createStyleTag' import CommandManager from './CommandManager' import ExtensionManager from './ExtensionManager' @@ -415,11 +416,8 @@ export class Editor extends EventEmitter { /** * Check if there is no content. */ - public isEmpty(): boolean { - const defaultContent = this.state.doc.type.createAndFill()?.toJSON() - const content = this.getJSON() - - return JSON.stringify(defaultContent) === JSON.stringify(content) + public get isEmpty(): boolean { + return isNodeEmpty(this.state.doc) } /** diff --git a/packages/core/src/helpers/isNodeEmpty.ts b/packages/core/src/helpers/isNodeEmpty.ts new file mode 100644 index 00000000..86f3c4a1 --- /dev/null +++ b/packages/core/src/helpers/isNodeEmpty.ts @@ -0,0 +1,8 @@ +import { Node as ProseMirrorNode } from 'prosemirror-model' + +export default function isNodeEmpty(node: ProseMirrorNode): boolean { + const defaultContent = node.type.createAndFill()?.toJSON() + const content = node.toJSON() + + return JSON.stringify(defaultContent) === JSON.stringify(content) +} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index e8b91e42..1bd2c738 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -18,6 +18,7 @@ export { default as getMarkAttributes } from './helpers/getMarkAttributes' export { default as isActive } from './helpers/isActive' export { default as isMarkActive } from './helpers/isMarkActive' export { default as isNodeActive } from './helpers/isNodeActive' +export { default as isNodeEmpty } from './helpers/isNodeEmpty' export { default as isNodeSelection } from './helpers/isNodeSelection' export { default as isTextSelection } from './helpers/isTextSelection' export { default as findParentNodeClosestToPos } from './helpers/findParentNodeClosestToPos' From 99d1bd207679cb9fc38c9a7642bef84d22e6f9d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Wed, 24 Mar 2021 22:23:21 +0100 Subject: [PATCH 02/11] improve placeholder --- .../Experiments/Placeholder/extension/placeholder.ts | 11 +++++------ docs/src/demos/Experiments/Placeholder/index.vue | 8 ++------ 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/docs/src/demos/Experiments/Placeholder/extension/placeholder.ts b/docs/src/demos/Experiments/Placeholder/extension/placeholder.ts index 8e011abc..095f4a7d 100644 --- a/docs/src/demos/Experiments/Placeholder/extension/placeholder.ts +++ b/docs/src/demos/Experiments/Placeholder/extension/placeholder.ts @@ -1,4 +1,4 @@ -import { Extension } from '@tiptap/core' +import { Extension, isNodeEmpty } from '@tiptap/core' import { Decoration, DecorationSet } from 'prosemirror-view' import { Plugin } from 'prosemirror-state' @@ -29,7 +29,6 @@ export default Extension.create({ const active = this.editor.isEditable || !this.options.showOnlyWhenEditable const { anchor } = selection const decorations: Decoration[] = [] - const isEditorEmpty = doc.textContent.length === 0 if (!active) { return @@ -37,13 +36,12 @@ export default Extension.create({ doc.descendants((node, pos) => { const hasAnchor = anchor >= pos && anchor <= (pos + node.nodeSize) - // TODO: should be false for image nodes (without text content), is true though - const isNodeEmpty = node.content.size === 0 + const isEmpty = !node.isLeaf && isNodeEmpty(node) - if ((hasAnchor || !this.options.showOnlyCurrent) && isNodeEmpty) { + if ((hasAnchor || !this.options.showOnlyCurrent) && isEmpty) { const classes = [this.options.emptyNodeClass] - if (isEditorEmpty) { + if (this.editor.isEmpty) { classes.push(this.options.emptyEditorClass) } @@ -53,6 +51,7 @@ export default Extension.create({ ? this.options.placeholder(node) : this.options.placeholder, }) + decorations.push(decoration) } diff --git a/docs/src/demos/Experiments/Placeholder/index.vue b/docs/src/demos/Experiments/Placeholder/index.vue index c87895e1..55337c02 100644 --- a/docs/src/demos/Experiments/Placeholder/index.vue +++ b/docs/src/demos/Experiments/Placeholder/index.vue @@ -4,9 +4,7 @@ ``` You don’t need to add those `class` attributes, feel free to remove them or pass other class names. Try it out in the following example: From aa93e973596e364c12dc6a7bc03ad888b720d9cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Thu, 25 Mar 2021 08:32:39 +0100 Subject: [PATCH 08/11] fix focus extension for leaf nodes, fix #223 --- packages/extension-focus/src/focus.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/extension-focus/src/focus.ts b/packages/extension-focus/src/focus.ts index 60c68e3b..2bbb3337 100644 --- a/packages/extension-focus/src/focus.ts +++ b/packages/extension-focus/src/focus.ts @@ -31,13 +31,15 @@ export const FocusClasses = Extension.create({ // Maximum Levels let maxLevels = 0 + if (this.options.mode === 'deepest') { doc.descendants((node, pos) => { if (node.isText) { return } - const isCurrent = anchor >= pos && anchor <= (pos + node.nodeSize) + const isCurrent = anchor >= pos && anchor <= (pos + node.nodeSize - 1) + if (!isCurrent) { return false } @@ -48,12 +50,14 @@ export const FocusClasses = Extension.create({ // Loop through current let currentLevel = 0 + doc.descendants((node, pos) => { if (node.isText) { return false } - const isCurrent = anchor >= pos && anchor <= (pos + node.nodeSize) + const isCurrent = anchor >= pos && anchor <= (pos + node.nodeSize - 1) + if (!isCurrent) { return false } @@ -61,7 +65,7 @@ export const FocusClasses = Extension.create({ currentLevel += 1 const outOfScope = (this.options.mode === 'deepest' && maxLevels - currentLevel > 0) - || (this.options.mode === 'shallowest' && currentLevel > 1) + || (this.options.mode === 'shallowest' && currentLevel > 1) if (outOfScope) { return this.options.mode === 'deepest' From 4f45572369038c2eacd97c84ca53cab982970845 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Thu, 25 Mar 2021 08:34:24 +0100 Subject: [PATCH 09/11] add missing contenteditable --- .../demos/Guide/NodeViews/ReactComponentContent/Component.jsx | 2 +- .../src/demos/Guide/NodeViews/VueComponentContent/Component.vue | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/demos/Guide/NodeViews/ReactComponentContent/Component.jsx b/docs/src/demos/Guide/NodeViews/ReactComponentContent/Component.jsx index 5865a14e..aa8b0370 100644 --- a/docs/src/demos/Guide/NodeViews/ReactComponentContent/Component.jsx +++ b/docs/src/demos/Guide/NodeViews/ReactComponentContent/Component.jsx @@ -4,7 +4,7 @@ import { NodeViewWrapper, NodeViewContent } from '@tiptap/react' export default () => { return ( - React Component + React Component diff --git a/docs/src/demos/Guide/NodeViews/VueComponentContent/Component.vue b/docs/src/demos/Guide/NodeViews/VueComponentContent/Component.vue index e279318a..45aac439 100644 --- a/docs/src/demos/Guide/NodeViews/VueComponentContent/Component.vue +++ b/docs/src/demos/Guide/NodeViews/VueComponentContent/Component.vue @@ -1,6 +1,6 @@