diff --git a/public/icons/editor-image-dd-full.svg b/public/icons/editor-image-dd-full.svg
new file mode 100644
index 00000000..5f5cffe8
--- /dev/null
+++ b/public/icons/editor-image-dd-full.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/components/Article/AudioPlayer/PlayerPlaylist.tsx b/src/components/Article/AudioPlayer/PlayerPlaylist.tsx
index 46e2a4bf..917d8ed0 100644
--- a/src/components/Article/AudioPlayer/PlayerPlaylist.tsx
+++ b/src/components/Article/AudioPlayer/PlayerPlaylist.tsx
@@ -8,6 +8,7 @@ import styles from './AudioPlayer.module.scss'
import { GrowingTextarea } from '../../_shared/GrowingTextarea'
import MD from '../MD'
import { MediaItem } from '../../../pages/types'
+import SimplifiedEditor from '../../Editor/SimplifiedEditor'
type Props = {
media: MediaItem[]
@@ -145,7 +146,6 @@ export const PlayerPlaylist = (props: Props) => {
- {/*FIXME*/}
@@ -158,12 +158,11 @@ export const PlayerPlaylist = (props: Props) => {
}
>
-
handleMediaItemFieldChange('body', value)}
placeholder={t('Description')}
- value={(value) => handleMediaItemFieldChange('body', value)}
- initialValue={mi.body || ''}
+ smallHeight={true}
/>
import('../_shared/CommentEditor'))
+const SimplifiedEditor = lazy(() => import('../Editor/SimplifiedEditor'))
type Props = {
comment: Reaction
@@ -34,7 +34,6 @@ export const Comment = (props: Props) => {
const [isReplyVisible, setIsReplyVisible] = createSignal(false)
const [loading, setLoading] = createSignal(false)
const [editMode, setEditMode] = createSignal(false)
- const [submitted, setSubmitted] = createSignal(false)
const { session } = useSession()
const {
@@ -71,7 +70,6 @@ export const Comment = (props: Props) => {
})
setIsReplyVisible(false)
setLoading(false)
- setSubmitted(true)
} catch (error) {
console.error('[handleCreate reaction]:', error)
}
@@ -160,7 +158,13 @@ export const Comment = (props: Props) => {
}>
{t('Loading')}}>
- handleUpdate(value)} />
+ handleUpdate(value)}
+ submitByShiftEnter={true}
+ />
@@ -216,11 +220,12 @@ export const Comment = (props: Props) => {
{t('Loading')}}>
- handleCreate(value)}
- cancel={() => setIsReplyVisible(false)}
+ submitByShiftEnter={true}
/>
diff --git a/src/components/Article/CommentsTree.tsx b/src/components/Article/CommentsTree.tsx
index 05ce0e97..947c1144 100644
--- a/src/components/Article/CommentsTree.tsx
+++ b/src/components/Article/CommentsTree.tsx
@@ -4,12 +4,12 @@ import styles from './Article.module.scss'
import { clsx } from 'clsx'
import { Author, Reaction, ReactionKind } from '../../graphql/types.gen'
import { useSession } from '../../context/session'
-import CommentEditor from '../_shared/CommentEditor'
import { Button } from '../_shared/Button'
import { useReactions } from '../../context/reactions'
import { byCreated } from '../../utils/sortby'
import { ShowIfAuthenticated } from '../_shared/ShowIfAuthenticated'
import { useLocalize } from '../../context/localize'
+import SimplifiedEditor from '../Editor/SimplifiedEditor'
type CommentsOrder = 'createdAt' | 'rating' | 'newOnly'
@@ -172,10 +172,12 @@ export const CommentsTree = (props: Props) => {
}
>
-
handleSubmitComment(value)}
+ submitByShiftEnter={true}
/>
>
diff --git a/src/components/Editor/Editor.tsx b/src/components/Editor/Editor.tsx
index 6ddd9ab3..ee65ddb9 100644
--- a/src/components/Editor/Editor.tsx
+++ b/src/components/Editor/Editor.tsx
@@ -1,4 +1,4 @@
-import { createEffect, createSignal } from 'solid-js'
+import { createEffect, createSignal, onMount } from 'solid-js'
import { createTiptapEditor, useEditorHTML } from 'solid-tiptap'
import { useLocalize } from '../../context/localize'
import { Bold } from '@tiptap/extension-bold'
@@ -43,6 +43,7 @@ import type { Doc } from 'yjs/dist/src/utils/Doc'
import './Prosemirror.scss'
import { TrailingNode } from './extensions/TrailingNode'
import Article from './extensions/Article'
+import styles from './SimplifiedEditor.module.scss'
type EditorProps = {
shoutId: number
@@ -218,6 +219,10 @@ export const Editor = (props: EditorProps) => {
]
}))
+ onMount(() => {
+ editor().view.dom.classList.add('articleEditor')
+ })
+
const {
actions: { countWords, setEditor }
} = useEditorContext()
diff --git a/src/components/Editor/InsertLinkForm/InsertLinkForm.tsx b/src/components/Editor/InsertLinkForm/InsertLinkForm.tsx
new file mode 100644
index 00000000..5ef0df3f
--- /dev/null
+++ b/src/components/Editor/InsertLinkForm/InsertLinkForm.tsx
@@ -0,0 +1,55 @@
+import { Editor } from '@tiptap/core'
+import { validateUrl } from '../../../utils/validateUrl'
+import { hideModal } from '../../../stores/ui'
+import { InlineForm } from '../InlineForm'
+import { useLocalize } from '../../../context/localize'
+import { createEditorTransaction } from 'solid-tiptap'
+
+type Props = {
+ editor: Editor
+}
+
+export const checkUrl = (url) => {
+ try {
+ new URL(url)
+ return url
+ } catch {
+ return `https://${url}`
+ }
+}
+
+export const InsertLinkForm = (props: Props) => {
+ const { t } = useLocalize()
+ const currentUrl = createEditorTransaction(
+ () => props.editor,
+ (ed) => {
+ return (ed && ed.getAttributes('link').href) || ''
+ }
+ )
+ const handleClearLinkForm = () => {
+ if (currentUrl()) {
+ props.editor.chain().focus().unsetLink().run()
+ }
+ }
+
+ const handleLinkFormSubmit = (value: string) => {
+ props.editor
+ .chain()
+ .focus()
+ .setLink({ href: checkUrl(value) })
+ .run()
+ }
+
+ return (
+
+ (validateUrl(value) ? '' : t('Invalid url format'))}
+ onSubmit={handleLinkFormSubmit}
+ onClose={() => hideModal()}
+ />
+
+ )
+}
diff --git a/src/components/Editor/InsertLinkForm/index.ts b/src/components/Editor/InsertLinkForm/index.ts
new file mode 100644
index 00000000..4cf74dea
--- /dev/null
+++ b/src/components/Editor/InsertLinkForm/index.ts
@@ -0,0 +1 @@
+export { InsertLinkForm } from './InsertLinkForm'
diff --git a/src/components/Editor/Prosemirror.scss b/src/components/Editor/Prosemirror.scss
index 45fabb41..a2890a03 100644
--- a/src/components/Editor/Prosemirror.scss
+++ b/src/components/Editor/Prosemirror.scss
@@ -17,10 +17,10 @@
// Keeping the cursor active when moving outside the editable area
-.ProseMirror p,
-.ProseMirror ul,
-.ProseMirror h4,
-.ProseMirror ol {
+.articleEditor p,
+.articleEditor ul,
+.articleEditor h4,
+.articleEditor ol {
box-sizing: content-box;
flex: 0 0 auto;
@@ -34,8 +34,8 @@
}
}
-.ProseMirror blockquote,
-.ProseMirror article[data-type='incut'] {
+.articleEditor blockquote,
+.articleEditor article[data-type='incut'] {
@media (min-width: 768px) {
margin-left: calc(21.9% + 3px) !important;
max-width: 73.6%;
@@ -46,7 +46,7 @@
}
}
-.ProseMirror h2 {
+.articleEditor h2 {
@media (min-width: 768px) {
padding-left: calc(21.9% + 2px);
max-width: 72.7%;
@@ -57,7 +57,7 @@
}
}
-.ProseMirror h3 {
+.articleEditor h3 {
@media (min-width: 768px) {
padding-left: calc(21.9% + 2px);
}
@@ -67,10 +67,10 @@
}
}
-.ProseMirror * p,
-.ProseMirror * h2,
-.ProseMirror * h3,
-.ProseMirror * h4 {
+.articleEditor * p,
+.articleEditor * h2,
+.articleEditor * h3,
+.articleEditor * h4 {
@media (min-width: 768px) {
padding-left: unset;
max-width: unset;
diff --git a/src/components/Editor/SimplifiedEditor.module.scss b/src/components/Editor/SimplifiedEditor.module.scss
new file mode 100644
index 00000000..df85659b
--- /dev/null
+++ b/src/components/Editor/SimplifiedEditor.module.scss
@@ -0,0 +1,100 @@
+.SimplifiedEditor {
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ background: var(--black-50);
+ border-radius: 16px;
+ padding: 16px 16px 8px;
+
+ .simplifiedEditorField {
+ @include font-size(1.4rem);
+ min-height: 100px;
+
+ .emptyNode:first-child::before {
+ @include font-size(1.4rem);
+
+ position: absolute;
+ top: 4px;
+ height: 0;
+ pointer-events: none;
+ margin-top: -4px;
+ color: var(--black-400);
+ content: attr(data-placeholder);
+ }
+ }
+
+ &.smallHeight .simplifiedEditorField {
+ min-height: 34px;
+ }
+
+ & * :focus {
+ outline: none;
+ }
+
+ .blockQuote {
+ font-weight: 500;
+ color: var(--black-500);
+ border-left: 2px solid #696969;
+ padding: 0 0 0 8px;
+ margin: 0;
+
+ p {
+ margin: 0;
+ }
+ }
+
+ .uploadedImage {
+ max-height: 60vh;
+ margin: auto;
+ display: block;
+ }
+
+ .controls {
+ margin-top: auto;
+ display: flex;
+ justify-content: space-between;
+ width: 100%;
+ position: relative;
+ opacity: 0;
+ bottom: -1rem;
+ transition: 0.3s ease-in-out;
+
+ .actions {
+ display: flex;
+ align-items: center;
+ justify-content: flex-start;
+ gap: 4px;
+ }
+
+ .buttons {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 12px;
+ margin-left: auto;
+ }
+
+ .actionButton {
+ width: 32px;
+ height: 32px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ opacity: 0.5;
+ transition: opacity ease-in-out 0.3s;
+
+ &.active,
+ &:hover {
+ opacity: 1;
+ }
+ }
+ }
+
+ &.isFocused {
+ //background: red;
+ .controls {
+ opacity: 1;
+ bottom: 0;
+ }
+ }
+}
diff --git a/src/components/Editor/SimplifiedEditor.tsx b/src/components/Editor/SimplifiedEditor.tsx
new file mode 100644
index 00000000..91aa4191
--- /dev/null
+++ b/src/components/Editor/SimplifiedEditor.tsx
@@ -0,0 +1,246 @@
+import { createEffect, onCleanup, onMount, Show } from 'solid-js'
+import {
+ createEditorTransaction,
+ createTiptapEditor,
+ useEditorHTML,
+ useEditorIsEmpty,
+ useEditorIsFocused
+} from 'solid-tiptap'
+import { useEditorContext } from '../../context/editor'
+import { Document } from '@tiptap/extension-document'
+import { Text } from '@tiptap/extension-text'
+import { Paragraph } from '@tiptap/extension-paragraph'
+import { Bold } from '@tiptap/extension-bold'
+import { Button } from '../_shared/Button'
+import { useLocalize } from '../../context/localize'
+import { Icon } from '../_shared/Icon'
+import { Popover } from '../_shared/Popover'
+import { Italic } from '@tiptap/extension-italic'
+import { Modal } from '../Nav/Modal'
+import { hideModal, showModal } from '../../stores/ui'
+import { Link } from '@tiptap/extension-link'
+import { Blockquote } from '@tiptap/extension-blockquote'
+import { CustomImage } from './extensions/CustomImage'
+import { UploadModalContent } from './UploadModalContent'
+import { imageProxy } from '../../utils/imageProxy'
+import { clsx } from 'clsx'
+import styles from './SimplifiedEditor.module.scss'
+import { Placeholder } from '@tiptap/extension-placeholder'
+import { InsertLinkForm } from './InsertLinkForm'
+
+type Props = {
+ initialContent?: string
+ onSubmit: (text: string) => void
+ placeholder: string
+ quoteEnabled?: boolean
+ imageEnabled?: boolean
+ setClear?: boolean
+ smallHeight?: boolean
+ submitByEnter?: boolean
+ submitByShiftEnter?: boolean
+}
+
+const SimplifiedEditor = (props: Props) => {
+ const { t } = useLocalize()
+
+ const editorElRef: {
+ current: HTMLDivElement
+ } = {
+ current: null
+ }
+ const {
+ actions: { setEditor }
+ } = useEditorContext()
+
+ const editor = createTiptapEditor(() => ({
+ element: editorElRef.current,
+ extensions: [
+ Document,
+ Text,
+ Paragraph,
+ Bold,
+ Italic,
+ Link.configure({
+ openOnClick: false
+ }),
+ Blockquote.configure({
+ HTMLAttributes: {
+ class: styles.blockQuote
+ }
+ }),
+ CustomImage.configure({
+ HTMLAttributes: {
+ class: styles.uploadedImage
+ }
+ }),
+ Placeholder.configure({
+ emptyNodeClass: styles.emptyNode,
+ placeholder: props.placeholder
+ })
+ ],
+ content: props.initialContent ?? null
+ }))
+
+ setEditor(editor)
+ const isEmpty = useEditorIsEmpty(() => editor())
+ const isFocused = useEditorIsFocused(() => editor())
+
+ const isActive = (name: string) =>
+ createEditorTransaction(
+ () => editor(),
+ (ed) => {
+ return ed && ed.isActive(name)
+ }
+ )
+
+ const html = useEditorHTML(() => editor())
+ const isBold = isActive('bold')
+ const isItalic = isActive('italic')
+ const isLink = isActive('link')
+ const isBlockquote = isActive('blockquote')
+
+ const renderImage = (src: string) => {
+ editor()
+ .chain()
+ .focus()
+ .setImage({ src: imageProxy(src) })
+ .run()
+ hideModal()
+ }
+
+ const handleClear = () => {
+ editor().commands.clearContent(true)
+ }
+ createEffect(() => {
+ if (props.setClear) {
+ editor().commands.clearContent(true)
+ }
+ })
+
+ const handleKeyDown = async (event) => {
+ if (props.submitByEnter && event.keyCode === 13 && !event.shiftKey && !isEmpty()) {
+ event.preventDefault()
+ props.onSubmit(html())
+ handleClear()
+ }
+
+ if (props.submitByShiftEnter && event.keyCode === 13 && event.shiftKey && !isEmpty()) {
+ event.preventDefault()
+ props.onSubmit(html())
+ handleClear()
+ }
+ }
+
+ onMount(() => {
+ editor().view.dom.classList.add(styles.simplifiedEditorField)
+ if (props.submitByShiftEnter || props.submitByEnter) {
+ window.addEventListener('keydown', handleKeyDown)
+ }
+ })
+
+ onCleanup(() => {
+ window.removeEventListener('keydown', handleKeyDown)
+ })
+
+ return (
+
+
(editorElRef.current = el)} />
+
+
+
+ {(triggerRef: (el) => void) => (
+
+ )}
+
+
+ {(triggerRef: (el) => void) => (
+
+ )}
+
+
+ {(triggerRef: (el) => void) => (
+
+ )}
+
+
+
+ {(triggerRef: (el) => void) => (
+
+ )}
+
+
+
+
+ {(triggerRef: (el) => void) => (
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+ {
+ renderImage(value)
+ }}
+ />
+
+
+
+ )
+}
+
+export default SimplifiedEditor // "export default" need to use for asynchronous (lazy) imports in the comments tree
diff --git a/src/components/Editor/TextBubbleMenu/TextBubbleMenu.tsx b/src/components/Editor/TextBubbleMenu/TextBubbleMenu.tsx
index a49915b0..fe4055fd 100644
--- a/src/components/Editor/TextBubbleMenu/TextBubbleMenu.tsx
+++ b/src/components/Editor/TextBubbleMenu/TextBubbleMenu.tsx
@@ -5,9 +5,8 @@ import { Icon } from '../../_shared/Icon'
import { clsx } from 'clsx'
import { createEditorTransaction } from 'solid-tiptap'
import { useLocalize } from '../../../context/localize'
-import { InlineForm } from '../InlineForm'
-import { validateUrl } from '../../../utils/validateUrl'
import { Popover } from '../../_shared/Popover'
+import { InsertLinkForm } from '../InsertLinkForm'
type BubbleMenuProps = {
editor: Editor
@@ -15,20 +14,8 @@ type BubbleMenuProps = {
ref: (el: HTMLDivElement) => void
}
-const checkUrl = (url) => {
- try {
- new URL(url)
- return url
- } catch {
- return `https://${url}`
- }
-}
-
export const TextBubbleMenu = (props: BubbleMenuProps) => {
const { t } = useLocalize()
- const [textSizeBubbleOpen, setTextSizeBubbleOpen] = createSignal
(false)
- const [listBubbleOpen, setListBubbleOpen] = createSignal(false)
- const [linkEditorOpen, setLinkEditorOpen] = createSignal(false)
const isActive = (name: string, attributes?: unknown) =>
createEditorTransaction(
@@ -37,6 +24,9 @@ export const TextBubbleMenu = (props: BubbleMenuProps) => {
return editor && editor.isActive(name, attributes)
}
)
+ const [textSizeBubbleOpen, setTextSizeBubbleOpen] = createSignal(false)
+ const [listBubbleOpen, setListBubbleOpen] = createSignal(false)
+ const [linkEditorOpen, setLinkEditorOpen] = createSignal(false)
const isBold = isActive('bold')
const isItalic = isActive('italic')
@@ -49,15 +39,10 @@ export const TextBubbleMenu = (props: BubbleMenuProps) => {
const isLink = isActive('link')
const isHighlight = isActive('highlight')
- const toggleLinkForm = () => {
- setLinkEditorOpen(true)
- }
-
const toggleTextSizePopup = () => {
if (listBubbleOpen()) {
setListBubbleOpen(false)
}
-
setTextSizeBubbleOpen((prev) => !prev)
}
const toggleListPopup = () => {
@@ -67,40 +52,11 @@ export const TextBubbleMenu = (props: BubbleMenuProps) => {
setListBubbleOpen((prev) => !prev)
}
- const handleLinkFormSubmit = (value: string) => {
- props.editor
- .chain()
- .focus()
- .setLink({ href: checkUrl(value) })
- .run()
- }
-
- const currentUrl = createEditorTransaction(
- () => props.editor,
- (editor) => {
- return (editor && editor.getAttributes('link').href) || ''
- }
- )
-
- const handleClearLinkForm = () => {
- if (currentUrl()) {
- props.editor.chain().focus().unsetLink().run()
- }
- setLinkEditorOpen(false)
- }
-
return (
{formattedTime(props.content.createdAt * 1000)()}
diff --git a/src/components/Views/Inbox.tsx b/src/components/Views/Inbox.tsx
index 203fb1a2..ba8b6dca 100644
--- a/src/components/Views/Inbox.tsx
+++ b/src/components/Views/Inbox.tsx
@@ -18,6 +18,7 @@ import { useRouter } from '../../stores/router'
import { clsx } from 'clsx'
import styles from '../../styles/Inbox.module.scss'
import { useLocalize } from '../../context/localize'
+import SimplifiedEditor from '../Editor/SimplifiedEditor'
type InboxSearchParams = {
initChat: string
@@ -41,14 +42,14 @@ export const InboxView = () => {
} = useInbox()
const [recipients, setRecipients] = createSignal([])
- const [postMessageText, setPostMessageText] = createSignal('')
- const [sortByGroup, setSortByGroup] = createSignal(false)
- const [sortByPerToPer, setSortByPerToPer] = createSignal(false)
+ const [sortByGroup, setSortByGroup] = createSignal(false)
+ const [sortByPerToPer, setSortByPerToPer] = createSignal(false)
const [currentDialog, setCurrentDialog] = createSignal()
const [messageToReply, setMessageToReply] = createSignal(null)
+ const [isClear, setClear] = createSignal(false)
const { session } = useSession()
const currentUserId = createMemo(() => session()?.user.id)
-
+ const { changeSearchParam, searchParams } = useRouter()
// Поиск по диалогам
const getQuery = (query) => {
if (query().length >= 2) {
@@ -97,28 +98,19 @@ export const InboxView = () => {
await loadChats()
})
- const handleSubmit = async () => {
+ const handleSubmit = async (message: string) => {
await sendMessage({
- body: postMessageText().toString(),
+ body: message,
chat: currentDialog().id.toString(),
replyTo: messageToReply()?.id
})
- setPostMessageText('')
+ setClear(true)
setMessageToReply(null)
chatWindow.scrollTop = chatWindow.scrollHeight
+ setClear(false)
}
- let textareaParent // textarea autoresize ghost element
- const handleChangeMessage = (event) => {
- setPostMessageText(event.target.value)
- }
-
- const { changeSearchParam, searchParams } = useRouter()
-
createEffect(async () => {
- if (textareaParent) {
- textareaParent.dataset.replicatedValue = postMessageText()
- }
if (searchParams().chat) {
const chatToOpen = chats()?.find((chat) => chat.id === searchParams().chat)
if (!chatToOpen) return
@@ -156,17 +148,6 @@ export const InboxView = () => {
return messages().find((message) => message.id === messageId)
}
- const handleKeyDown = async (event) => {
- if (event.keyCode === 13 && event.shiftKey) {
- return
- }
-
- if (event.keyCode === 13 && !event.shiftKey && postMessageText()?.trim().length > 0) {
- event.preventDefault()
- handleSubmit()
- }
- }
-
return (
@@ -278,19 +259,14 @@ export const InboxView = () => {
/>
-
-
-
+
handleSubmit(message)}
+ submitByEnter={true}
+ />
diff --git a/src/components/_shared/CommentEditor/CommentEditor.tsx b/src/components/_shared/CommentEditor/CommentEditor.tsx
deleted file mode 100644
index e17e4ba9..00000000
--- a/src/components/_shared/CommentEditor/CommentEditor.tsx
+++ /dev/null
@@ -1,97 +0,0 @@
-import styles from './styles/CommentEditor.module.scss'
-import './styles/ProseMirrorOverrides.scss'
-import { clsx } from 'clsx'
-import { Button } from '../Button'
-import { createEffect, onMount } from 'solid-js'
-// ProseMirror deps
-import { schema } from './schema'
-import { EditorState } from 'prosemirror-state'
-import { EditorView } from 'prosemirror-view'
-import { DOMParser as ProseDOMParser, DOMSerializer } from 'prosemirror-model'
-import { renderGrouped } from 'prosemirror-menu'
-import { buildMenuItems } from './menu'
-import { keymap } from 'prosemirror-keymap'
-import { baseKeymap } from 'prosemirror-commands'
-import { customKeymap } from '../../EditorNew/prosemirror/plugins/customKeymap'
-import { placeholder } from '../../EditorNew/prosemirror/plugins/placeholder'
-import { undo, redo, history } from 'prosemirror-history'
-import { useLocalize } from '../../../context/localize'
-
-type Props = {
- placeholder?: string
- onSubmit: (value: string) => void
- clear?: boolean
- cancel?: () => void
- initialContent?: string
-}
-
-const htmlContainer = typeof document === 'undefined' ? null : document.createElement('div')
-const getHtml = (state: EditorState) => {
- const fragment = DOMSerializer.fromSchema(schema).serializeFragment(state.doc.content)
- htmlContainer.replaceChildren(fragment)
- return htmlContainer.innerHTML
-}
-
-const CommentEditor = (props: Props) => {
- const { t } = useLocalize()
- const editorElRef: { current: HTMLDivElement } = { current: null }
- const menuElRef: { current: HTMLDivElement } = { current: null }
- const editorViewRef: { current: EditorView } = { current: null }
-
- const domNew = new DOMParser().parseFromString(`${props.initialContent}
`, 'text/xml')
- const doc = ProseDOMParser.fromSchema(schema).parse(domNew)
-
- const initEditor = () => {
- editorViewRef.current = new EditorView(editorElRef.current, {
- state: EditorState.create({
- schema,
- doc: props.initialContent ? doc : null,
- plugins: [
- history(),
- customKeymap(),
- placeholder(props.placeholder),
- keymap({ 'Mod-z': undo, 'Mod-Shift-z': redo, 'Mod-y': redo }),
- keymap(baseKeymap)
- ]
- })
- })
- }
-
- onMount(() => {
- initEditor()
- const { dom } = renderGrouped(editorViewRef.current, buildMenuItems(schema))
- menuElRef.current.appendChild(dom)
- })
-
- const handleSubmitButtonClick = () => {
- props.onSubmit(getHtml(editorViewRef.current.state))
- }
-
- const clearEditor = () => {
- editorViewRef.current.destroy()
- initEditor()
- if (props.cancel) {
- props.cancel()
- }
- }
-
- createEffect(() => {
- if (props.clear) {
- clearEditor()
- }
- })
- return (
-