Skip to content

Commit

Permalink
feat(core): apply input and paste rules when using insertContent meth…
Browse files Browse the repository at this point in the history
…ods (#5046)
  • Loading branch information
svenadlung authored Apr 9, 2024
1 parent d8f3404 commit 96b6abc
Show file tree
Hide file tree
Showing 8 changed files with 389 additions and 31 deletions.
Empty file.
178 changes: 178 additions & 0 deletions demos/src/Commands/InsertContentApplyingRules/React/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
import './styles.scss'

import { EditorProvider, useCurrentEditor } from '@tiptap/react'
import StarterKit from '@tiptap/starter-kit'
import React, { useState } from 'react'

const MenuBar = () => {
const { editor } = useCurrentEditor()
const [useInputRules, setUseInputRules] = useState(true)
const [usePasteRules, setUsePasteRules] = useState(false)

if (!editor) {
return null
}

return (
<>
<div>
<button
onClick={() => setUseInputRules(prev => !prev)}
style={{
color: useInputRules ? 'white' : 'inherit',
backgroundColor: useInputRules ? 'black' : 'transparent',
}}
>
Apply Input Rules
</button>
<button
onClick={() => setUsePasteRules(prev => !prev)}
style={{
color: usePasteRules ? 'white' : 'inherit',
backgroundColor: usePasteRules ? 'black' : 'transparent',
}}
>
Apply Paste Rules
</button>
</div>

<br />

<button
onClick={() => {
editor
.chain()
.insertContent('-', {
applyInputRules: useInputRules,
applyPasteRules: usePasteRules,
})
.focus()
.run()
}}
data-test-1
>
Insert "-"
</button>
<button
onClick={() => {
editor
.chain()
.insertContent(' ', {
applyInputRules: useInputRules,
applyPasteRules: usePasteRules,
})
.focus()
.run()
}}
data-test-2
>
Insert " "
</button>
<button
onClick={() => {
editor
.chain()
.insertContent('A', {
applyInputRules: useInputRules,
applyPasteRules: usePasteRules,
})
.focus()
.run()
}}
data-test-3
>
Insert "A"
</button>

<br />

<button
onClick={() => {
editor
.chain()
.insertContent('*this is', {
applyInputRules: useInputRules,
applyPasteRules: usePasteRules,
})
.focus()
.run()
}}
data-test-4
>
Insert "*this is"
</button>
<button
onClick={() => {
editor
.chain()
.insertContent(' a test*', {
applyInputRules: useInputRules,
applyPasteRules: usePasteRules,
})
.focus()
.run()
}}
data-test-5
>
Insert " a test*"
</button>
<button
onClick={() => {
editor
.chain()
.insertContent(' a test*, whooho', {
applyInputRules: useInputRules,
applyPasteRules: usePasteRules,
})
.focus()
.run()
}}
data-test-6
>
Insert " a test*, whooho."
</button>
<button
onClick={() => {
editor
.chain()
.insertContent('*this is a test*, whooho.', {
applyInputRules: useInputRules,
applyPasteRules: usePasteRules,
})
.focus()
.run()
}}
data-test-7
>
Insert "*this is a test*, whooho."
</button>
<button
onClick={() => {
editor
.chain()
.insertContent('*this is a test*', {
applyInputRules: useInputRules,
applyPasteRules: usePasteRules,
})
.focus()
.run()
}}
data-test-8
>
Insert "*this is a test*"
</button>
</>
)
}

const extensions = [
StarterKit,
]

const content = ''

export default () => {
return (
<EditorProvider slotBefore={<MenuBar />} extensions={extensions} content={content}></EditorProvider>
)
}
35 changes: 35 additions & 0 deletions demos/src/Commands/InsertContentApplyingRules/React/index.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
context('/src/Commands/InsertContentApplyingRules/React/', () => {
before(() => {
cy.visit('/src/Commands/InsertContentApplyingRules/React/')
})

beforeEach(() => {
cy.get('.tiptap').then(([{ editor }]) => {
editor.commands.clearContent()
})
})

it('should apply list InputRule', () => {
cy.get('.tiptap').then(([{ editor }]) => {
editor.commands.insertContent('-', {
applyInputRules: true,
})

editor.commands.insertContent(' ', {
applyInputRules: true,
})

cy.get('.tiptap').should('contain.html', '<ul><li><p><br class="ProseMirror-trailingBreak"></p></li></ul>')
})
})

it('should apply markdown using a PasteRule', () => {
cy.get('.tiptap').then(([{ editor }]) => {
editor.commands.insertContentAt(1, '*This is an italic text*', {
applyPasteRules: true,
})

cy.get('.tiptap').should('contain.html', '<p><em>This is an italic text</em></p>')
})
})
})
56 changes: 56 additions & 0 deletions demos/src/Commands/InsertContentApplyingRules/React/styles.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* Basic editor styles */
.tiptap {
> * + * {
margin-top: 0.75em;
}

ul,
ol {
padding: 0 1rem;
}

h1,
h2,
h3,
h4,
h5,
h6 {
line-height: 1.1;
}

code {
background-color: rgba(#616161, 0.1);
color: #616161;
}

pre {
background: #0D0D0D;
color: #FFF;
font-family: 'JetBrainsMono', monospace;
padding: 0.75rem 1rem;
border-radius: 0.5rem;

code {
color: inherit;
padding: 0;
background: none;
font-size: 0.8rem;
}
}

img {
max-width: 100%;
height: auto;
}

blockquote {
padding-left: 1rem;
border-left: 2px solid rgba(#0D0D0D, 0.1);
}

hr {
border: none;
border-top: 2px solid rgba(#0D0D0D, 0.1);
margin: 2rem 0;
}
}
20 changes: 20 additions & 0 deletions packages/core/src/InputRule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,26 @@ export function inputRulesPlugin(props: { editor: Editor; rules: InputRule[] }):
return stored
}

// if InputRule is triggered by insertContent()
const simulatedInputMeta = tr.getMeta('applyInputRules')
const isSimulatedInput = !!simulatedInputMeta

if (isSimulatedInput) {
setTimeout(() => {
const { from, text } = simulatedInputMeta
const to = from + text.length

run({
editor,
from,
to,
text,
rules,
plugin,
})
})
}

return tr.selectionSet || tr.docChanged ? null : prev
},
},
Expand Down
Loading

0 comments on commit 96b6abc

Please sign in to comment.