fix(web): refine code block editing behavior
This commit is contained in:
1 parent
db1854e6be
commit
fe437a7875
3 files changed
+91
No files matched your search
@@ -247,6 +247,9 @@ export const MermaidCodeBlock = ({ editor, node }: NodeViewProps) => {
|
||||
<NodeViewContent
|
||||
className={isMermaid ? "edgeever-code-source edgeever-mermaid-source" : "edgeever-code-source"}
|
||||
role="textbox"
|
||||
autoCapitalize="none"
|
||||
autoCorrect="off"
|
||||
spellCheck={false}
|
||||
aria-label={isMermaid ? t("editorToolbar.mermaidSource") : undefined}
|
||||
aria-multiline="true"
|
||||
aria-readonly={!editor.isEditable}
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
import { describe, expect, test } from "bun:test";
|
||||
import { Editor } from "@tiptap/core";
|
||||
import StarterKit from "@tiptap/starter-kit";
|
||||
import { EdgeEverCodeBlock, selectCurrentCodeBlockContent } from "./code-block.ts";
|
||||
|
||||
const createEditor = () => new Editor({
|
||||
extensions: [
|
||||
StarterKit.configure({ codeBlock: false }),
|
||||
EdgeEverCodeBlock,
|
||||
],
|
||||
content: {
|
||||
type: "doc",
|
||||
content: [
|
||||
{ type: "paragraph", content: [{ type: "text", text: "before" }] },
|
||||
{
|
||||
type: "codeBlock",
|
||||
attrs: { language: "mermaid" },
|
||||
content: [{ type: "text", text: "flowchart TD\n A --> B" }],
|
||||
},
|
||||
{ type: "paragraph", content: [{ type: "text", text: "after" }] },
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const getCodeBlockRange = (editor) => {
|
||||
let range = null;
|
||||
editor.state.doc.descendants((node, pos) => {
|
||||
if (!range && node.type.name === "codeBlock") {
|
||||
range = { from: pos + 1, to: pos + 1 + node.content.size };
|
||||
}
|
||||
});
|
||||
return range;
|
||||
};
|
||||
|
||||
describe("code block selection", () => {
|
||||
test("selects only the current code block on the first Mod-a", () => {
|
||||
const editor = createEditor();
|
||||
const range = getCodeBlockRange(editor);
|
||||
editor.commands.setTextSelection(range.from + 2);
|
||||
|
||||
expect(selectCurrentCodeBlockContent(editor)).toBe(true);
|
||||
expect({
|
||||
from: editor.state.selection.from,
|
||||
to: editor.state.selection.to,
|
||||
}).toEqual(range);
|
||||
editor.destroy();
|
||||
});
|
||||
|
||||
test("allows the editor-wide Mod-a after the code block is fully selected", () => {
|
||||
const editor = createEditor();
|
||||
const range = getCodeBlockRange(editor);
|
||||
editor.commands.setTextSelection(range);
|
||||
|
||||
expect(selectCurrentCodeBlockContent(editor)).toBe(false);
|
||||
editor.destroy();
|
||||
});
|
||||
|
||||
test("leaves Mod-a unchanged outside code blocks", () => {
|
||||
const editor = createEditor();
|
||||
editor.commands.setTextSelection(2);
|
||||
|
||||
expect(selectCurrentCodeBlockContent(editor)).toBe(false);
|
||||
editor.destroy();
|
||||
});
|
||||
});
|
||||
@@ -1,11 +1,34 @@
|
||||
import { common, createLowlight } from "lowlight";
|
||||
import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight";
|
||||
import type { Editor } from "@tiptap/core";
|
||||
import { ReactNodeViewRenderer } from "@tiptap/react";
|
||||
import { MermaidCodeBlock } from "@/components/MermaidCodeBlock";
|
||||
|
||||
export const codeBlockLowlight = createLowlight(common);
|
||||
|
||||
export const selectCurrentCodeBlockContent = (editor: Editor) => {
|
||||
const { $from, $to, from, to } = editor.state.selection;
|
||||
if ($from.parent !== $to.parent || $from.parent.type.name !== "codeBlock") {
|
||||
return false;
|
||||
}
|
||||
|
||||
const blockFrom = $from.start();
|
||||
const blockTo = $from.end();
|
||||
if (from === blockFrom && to === blockTo) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return editor.commands.setTextSelection({ from: blockFrom, to: blockTo });
|
||||
};
|
||||
|
||||
export const EdgeEverCodeBlock = CodeBlockLowlight.extend({
|
||||
addKeyboardShortcuts() {
|
||||
return {
|
||||
...this.parent?.(),
|
||||
"Mod-a": () => selectCurrentCodeBlockContent(this.editor),
|
||||
};
|
||||
},
|
||||
|
||||
addNodeView() {
|
||||
return ReactNodeViewRenderer(MermaidCodeBlock);
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user