Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: docs: tutorials: adds react examples, makes it possible to add Lexica… #4096

Merged
merged 3 commits into from
Jun 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions demos/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
},
"dependencies": {
"@hocuspocus/provider": "^2.0.1",
"@lexical/react": "^0.11.1",
"d3": "^7.3.0",
"fast-glob": "^3.2.11",
"highlight.js": "^11.6.0",
"lexical": "^0.11.1",
"lowlight": "^2.7.0",
"remixicon": "^2.5.0",
"shiki": "^0.10.0",
Expand Down
2 changes: 1 addition & 1 deletion demos/setup/helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const sendData = (eventName: string, data: any) => {
export function splitName(name: string) {
const parts = name.split('/')

if (parts.length !== 2) {
if (parts.length !== 3) {
throw Error('Demos must always be within exactly one category. Nested categories are not supported.')
}

Expand Down
19 changes: 16 additions & 3 deletions demos/setup/react.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,28 @@ export default function init(name: string, source: any) {
window.source = source
document.title = name

const [demoCategory, demoName] = splitName(name)
const [demoCategory, demoName, frameworkName] = splitName(name)

import(`../src/${demoCategory}/${demoName}/React/index.jsx`)
import(`../src/${demoCategory}/${demoName}/${frameworkName}/index.tsx`)
.then(module => {
const root = document.getElementById('app')

if (root) {
createRoot(root).render(React.createElement(module.default))
createRoot(root)
.render(React.createElement(module.default))
}
debug()
})
.catch(() => {
import(`../src/${demoCategory}/${demoName}/${frameworkName}/index.jsx`)
.then(module => {
const root = document.getElementById('app')

if (root) {
createRoot(root)
.render(React.createElement(module.default))
}
debug()
})
})
}
4 changes: 2 additions & 2 deletions demos/setup/svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ export default function init(name: string, source: any) {
window.source = source
document.title = name

const [demoCategory, demoName] = splitName(name)
const [demoCategory, demoName, frameworkName] = splitName(name)

import(`../src/${demoCategory}/${demoName}/Svelte/index.svelte`)
import(`../src/${demoCategory}/${demoName}/${frameworkName}/index.svelte`)
.then(Module => {
const Component = Module.default

Expand Down
4 changes: 2 additions & 2 deletions demos/setup/vue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ export default function init(name: string, source: any) {
window.source = source
document.title = name

const [demoCategory, demoName] = splitName(name)
const [demoCategory, demoName, frameworkName] = splitName(name)

import(`../src/${demoCategory}/${demoName}/Vue/index.vue`)
import(`../src/${demoCategory}/${demoName}/${frameworkName}/index.vue`)
.then(module => {
createApp(module.default).mount('#app')
debug()
Expand Down
15 changes: 15 additions & 0 deletions demos/src/Tutorials/1-1-textarea/React/Note.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import './styles.css'

import React, { useState } from 'react'

import { TNote } from './types'

export default ({ note }: { note: TNote }) => {
const [modelValue, setModelValue] = useState(note.content)

return (
<textarea onChange={e => setModelValue(e.target.value)} value={modelValue}
className="p-2 border border-black rounded-lg"
></textarea>
)
}
26 changes: 26 additions & 0 deletions demos/src/Tutorials/1-1-textarea/React/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import './styles.css'

import React from 'react'

import Note from './Note'
import { TNote } from './types'

const notes: TNote[] = [
{
id: 'note-1',
content: 'some random note text',
},
{
id: 'note-2',
content: 'some really random note text',
},
]

export default () => {

return (
<div>
{notes.map(note => <Note note={note} key={note.id}/>)}
</div>
)
}
31 changes: 31 additions & 0 deletions demos/src/Tutorials/1-2-tiptap/React/Note.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import './styles.css'

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

import { TNote } from './types'

export default ({ note }: { note: TNote }) => {
const [modelValue, setModelValue] = useState(note.content)

const editor = useEditor({
content: modelValue,
editorProps: {
attributes: {
class: 'm-2 p-2 border border-black rounded-lg',
},
},
onUpdate() {
setModelValue(editor?.getText() ?? '')
},
extensions: [
StarterKit,
],
})

return (
// @ts-ignore
<EditorContent editor={editor}/>
)
}
26 changes: 26 additions & 0 deletions demos/src/Tutorials/1-2-tiptap/React/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import './styles.css'

import React from 'react'

import Note from './Note'
import { TNote } from './types'

const notes: TNote[] = [
{
id: 'note-1',
content: 'some random note text',
},
{
id: 'note-2',
content: 'some really random note text',
},
]

export default () => {

return (
<div>
{notes.map(note => <Note note={note} key={note.id}/>)}
</div>
)
}
4 changes: 4 additions & 0 deletions demos/src/Tutorials/1-2-tiptap/React/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type TNote = {
id: string;
content: string;
};
4 changes: 4 additions & 0 deletions demos/src/Tutorials/1-2-tiptap/Vue/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type TNote = {
id: string;
content: string;
};
36 changes: 36 additions & 0 deletions demos/src/Tutorials/1-2-tiptap_lexical/Lexical-React/Note.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import './styles.css'

import { InitialConfigType, LexicalComposer } from '@lexical/react/LexicalComposer'
import { ContentEditable } from '@lexical/react/LexicalContentEditable'
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary'
import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin'
import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin'
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'
import { EditorState } from 'lexical/LexicalEditorState'
import React, { useRef } from 'react'

import { TNote } from './types'

export default ({ note }: { note: TNote }) => {
const editorStateRef = useRef<EditorState>()

const initialConfig: InitialConfigType = {
onError(error: Error): void {
throw error
},
namespace: 'myeditor',
editable: true,
}

return (
<LexicalComposer initialConfig={initialConfig}>
<RichTextPlugin
contentEditable={<ContentEditable/>}
placeholder={<p>{note.content}</p>}
ErrorBoundary={LexicalErrorBoundary}
/>
<HistoryPlugin/>
<OnChangePlugin onChange={editorState => editorStateRef.current = editorState}/>
</LexicalComposer>
)
}
Empty file.
26 changes: 26 additions & 0 deletions demos/src/Tutorials/1-2-tiptap_lexical/Lexical-React/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import './styles.css'

import React from 'react'

import Note from './Note'
import { TNote } from './types'

const notes: TNote[] = [
{
id: 'note-1',
content: 'some random note text',
},
{
id: 'note-2',
content: 'some really random note text',
},
]

export default () => {

return (
<div>
{notes.map(note => <Note note={note} key={note.id}/>)}
</div>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
4 changes: 4 additions & 0 deletions demos/src/Tutorials/1-2-tiptap_lexical/Lexical-React/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type TNote = {
id: string;
content: string;
};
35 changes: 35 additions & 0 deletions demos/src/Tutorials/1-3-yjs/React/Note.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import './styles.css'

import { Collaboration } from '@tiptap/extension-collaboration'
import { EditorContent, useEditor } from '@tiptap/react'
import { StarterKit } from '@tiptap/starter-kit'
import React from 'react'
import * as Y from 'yjs'

import { TNote } from './types'

export default ({ note }: { note: TNote }) => {
const doc = new Y.Doc()

const editor = useEditor({
content: note.defaultContent,
editorProps: {
attributes: {
class: 'm-2 p-2 border border-black rounded-lg',
},
},
extensions: [
StarterKit.configure({
history: false, // important because history will now be handled by Y.js
}),
Collaboration.configure({
document: doc,
}),
],
})

return (
// @ts-ignore
<EditorContent editor={editor}/>
)
}
Empty file.
26 changes: 26 additions & 0 deletions demos/src/Tutorials/1-3-yjs/React/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import './styles.css'

import React from 'react'

import Note from './Note'
import { TNote } from './types'

const notes: TNote[] = [
{
id: 'note-1',
defaultContent: 'some random note text',
},
{
id: 'note-2',
defaultContent: 'some really random note text',
},
]

export default () => {

return (
<div>
{notes.map(note => <Note note={note} key={note.id}/>)}
</div>
)
}
3 changes: 3 additions & 0 deletions demos/src/Tutorials/1-3-yjs/React/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
Empty file.
3 changes: 3 additions & 0 deletions demos/src/Tutorials/1-3-yjs/Vue/styles.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";
4 changes: 4 additions & 0 deletions demos/src/Tutorials/1-3-yjs/Vue/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export type TNote = {
id: string;
defaultContent: string;
};
52 changes: 52 additions & 0 deletions demos/src/Tutorials/1-3-yjs_lexical/Lexical-React/Note.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import './styles.css'

import { TiptapCollabProvider } from '@hocuspocus/provider'
import { CollaborationPlugin } from '@lexical/react/LexicalCollaborationPlugin'
import { InitialConfigType, LexicalComposer } from '@lexical/react/LexicalComposer'
import { ContentEditable } from '@lexical/react/LexicalContentEditable'
import LexicalErrorBoundary from '@lexical/react/LexicalErrorBoundary'
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'
import React from 'react'
import * as Y from 'yjs'

import { TNote } from './types'

export default ({ note }: { note: TNote }) => {
const initialConfig: InitialConfigType = {
onError(error: Error): void {
throw error
},
namespace: 'myeditor',
editable: true,
}

return (
<LexicalComposer initialConfig={initialConfig}>
<RichTextPlugin
contentEditable={<ContentEditable/>}
placeholder={<p>{note.defaultContent}</p>}
ErrorBoundary={LexicalErrorBoundary}
/>
<CollaborationPlugin
id={note.id}
key={note.id}
// @ts-ignore
providerFactory={(id, yjsDocMap) => {
const doc = new Y.Doc()

yjsDocMap.set(id, doc)

const provider = new TiptapCollabProvider({
name: note.id, // any identifier - all connections sharing the same identifier will be synced
appId: '7j9y6m10', // replace with YOUR_APP_ID
token: 'notoken', // replace with your JWT
document: doc,
})

return provider
}}
shouldBootstrap={true}
/>
</LexicalComposer>
)
}
Empty file.
Loading