diff --git a/demos/src/Examples/CustomParagraph/React/Paragraph.jsx b/demos/src/Examples/CustomParagraph/React/Paragraph.jsx new file mode 100644 index 0000000000..cec21f2fd6 --- /dev/null +++ b/demos/src/Examples/CustomParagraph/React/Paragraph.jsx @@ -0,0 +1,25 @@ +import { Paragraph as BaseParagraph } from '@tiptap/extension-paragraph' +import { + NodeViewContent, + NodeViewWrapper, + ReactNodeViewRenderer, +} from '@tiptap/react' + +const ParagraphComponent = ({ node }) => { + return ( + + + {node.textContent.length} + + + + ) +} + +export const Paragraph = BaseParagraph.extend({ + addNodeView() { + return ReactNodeViewRenderer(ParagraphComponent) + }, +}) diff --git a/demos/src/Examples/CustomParagraph/React/index.html b/demos/src/Examples/CustomParagraph/React/index.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/demos/src/Examples/CustomParagraph/React/index.jsx b/demos/src/Examples/CustomParagraph/React/index.jsx new file mode 100644 index 0000000000..67f7df514e --- /dev/null +++ b/demos/src/Examples/CustomParagraph/React/index.jsx @@ -0,0 +1,27 @@ +import './styles.scss' + +import { EditorContent, useEditor } from '@tiptap/react' +import StarterKit from '@tiptap/starter-kit' +import React from 'react' + +import { Paragraph } from './Paragraph.jsx' + +export default () => { + const editor = useEditor({ + extensions: [ + StarterKit.configure({ + paragraph: false, + }), + Paragraph, + ], + content: ` +

+ Each line shows the number of characters in the paragraph. +

+ `, + }) + + return ( + + ) +} diff --git a/demos/src/Examples/CustomParagraph/React/index.spec.js b/demos/src/Examples/CustomParagraph/React/index.spec.js new file mode 100644 index 0000000000..1df3abf8d3 --- /dev/null +++ b/demos/src/Examples/CustomParagraph/React/index.spec.js @@ -0,0 +1,23 @@ +context('/src/Examples/CustomParagraph/React/', () => { + beforeEach(() => { + cy.visit('/src/Examples/CustomParagraph/React/') + }) + + it('should have a working tiptap instance', () => { + cy.get('.ProseMirror').then(([{ editor }]) => { + // eslint-disable-next-line + expect(editor).to.not.be.null + }) + }) + + it('should have a paragraph and text length', () => { + cy.get('.ProseMirror p').should('exist').should('have.text', 'Each line shows the number of characters in the paragraph.') + cy.get('.ProseMirror .label').should('exist').should('have.text', '58') + }) + + it('should have new paragraph', () => { + cy.get('.ProseMirror').type('{selectall}{moveToEnd}{enter}') + cy.get('.ProseMirror p').eq(1).should('exist').should('have.text', '') + cy.get('.ProseMirror .label').eq(1).should('exist').should('have.text', '0') + }) +}) diff --git a/demos/src/Examples/CustomParagraph/React/styles.scss b/demos/src/Examples/CustomParagraph/React/styles.scss new file mode 100644 index 0000000000..85f390477a --- /dev/null +++ b/demos/src/Examples/CustomParagraph/React/styles.scss @@ -0,0 +1,24 @@ +/* Basic editor styles */ +.ProseMirror { + > * + * { + margin-top: 0.75em; + } +} + +/* Placeholder (at the top) */ +/*.ProseMirror p.is-editor-empty:first-child::before { + content: attr(data-placeholder); + float: left; + color: #ced4da; + pointer-events: none; + height: 0; +}*/ + +/* Placeholder (on every new line) */ +.ProseMirror .is-empty::before { + content: attr(data-placeholder); + float: left; + color: #ced4da; + pointer-events: none; + height: 0; +} diff --git a/demos/src/Examples/CustomParagraph/Vue/Component.vue b/demos/src/Examples/CustomParagraph/Vue/Component.vue new file mode 100644 index 0000000000..3dbaeac920 --- /dev/null +++ b/demos/src/Examples/CustomParagraph/Vue/Component.vue @@ -0,0 +1,32 @@ + + + + + diff --git a/demos/src/Examples/CustomParagraph/Vue/Extension.js b/demos/src/Examples/CustomParagraph/Vue/Extension.js new file mode 100644 index 0000000000..cc53c39195 --- /dev/null +++ b/demos/src/Examples/CustomParagraph/Vue/Extension.js @@ -0,0 +1,10 @@ +import { Paragraph as BaseParagraph } from '@tiptap/extension-paragraph' +import { VueNodeViewRenderer } from '@tiptap/vue-3' + +import Component from './Component.vue' + +export default BaseParagraph.extend({ + addNodeView() { + return VueNodeViewRenderer(Component) + }, +}) diff --git a/demos/src/Examples/CustomParagraph/Vue/index.html b/demos/src/Examples/CustomParagraph/Vue/index.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/demos/src/Examples/CustomParagraph/Vue/index.spec.js b/demos/src/Examples/CustomParagraph/Vue/index.spec.js new file mode 100644 index 0000000000..1df3abf8d3 --- /dev/null +++ b/demos/src/Examples/CustomParagraph/Vue/index.spec.js @@ -0,0 +1,23 @@ +context('/src/Examples/CustomParagraph/React/', () => { + beforeEach(() => { + cy.visit('/src/Examples/CustomParagraph/React/') + }) + + it('should have a working tiptap instance', () => { + cy.get('.ProseMirror').then(([{ editor }]) => { + // eslint-disable-next-line + expect(editor).to.not.be.null + }) + }) + + it('should have a paragraph and text length', () => { + cy.get('.ProseMirror p').should('exist').should('have.text', 'Each line shows the number of characters in the paragraph.') + cy.get('.ProseMirror .label').should('exist').should('have.text', '58') + }) + + it('should have new paragraph', () => { + cy.get('.ProseMirror').type('{selectall}{moveToEnd}{enter}') + cy.get('.ProseMirror p').eq(1).should('exist').should('have.text', '') + cy.get('.ProseMirror .label').eq(1).should('exist').should('have.text', '0') + }) +}) diff --git a/demos/src/Examples/CustomParagraph/Vue/index.vue b/demos/src/Examples/CustomParagraph/Vue/index.vue new file mode 100644 index 0000000000..6dfb471955 --- /dev/null +++ b/demos/src/Examples/CustomParagraph/Vue/index.vue @@ -0,0 +1,55 @@ + + + + + +n diff --git a/packages/react/src/EditorContent.tsx b/packages/react/src/EditorContent.tsx index 9f159c5190..0a7ea77323 100644 --- a/packages/react/src/EditorContent.tsx +++ b/packages/react/src/EditorContent.tsx @@ -75,9 +75,7 @@ export class PureEditorContent extends React.Component { - flushSync(fn) - }) + flushSync(fn) } else { fn() }