import React, { useState } from 'react'
import tippy from 'tippy.js'
import { useEditor, EditorContent, ReactRenderer, ReactNodeViewRenderer, NodeViewWrapper, NodeViewContent } from '@tiptap/react'
import { defaultExtensions } from '@tiptap/starter-kit'
import Heading from '@tiptap/extension-heading'
import Paragraph from '@tiptap/extension-paragraph'
import Mention from '@tiptap/extension-mention'
import './styles.scss'
import { render } from 'react-dom'
const MenuBar = ({ editor }) => {
if (!editor) {
return null
}
return (
<>
editor.chain().focus().toggleBold().run()}
className={editor.isActive('bold') ? 'is-active' : ''}
>
bold
editor.chain().focus().toggleItalic().run()}
className={editor.isActive('italic') ? 'is-active' : ''}
>
italic
editor.chain().focus().toggleStrike().run()}
className={editor.isActive('strike') ? 'is-active' : ''}
>
strike
editor.chain().focus().toggleCode().run()}
className={editor.isActive('code') ? 'is-active' : ''}
>
code
editor.chain().focus().unsetAllMarks().run()}>
clear marks
editor.chain().focus().clearNodes().run()}>
clear nodes
editor.chain().focus().setParagraph().run()}
className={editor.isActive('paragraph') ? 'is-active' : ''}
>
paragraph
editor.chain().focus().toggleHeading({ level: 1 }).run()}
className={editor.isActive('heading', { level: 1 }) ? 'is-active' : ''}
>
h1
editor.chain().focus().toggleHeading({ level: 2 }).run()}
className={editor.isActive('heading', { level: 2 }) ? 'is-active' : ''}
>
h2
editor.chain().focus().toggleHeading({ level: 3 }).run()}
className={editor.isActive('heading', { level: 3 }) ? 'is-active' : ''}
>
h3
editor.chain().focus().toggleHeading({ level: 4 }).run()}
className={editor.isActive('heading', { level: 4 }) ? 'is-active' : ''}
>
h4
editor.chain().focus().toggleHeading({ level: 5 }).run()}
className={editor.isActive('heading', { level: 5 }) ? 'is-active' : ''}
>
h5
editor.chain().focus().toggleHeading({ level: 6 }).run()}
className={editor.isActive('heading', { level: 6 }) ? 'is-active' : ''}
>
h6
editor.chain().focus().toggleBulletList().run()}
className={editor.isActive('bulletList') ? 'is-active' : ''}
>
bullet list
editor.chain().focus().toggleOrderedList().run()}
className={editor.isActive('orderedList') ? 'is-active' : ''}
>
ordered list
editor.chain().focus().toggleCodeBlock().run()}
className={editor.isActive('codeBlock') ? 'is-active' : ''}
>
code block
editor.chain().focus().toggleBlockquote().run()}
className={editor.isActive('blockquote') ? 'is-active' : ''}
>
blockquote
editor.chain().focus().setHorizontalRule().run()}>
horizontal rule
editor.chain().focus().setHardBreak().run()}>
hard break
editor.chain().focus().undo().run()}>
undo
editor.chain().focus().redo().run()}>
redo
>
)
}
const MentionList = (props) => {
console.log({props})
return (
mentions
{props.items.map((item) => (
{item}
))}
)
}
class MentionList2 extends React.Component {
onKeyDown(props) {
console.log('onKeyDown', props)
}
render() {
return (
mentions
{this.props.items.map((item, index) => (
{item}
))}
)
}
}
export default () => {
const [isVisible, setVisible] = useState(true)
const editor = useEditor({
// onTransaction({ editor }) {
// console.log('anchor', editor.state.selection.anchor)
// },
extensions: [
...defaultExtensions().filter(item => item.config.name !== 'heading'),
Heading.extend({
draggable: true,
addNodeView() {
return ReactNodeViewRenderer((props) => {
return (
⠿
level: {props.node.attrs.level}
props.updateAttributes({ level: 1 })}>
set level 1
)
})
}
}),
Mention.configure({
suggestion: {
items: query => {
return [
'Lea Thompson', 'Cyndi Lauper', 'Tom Cruise', 'Madonna', 'Jerry Hall', 'Joan Collins', 'Winona Ryder', 'Christina Applegate', 'Alyssa Milano', 'Molly Ringwald', 'Ally Sheedy', 'Debbie Harry', 'Olivia Newton-John', 'Elton John', 'Michael J. Fox', 'Axl Rose', 'Emilio Estevez', 'Ralph Macchio', 'Rob Lowe', 'Jennifer Grey', 'Mickey Rourke', 'John Cusack', 'Matthew Broderick', 'Justine Bateman', 'Lisa Bonet',
].filter(item => item.toLowerCase().startsWith(query.toLowerCase())).slice(0, 10)
},
render: () => {
let reactRenderer
let popup
return {
onStart: props => {
reactRenderer = new ReactRenderer(MentionList2, {
props,
editor: props.editor,
})
popup = tippy('body', {
getReferenceClientRect: props.clientRect,
appendTo: () => document.body,
content: reactRenderer.element,
showOnCreate: true,
interactive: true,
trigger: 'manual',
placement: 'bottom-start',
})
},
onUpdate(props) {
reactRenderer.updateProps(props)
popup[0].setProps({
getReferenceClientRect: props.clientRect,
})
},
onKeyDown(props) {
return reactRenderer.ref.onKeyDown(props)
},
onExit() {
popup[0].destroy()
reactRenderer.destroy()
},
}
}
},
})
],
content: `
heading
heading
paragraph
`,
// content: `
//
// Hi there,
//
//
// this is a basic basic example of tiptap . Sure, there are all kind of basic text styles you’d probably expect from a text editor. But wait until you see the lists:
//
//
//
// That’s a bullet list with one …
//
//
// … or two list items.
//
//
//
// Isn’t that great? And all of that is editable. But wait, there’s more. Let’s try a code block:
//
// body {
// display: none;
// }
//
// I know, I know, this is impressive. It’s only the tip of the iceberg though. Give it a try and click a little bit around. Don’t forget to check the other examples too.
//
//
// Wow, that’s amazing. Good work, boy! 👏
//
// — Mom
//
// `,
})
return (
setVisible(true)}>visible
setVisible(false)}>hidden
editor.setEditable(true)}>editable
editor.setEditable(false)}>readonly
{isVisible &&
}
)
}