/
RichTextArea.tsx
71 lines (63 loc) · 2.07 KB
/
RichTextArea.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
import './RichTextArea.css'
import { createComponent, reactive } from '@vue/composition-api'
import { EditorContent, EditorMenuBubble } from 'tiptap'
import MenuItems from './MenuItems'
import useEditor from './useEditor'
const MenuElement = createComponent({
setup(_, { slots, parent }: any) {
return () =>
parent && parent.menu ? (
<div
class={[
'absolute bg-white rounded p-1 border border-solid border-gray-100 shadow mb-2 transform -translate-x-1/2',
'transition-fade ease-in-out duration-150',
{ 'invisible opacity-0': !parent.menu.isActive },
{ 'visible opacity-100': parent.menu.isActive },
]}
style={`left: ${parent.menu.left}px; bottom: ${parent.menu.bottom}px`}
onClick={(e: Event) => { e.preventDefault() /* Prevent form submission */ }}
>
{slots.default()}
</div>
) : <div />
},
})
interface Props {
content: string
onUpdate: (content: string) => any
}
const RichTextArea = createComponent<Props>({
props: {
content: String,
onUpdate: Function,
},
setup(props, { emit, slots }) {
const state = reactive({
editor: useEditor({
content: props.content,
onUpdate: (content) => emit('update', content),
}),
})
const { editor } = state
return () => (
<div class="sm-RichText sm-RichTextArea relative">
{slots.label && <label onClick={() => { editor.focus() }}>{slots.label()}</label>}
<EditorContent
class={[
'h-40 w-full box-border overflow-y-auto cursor-text text-gray-800 text-sm',
'rounded border border-solid transition-colors ease-in-out duration-200',
'border-gray-300 hover:border-gray-500 focus-within:border-primary',
{ 'mt-1': slots.label },
]}
editor={editor}
/>
<EditorMenuBubble editor={editor} >
<MenuElement>
<MenuItems editor={editor} />
</MenuElement>
</EditorMenuBubble>
</div>
)
},
})
export default RichTextArea