move React components to a package, translate default editor example to React

This commit is contained in:
Hans Pagel 2021-02-26 02:00:35 +01:00
parent 38952fb8c9
commit bf5fb2ad3c
12 changed files with 319 additions and 4 deletions

View File

@ -0,0 +1,167 @@
import React, { useState } from 'react'
import { defaultExtensions } from '@tiptap/starter-kit'
import { useEditor, Editor } from '@tiptap/react'
import './styles.scss'
// useEditor only works for child components of <Editor />
const MenuBar = () => {
const editor = useEditor()
return (
<>
<button
onClick={() => editor.chain().focus().toggleItalic().run()}
className={`${editor.isActive('italic') ? 'active' : ''}`}
>
italic
</button>
<button
onClick={() => editor.chain().focus().toggleStrike().run()}
className={`${editor.isActive('strike') ? 'active' : ''}`}
>
strike
</button>
<button
onClick={() => editor.chain().focus().toggleCode().run()}
className={`${editor.isActive('code') ? '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') ? 'active' : ''}`}
>
paragraph
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}
className={`${editor.isActive('heading', { level: 1 }) ? 'active' : ''}`}
>
h1
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 2 }).run()}
className={`${editor.isActive('heading', { level: 2 }) ? 'active' : ''}`}
>
h2
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 3 }).run()}
className={`${editor.isActive('heading', { level: 3 }) ? 'active' : ''}`}
>
h3
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 4 }).run()}
className={`${editor.isActive('heading', { level: 4 }) ? 'active' : ''}`}
>
h4
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 5 }).run()}
className={`${editor.isActive('heading', { level: 5 }) ? 'active' : ''}`}
>
h5
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 6 }).run()}
className={`${editor.isActive('heading', { level: 6 }) ? 'active' : ''}`}
>
h6
</button>
<button
onClick={() => editor.chain().focus().toggleBulletList().run()}
className={`${editor.isActive('bulletList') ? 'active' : ''}`}
>
bullet list
</button>
<button
onClick={() => editor.chain().focus().toggleOrderedList().run()}
className={`${editor.isActive('orderedList') ? 'active' : ''}`}
>
ordered list
</button>
<button
onClick={() => editor.chain().focus().toggleCodeBlock().run()}
className={`${editor.isActive('codeBlock') ? 'active' : ''}`}
>
code block
</button>
<button
onClick={() => editor.chain().focus().toggleBlockquote().run()}
className={`${editor.isActive('blockquote') ? '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>
<button
onClick={() => editor.chain().focus().toggleBold().run()}
className={`${editor.isActive('bold') ? 'is-active' : ''}`}
>
bold
</button>
</>
)
}
export default () => {
const [value, setValue] = useState(`
<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 (
<>
<Editor
value={value}
onChange={setValue}
extensions={defaultExtensions()}
>
<MenuBar />
</Editor>
</>
)
}

View File

@ -0,0 +1,55 @@
/* Basic editor styles */
.ProseMirror {
> * + * {
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;
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;
}
}

View File

@ -1,6 +1,6 @@
context('/demos/Examples/Default', () => {
context('/demos/Examples/Default/Vue', () => {
before(() => {
cy.visit('/demos/Examples/Default')
cy.visit('/demos/Examples/Default/Vue')
})
beforeEach(() => {

View File

@ -1,6 +1,6 @@
import React, { useState } from 'react'
import { defaultExtensions } from '@tiptap/starter-kit'
import { useEditor, Editor } from './components/Editor'
import { useEditor, Editor } from '@tiptap/react'
// Menu bar example component
// useEditor only works for child components of <Editor />

View File

@ -1,4 +1,8 @@
# Default text editor
Did we mention that you have full control over the rendering of the editor? Here is barebones example without any styling, but packed with a whole set of common extensions.
<demo name="Examples/Default" />
## Vue
<demo name="Examples/Default/Vue" />
## React
<demo name="Examples/Default/React" />

14
packages/react/README.md Normal file
View File

@ -0,0 +1,14 @@
# @tiptap/react
[![Version](https://img.shields.io/npm/v/@tiptap/react.svg?label=version)](https://www.npmjs.com/package/@tiptap/react)
[![Downloads](https://img.shields.io/npm/dm/@tiptap/react.svg)](https://npmcharts.com/compare/tiptap?minimal=true)
[![License](https://img.shields.io/npm/l/@tiptap/react.svg)](https://www.npmjs.com/package/@tiptap/react)
[![Sponsor](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub)](https://github.com/sponsors/ueberdosis)
## Introduction
tiptap is a headless wrapper around [ProseMirror](https://ProseMirror.net) a toolkit for building rich text WYSIWYG editors, which is already in use at many well-known companies such as *New York Times*, *The Guardian* or *Atlassian*.
## Offical Documentation
Documentation can be found on the [tiptap website](https://tiptap.dev).
## License
tiptap is open-sourced software licensed under the [MIT license](https://github.com/ueberdosis/tiptap-next/blob/main/LICENSE.md).

View File

@ -0,0 +1,32 @@
{
"name": "@tiptap/react",
"description": "React components for tiptap",
"version": "2.0.0-alpha.1",
"private": true,
"homepage": "https://tiptap.dev",
"keywords": [
"tiptap",
"tiptap react components"
],
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/ueberdosis"
},
"main": "dist/tiptap-react.cjs.js",
"umd": "dist/tiptap-react.umd.js",
"module": "dist/tiptap-react.esm.js",
"unpkg": "dist/tiptap-react.bundle.umd.min.js",
"types": "dist/packages/react/src/index.d.ts",
"files": [
"src",
"dist"
],
"peerDependencies": {
"@tiptap/core": "^2.0.0-alpha.6",
"react": "^17.0.1"
},
"dependencies": {
"prosemirror-view": "^1.17.6"
}
}

View File

@ -0,0 +1 @@
export default class ReactNodeViewRenderer {}

View File

@ -0,0 +1 @@
export default class ReactRenderer {}

View File

@ -0,0 +1,34 @@
import React, {
useState, useRef, useEffect, createContext, useContext,
} from 'react'
import { Editor as Tiptap } from '@tiptap/core'
export const EditorContext = createContext({})
export const useEditor = () => useContext(EditorContext)
export const Editor = ({
value, onChange, children, ...props
}) => {
const [editor, setEditor] = useState(null)
const editorRef = useRef(null)
useEffect(() => {
const e = new Tiptap({
element: editorRef.current,
content: value,
...props,
}).on('transaction', () => {
onChange(e.getJSON())
})
setEditor(e)
}, [])
return (
<EditorContext.Provider value={editor}>
{editorRef.current && children}
<div ref={editorRef} />
</EditorContext.Provider>
)
}

View File

@ -0,0 +1,7 @@
// @ts-nocheck
export * from '@tiptap/core'
export { default as ReactRenderer } from './ReactRenderer'
export { default as ReactNodeViewRenderer } from './ReactNodeViewRenderer'
export {
Editor, EditorContext, useEditor,
} from './components/Editor'