-
Notifications
You must be signed in to change notification settings - Fork 71
/
Copy pathCKEditor.tsx
137 lines (119 loc) · 3.89 KB
/
CKEditor.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import MarkdownEditor, { Editor, EventInfo } from '@joystream/markdown-editor'
import React, { Ref, RefObject, useEffect, useRef } from 'react'
import { useFormContext } from 'react-hook-form'
import { useMentions } from '@/common/hooks/useMentions'
import { CKEditorStylesOverrides } from './CKEditorStylesOverrides'
export interface BaseCKEditorProps {
id?: string
maxRows?: number
minRows?: number
onChange?: (event: EventInfo, editor: Editor) => void
onBlur?: (event: EventInfo, editor: Editor) => void
onFocus?: (event: EventInfo, editor: Editor) => void
onReady?: (editor: Editor) => void
disabled?: boolean
inline?: boolean
}
export const BaseCKEditor = React.forwardRef(
(
{ maxRows = 20, minRows = 5, onChange, onBlur, onFocus, onReady, disabled, inline }: CKEditorProps,
ref?: Ref<HTMLDivElement>
) => {
const localRef = useRef<HTMLDivElement>(null)
const elementRef: RefObject<HTMLDivElement> = (ref ?? localRef) as RefObject<HTMLDivElement>
const editorRef = useRef<Editor | null>(null)
const { mentionMembersFeed, mentionFeed, itemRenderer } = useMentions()
useEffect(() => {
if (!editorRef.current) {
return
}
editorRef.current.isReadOnly = !!disabled
}, [disabled])
useEffect(() => {
const createPromise: Promise<Editor> = (inline ? MarkdownEditor.InlineEditor : MarkdownEditor.ClassicEditor)
.create(elementRef.current || '', {
toolbar: {
items: [
'heading',
'|',
'bold',
'italic',
'link',
'strikethrough',
'|',
'bulletedList',
'numberedList',
'outdent',
'indent',
'|',
'blockQuote',
'undo',
'redo',
],
},
mention: {
feeds: [
{ marker: '@', feed: mentionMembersFeed, minimumCharacters: 1 },
{ marker: '#', feed: mentionFeed, itemRenderer, dropdownLimit: 10 },
],
},
image: {
toolbar: ['imageStyle:full', 'imageStyle:side', '|', 'imageTextAlternative'],
},
// This value must be kept in sync with the language defined in webpack.config.js.
language: 'en',
})
.then((editor: any) => {
if (onReady) {
onReady(editor)
}
editorRef.current = editor
editor.isReadOnly = disabled ?? false
const modelDocument = editor.model.document
const viewDocument = editor.editing.view.document
modelDocument.on('change:data', (event: EventInfo) => {
if (onChange) {
onChange(event, editor)
}
})
viewDocument.on('focus', (event: EventInfo) => {
if (onFocus) {
onFocus(event, editor)
}
})
viewDocument.on('blur', (event: EventInfo) => {
if (onBlur) {
onBlur(event, editor)
}
})
return editor
})
return () => {
createPromise.then((editor) => editor.destroy())
}
}, [elementRef.current])
return (
<>
<CKEditorStylesOverrides maxRows={maxRows} minRows={minRows} />
<div className="ckeditor-anchor" ref={elementRef} />
</>
)
}
)
export interface CKEditorProps extends BaseCKEditorProps {
name?: string
}
export const CKEditor = React.memo(({ name, ...props }: CKEditorProps) => {
const formContext = useFormContext()
if (!formContext || !name) {
return <BaseCKEditor {...props} />
}
const value = formContext.watch(name)
return (
<BaseCKEditor
{...props}
onReady={(editor) => editor.setData(value ?? '')}
onChange={(_, editor) => formContext.setValue(name, editor.getData(), { shouldValidate: true })}
/>
)
})