diff --git a/app/editor/components/FloatingToolbar.tsx b/app/editor/components/FloatingToolbar.tsx
index 49a184aa5..d451adeb6 100644
--- a/app/editor/components/FloatingToolbar.tsx
+++ b/app/editor/components/FloatingToolbar.tsx
@@ -74,7 +74,7 @@ function usePosition({
// position at the top right of code blocks
const codeBlock = findParentNode(isCode)(view.state.selection);
- if (codeBlock) {
+ if (codeBlock && view.state.selection.empty) {
const element = view.nodeDOM(codeBlock.pos);
const bounds = (element as HTMLElement).getBoundingClientRect();
selectionBounds.top = bounds.top;
diff --git a/app/editor/components/SelectionToolbar.tsx b/app/editor/components/SelectionToolbar.tsx
index ac9e2c001..3d8f82402 100644
--- a/app/editor/components/SelectionToolbar.tsx
+++ b/app/editor/components/SelectionToolbar.tsx
@@ -4,6 +4,7 @@ import * as React from "react";
import createAndInsertLink from "@shared/editor/commands/createAndInsertLink";
import filterExcessSeparators from "@shared/editor/lib/filterExcessSeparators";
import getMarkRange from "@shared/editor/queries/getMarkRange";
+import isInCode from "@shared/editor/queries/isInCode";
import isMarkActive from "@shared/editor/queries/isMarkActive";
import isNodeActive from "@shared/editor/queries/isNodeActive";
import { getColumnIndex, getRowIndex } from "@shared/editor/queries/table";
@@ -216,13 +217,11 @@ export default function SelectionToolbar(props: Props) {
const range = getMarkRange(selection.$from, state.schema.marks.link);
const isImageSelection =
selection instanceof NodeSelection && selection.node.type.name === "image";
- const isCodeSelection =
- isNodeActive(state.schema.nodes.code_block)(state) ||
- isNodeActive(state.schema.nodes.code_fence)(state);
+ const isCodeSelection = isInCode(state, { onlyBlock: true });
let items: MenuItem[] = [];
- if (isCodeSelection) {
+ if (isCodeSelection && selection.empty) {
items = getCodeMenuItems(state, readOnly, dictionary);
} else if (isTableSelection) {
items = getTableMenuItems(dictionary);
diff --git a/app/editor/components/ToolbarButton.tsx b/app/editor/components/ToolbarButton.tsx
index 0ffbb79b1..bcd3b608e 100644
--- a/app/editor/components/ToolbarButton.tsx
+++ b/app/editor/components/ToolbarButton.tsx
@@ -23,7 +23,7 @@ export default styled.button.attrs((props) => ({
background: none;
transition: opacity 100ms ease-in-out;
padding: 0;
- opacity: 0.7;
+ opacity: 0.8;
outline: none;
pointer-events: all;
position: relative;
diff --git a/app/editor/components/ToolbarMenu.tsx b/app/editor/components/ToolbarMenu.tsx
index e572b71cd..16a6bd2dd 100644
--- a/app/editor/components/ToolbarMenu.tsx
+++ b/app/editor/components/ToolbarMenu.tsx
@@ -129,6 +129,7 @@ const Arrow = styled(ExpandedIcon)`
const Label = styled.span`
font-size: 15px;
font-weight: 500;
+ color: ${s("text")};
`;
export default ToolbarMenu;
diff --git a/app/editor/menus/formatting.tsx b/app/editor/menus/formatting.tsx
index a786b5e7e..4e52e12d7 100644
--- a/app/editor/menus/formatting.tsx
+++ b/app/editor/menus/formatting.tsx
@@ -36,6 +36,7 @@ export default function formattingMenuItems(
const isTable = isInTable(state);
const isList = isInList(state);
const isCode = isInCode(state);
+ const isCodeBlock = isInCode(state, { onlyBlock: true });
const allowBlocks = !isTable && !isList;
return [
@@ -83,6 +84,7 @@ export default function formattingMenuItems(
tooltip: dictionary.codeInline,
icon: ,
active: isMarkActive(schema.marks.code_inline),
+ visible: !isCodeBlock,
},
{
name: "separator",
@@ -166,8 +168,8 @@ export default function formattingMenuItems(
name: "comment",
tooltip: dictionary.comment,
icon: ,
+ label: isCodeBlock ? dictionary.comment : undefined,
active: isMarkActive(schema.marks.comment),
- visible: !isCode,
},
];
}
diff --git a/shared/editor/marks/Code.ts b/shared/editor/marks/Code.ts
index 185f51f46..7f0011ce9 100644
--- a/shared/editor/marks/Code.ts
+++ b/shared/editor/marks/Code.ts
@@ -41,7 +41,7 @@ export default class Code extends Mark {
get schema(): MarkSpec {
return {
- excludes: "comment mention link placeholder highlight em strong",
+ excludes: "mention link placeholder highlight em strong",
parseDOM: [{ tag: "code.inline", preserveWhitespace: true }],
toDOM: () => ["code", { class: "inline", spellCheck: "false" }],
};
diff --git a/shared/editor/marks/Comment.ts b/shared/editor/marks/Comment.ts
index c9ff8431a..a58a5ea18 100644
--- a/shared/editor/marks/Comment.ts
+++ b/shared/editor/marks/Comment.ts
@@ -109,14 +109,16 @@ export default class Comment extends Mark {
props: {
handleDOMEvents: {
mouseup: (_view, event: MouseEvent) => {
- if (
- !(event.target instanceof HTMLSpanElement) ||
- !event.target.classList.contains("comment-marker")
- ) {
+ if (!(event.target instanceof HTMLElement)) {
return false;
}
- const commentId = event.target.id.replace("comment-", "");
+ const comment = event.target.closest(".comment-marker");
+ if (!comment) {
+ return false;
+ }
+
+ const commentId = comment.id.replace("comment-", "");
if (commentId) {
this.options?.onClickCommentMark?.(commentId);
}
diff --git a/shared/editor/nodes/CodeFence.ts b/shared/editor/nodes/CodeFence.ts
index 9b553f142..5c11babd9 100644
--- a/shared/editor/nodes/CodeFence.ts
+++ b/shared/editor/nodes/CodeFence.ts
@@ -150,7 +150,7 @@ export default class CodeFence extends Node {
},
},
content: "text*",
- marks: "",
+ marks: "comment",
group: "block",
code: true,
defining: true,
diff --git a/shared/editor/nodes/index.ts b/shared/editor/nodes/index.ts
index 0634028cb..6ef1263b1 100644
--- a/shared/editor/nodes/index.ts
+++ b/shared/editor/nodes/index.ts
@@ -118,4 +118,4 @@ export const richExtensions: Nodes = [
/**
* Add commenting and mentions to a set of nodes
*/
-export const withComments = (nodes: Nodes) => [Mention, Comment, ...nodes];
+export const withComments = (nodes: Nodes) => [...nodes, Mention, Comment];
diff --git a/shared/editor/queries/isInCode.ts b/shared/editor/queries/isInCode.ts
index 70c7706df..e9c6ba30b 100644
--- a/shared/editor/queries/isInCode.ts
+++ b/shared/editor/queries/isInCode.ts
@@ -1,29 +1,40 @@
import { EditorState } from "prosemirror-state";
import isMarkActive from "./isMarkActive";
+import isNodeActive from "./isNodeActive";
+
+type Options = {
+ /** Only check if the selection is inside a code block. */
+ onlyBlock?: boolean;
+ /** Only check if the selection is inside a code mark. */
+ onlyMark?: boolean;
+};
/**
* Returns true if the selection is inside a code block or code mark.
*
* @param state The editor state.
+ * @param options The options.
* @returns True if the selection is inside a code block or code mark.
*/
-export default function isInCode(state: EditorState): boolean {
+export default function isInCode(
+ state: EditorState,
+ options?: Options
+): boolean {
const { nodes, marks } = state.schema;
- if (nodes.code_block || nodes.code_fence) {
- const $head = state.selection.$head;
- for (let d = $head.depth; d > 0; d--) {
- if (nodes.code_block && $head.node(d).type === nodes.code_block) {
- return true;
- }
- if (nodes.code_fence && $head.node(d).type === nodes.code_fence) {
- return true;
- }
+ if (!options?.onlyMark) {
+ if (nodes.code_block && isNodeActive(nodes.code_block)(state)) {
+ return true;
+ }
+ if (nodes.code_fence && isNodeActive(nodes.code_fence)(state)) {
+ return true;
}
}
- if (marks.code_inline) {
- return isMarkActive(marks.code_inline)(state);
+ if (!options?.onlyBlock) {
+ if (marks.code_inline) {
+ return isMarkActive(marks.code_inline)(state);
+ }
}
return false;