diff --git a/packages/ui/src/RichEditor/BlockMenu.tsx b/packages/ui/src/RichEditor/BlockMenu.tsx index b922fc526..e2c907f0e 100644 --- a/packages/ui/src/RichEditor/BlockMenu.tsx +++ b/packages/ui/src/RichEditor/BlockMenu.tsx @@ -134,9 +134,16 @@ export function BlockMenu({ editor }: BlockMenuProps) { try { const pos = editor.view.posAtDOM(hoveredBlock, 0); const $pos = editor.state.doc.resolve(pos); - const rootPos = $pos.before(1); - const rootNode = $pos.node(1); - const insertPos = rootPos + rootNode.nodeSize; + + let insertPos: number; + if ($pos.depth >= 1) { + const rootPos = $pos.before(1); + const rootNode = $pos.node(1); + insertPos = rootPos + rootNode.nodeSize; + } else { + const nodeAfter = $pos.nodeAfter; + insertPos = pos + (nodeAfter?.nodeSize ?? 1); + } editor.chain() .focus() diff --git a/packages/ui/src/RichEditor/OptionsMenu.tsx b/packages/ui/src/RichEditor/OptionsMenu.tsx index 43e9e8bc5..c27d71017 100644 --- a/packages/ui/src/RichEditor/OptionsMenu.tsx +++ b/packages/ui/src/RichEditor/OptionsMenu.tsx @@ -139,7 +139,14 @@ export function OptionsMenu({ editor }: OptionsMenuProps) { try { const pos = editor.view.posAtDOM(hoveredBlock, 0); const $pos = editor.state.doc.resolve(pos); - return { node: $pos.node(1), pos: $pos.before(1) }; + if ($pos.depth >= 1) { + return { node: $pos.node(1), pos: $pos.before(1) }; + } + const nodeAfter = $pos.nodeAfter; + if (nodeAfter) { + return { node: nodeAfter, pos: pos }; + } + return null; } catch { return null; } @@ -161,10 +168,36 @@ export function OptionsMenu({ editor }: OptionsMenuProps) { applyCommand: (chain: ReturnType) => ReturnType, ) => { const data = getNodeAtHoveredBlock(); - if (!data) return; + if (!data) { + setMenuOpen(false); + return; + } try { if (!data.node.isTextblock) { + if (!data.node.firstChild) { + const paragraph = editor.state.schema.nodes.paragraph.create(); + editor.chain() + .focus() + .command(({ tr }) => { + tr.replaceWith(data.pos, data.pos + data.node.nodeSize, paragraph); + return true; + }) + .run(); + + const $near = editor.state.doc.resolve(data.pos + 1); + const textPos = TextSelection.near($near).from; + + applyCommand( + editor.chain() + .focus() + .setTextSelection(textPos), + ).run(); + + setMenuOpen(false); + return; + } + let textBlock = data.node.firstChild; if (!textBlock) return; while (!textBlock.isTextblock && textBlock.firstChild) { @@ -172,7 +205,7 @@ export function OptionsMenu({ editor }: OptionsMenuProps) { } if (!textBlock.isTextblock) return; - const firstChildSize = data.node.firstChild!.nodeSize; + const firstChildSize = data.node.firstChild.nodeSize; const paragraph = editor.state.schema.nodes.paragraph.create( null, textBlock.content, @@ -254,6 +287,7 @@ export function OptionsMenu({ editor }: OptionsMenuProps) { menuRefs.setReference(node); }} {...getReferenceProps()} + onMouseDown={e => e.preventDefault()} draggable onDragStart={onDragStart} onDragEnd={() => setHoveredBlock(null)} diff --git a/packages/ui/src/rich-editor.css b/packages/ui/src/rich-editor.css new file mode 100644 index 000000000..fc4e93135 --- /dev/null +++ b/packages/ui/src/rich-editor.css @@ -0,0 +1,55 @@ +.ProseMirror-focused { + outline-width: 0 !important; + outline-color: transparent !important; + outline-style: none !important; +} + +.tiptap { + p { + @apply my-2; + code { @apply py-0.5 px-1; } + } + + strong { @apply font-semibold; } + + h1 { @apply text-2xl font-semibold mt-4; } + + h2 { @apply text-xl font-semibold mt-3; } + + h3 { @apply text-lg font-semibold mt-2; } + + ul { + @apply list-disc list-inside my-2; + + li { + p { @apply inline-block my-0 } + } + li::marker { @apply mx-2!; } + } + + ol { + @apply list-decimal list-inside my-2; + + li { + p { @apply inline-block my-0 } + } + li::marker { @apply mx-2!; } + } + + a { @apply text-txt-info underline font-normal; } + + &.pointer-on-hovered-link { + a:hover { cursor: pointer; } + } + + blockquote { + @apply my-2 pl-4 border-l-4 border-l-border-solid; + p { @apply my-0; } + } + + hr { @apply my-4 border-t-border-solid border-t; } + + pre { @apply my-4 px-6 py-4 bg-border-solid rounded-lg text-sm; } + + code { @apply text-inherit font-mono bg-border-solid rounded-md; } +} diff --git a/packages/ui/src/theme.css b/packages/ui/src/theme.css index 4bb339abe..3b595a372 100644 --- a/packages/ui/src/theme.css +++ b/packages/ui/src/theme.css @@ -278,71 +278,4 @@ button[data-cell]:focus-visible { border-radius: 4px; } -.ProseMirror-focused { - outline-width: 0 !important; - outline-color: transparent !important; - outline-style: none !important; -} - -.tiptap p { @apply my-2; } - -.tiptap strong { @apply font-semibold; } - -.tiptap h1 { - @apply text-2xl font-semibold mt-4; -} - -.tiptap h2 { - @apply text-xl font-semibold mt-3; -} - -.tiptap h3 { - @apply text-lg font-semibold mt-2; -} - -.tiptap ul { - @apply list-disc list-inside my-2; - - li { - p { @apply inline-block my-0 } - } - li::marker { @apply mx-2!; } -} - -.tiptap ol { - @apply list-decimal list-inside my-2; - - li { - p { @apply inline-block my-0 } - } - li::marker { @apply mx-2!; } -} - -.tiptap a { - @apply text-txt-info underline font-normal; -} - -.tiptap.pointer-on-hovered-link { - a:hover { cursor: pointer; } -} - -.tiptap blockquote { - @apply my-2 pl-4 border-l-4 border-l-border-solid; - p { @apply my-0; } -} - -.tiptap hr { - @apply my-4 border-t-border-solid border-t; -} - -.tiptap pre { - @apply my-4 px-6 py-4 bg-border-solid rounded-lg text-sm; -} - -.tiptap code { - @apply text-inherit font-mono bg-border-solid rounded-md; -} - -.tiptap p code { - @apply py-0.5 px-1; -} +@import "./rich-editor.css";