Files
tiptap/docs/src/demos/ReactPlayground/index.jsx
Philipp Kühn 57915d8638 fix toggle editor
2021-03-15 14:53:23 +01:00

297 lines
9.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 (
<>
<button
onClick={() => editor.chain().focus().toggleBold().run()}
className={editor.isActive('bold') ? 'is-active' : ''}
>
bold
</button>
<button
onClick={() => editor.chain().focus().toggleItalic().run()}
className={editor.isActive('italic') ? 'is-active' : ''}
>
italic
</button>
<button
onClick={() => editor.chain().focus().toggleStrike().run()}
className={editor.isActive('strike') ? 'is-active' : ''}
>
strike
</button>
<button
onClick={() => editor.chain().focus().toggleCode().run()}
className={editor.isActive('code') ? 'is-active' : ''}
>
code
</button>
<button onClick={() => editor.chain().focus().unsetAllMarks().run()}>
clear marks
</button>
<button onClick={() => editor.chain().focus().clearNodes().run()}>
clear nodes
</button>
<button
onClick={() => editor.chain().focus().setParagraph().run()}
className={editor.isActive('paragraph') ? 'is-active' : ''}
>
paragraph
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}
className={editor.isActive('heading', { level: 1 }) ? 'is-active' : ''}
>
h1
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}
className={editor.isActive('heading', { level: 2 }) ? 'is-active' : ''}
>
h2
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()}
className={editor.isActive('heading', { level: 3 }) ? 'is-active' : ''}
>
h3
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 4 }).run()}
className={editor.isActive('heading', { level: 4 }) ? 'is-active' : ''}
>
h4
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 5 }).run()}
className={editor.isActive('heading', { level: 5 }) ? 'is-active' : ''}
>
h5
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 6 }).run()}
className={editor.isActive('heading', { level: 6 }) ? 'is-active' : ''}
>
h6
</button>
<button
onClick={() => editor.chain().focus().toggleBulletList().run()}
className={editor.isActive('bulletList') ? 'is-active' : ''}
>
bullet list
</button>
<button
onClick={() => editor.chain().focus().toggleOrderedList().run()}
className={editor.isActive('orderedList') ? 'is-active' : ''}
>
ordered list
</button>
<button
onClick={() => editor.chain().focus().toggleCodeBlock().run()}
className={editor.isActive('codeBlock') ? 'is-active' : ''}
>
code block
</button>
<button
onClick={() => editor.chain().focus().toggleBlockquote().run()}
className={editor.isActive('blockquote') ? 'is-active' : ''}
>
blockquote
</button>
<button onClick={() => editor.chain().focus().setHorizontalRule().run()}>
horizontal rule
</button>
<button onClick={() => editor.chain().focus().setHardBreak().run()}>
hard break
</button>
<button onClick={() => editor.chain().focus().undo().run()}>
undo
</button>
<button onClick={() => editor.chain().focus().redo().run()}>
redo
</button>
</>
)
}
const MentionList = (props) => {
console.log({props})
return (
<div>
mentions
{props.items.map((item) => (
<div>
{item}
</div>
))}
</div>
)
}
class MentionList2 extends React.Component {
onKeyDown(props) {
console.log('onKeyDown', props)
}
render() {
return (
<div>
mentions
{this.props.items.map((item, index) => (
<div key={index}>
{item}
</div>
))}
</div>
)
}
}
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 (
<NodeViewWrapper>
<div className="heading">
<span
data-drag-handle
contentEditable={false}
draggable={true}
suppressContentEditableWarning={true}
></span>
level: {props.node.attrs.level}
<button onClick={() => props.updateAttributes({ level: 1 })}>
set level 1
</button>
<NodeViewContent />
</div>
</NodeViewWrapper>
)
})
}
}),
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: `
<h1>heading</h1>
<h2>heading</h2>
<p>paragraph</p>
`,
// content: `
// <h2>
// Hi there,
// </h2>
// <p>
// this is a basic <em>basic</em> example of <strong>tiptap</strong>. Sure, there are all kind of basic text styles youd probably expect from a text editor. But wait until you see the lists:
// </p>
// <ul>
// <li>
// Thats a bullet list with one …
// </li>
// <li>
// … or two list items.
// </li>
// </ul>
// <p>
// Isnt that great? And all of that is editable. But wait, theres more. Lets try a code block:
// </p>
// <pre><code class="language-css">body {
// display: none;
// }</code></pre>
// <p>
// I know, I know, this is impressive. Its only the tip of the iceberg though. Give it a try and click a little bit around. Dont forget to check the other examples too.
// </p>
// <blockquote>
// Wow, thats amazing. Good work, boy! 👏
// <br />
// — Mom
// </blockquote>
// `,
})
return (
<div>
<div>
<button onClick={() => setVisible(true)}>visible</button>
<button onClick={() => setVisible(false)}>hidden</button>
</div>
<div>
<button onClick={() => editor.setEditable(true)}>editable</button>
<button onClick={() => editor.setEditable(false)}>readonly</button>
</div>
<MenuBar editor={editor} />
{isVisible && <EditorContent editor={editor} />}
</div>
)
}