chore: add missing headings to the rich text editor (#5135)
This commit is contained in:
parent
8771c80c9b
commit
2ee6cd20d8
10 changed files with 227 additions and 187 deletions
|
|
@ -1,3 +1,5 @@
|
|||
import { Selection } from "@tiptap/pm/state";
|
||||
import { Editor } from "@tiptap/react";
|
||||
import {
|
||||
BoldIcon,
|
||||
Heading1,
|
||||
|
|
@ -19,8 +21,6 @@ import {
|
|||
CaseSensitive,
|
||||
LucideIcon,
|
||||
} from "lucide-react";
|
||||
import { Selection } from "@tiptap/pm/state";
|
||||
import { Editor } from "@tiptap/react";
|
||||
// helpers
|
||||
import {
|
||||
insertImageCommand,
|
||||
|
|
@ -43,168 +43,151 @@ import {
|
|||
toggleUnderline,
|
||||
} from "@/helpers/editor-commands";
|
||||
// types
|
||||
import { UploadImage } from "@/types";
|
||||
import { TEditorCommands, UploadImage } from "@/types";
|
||||
|
||||
export interface EditorMenuItem {
|
||||
key: string;
|
||||
key: TEditorCommands;
|
||||
name: string;
|
||||
isActive: () => boolean;
|
||||
command: () => void;
|
||||
icon: LucideIcon;
|
||||
}
|
||||
|
||||
export const TextItem = (editor: Editor) =>
|
||||
({
|
||||
key: "text",
|
||||
name: "Text",
|
||||
isActive: () => editor.isActive("paragraph"),
|
||||
command: () => setText(editor),
|
||||
icon: CaseSensitive,
|
||||
}) as const satisfies EditorMenuItem;
|
||||
export const TextItem = (editor: Editor): EditorMenuItem => ({
|
||||
key: "text",
|
||||
name: "Text",
|
||||
isActive: () => editor.isActive("paragraph"),
|
||||
command: () => setText(editor),
|
||||
icon: CaseSensitive,
|
||||
});
|
||||
|
||||
export const HeadingOneItem = (editor: Editor) =>
|
||||
({
|
||||
key: "h1",
|
||||
name: "Heading 1",
|
||||
isActive: () => editor.isActive("heading", { level: 1 }),
|
||||
command: () => toggleHeadingOne(editor),
|
||||
icon: Heading1,
|
||||
}) as const satisfies EditorMenuItem;
|
||||
export const HeadingOneItem = (editor: Editor): EditorMenuItem => ({
|
||||
key: "h1",
|
||||
name: "Heading 1",
|
||||
isActive: () => editor.isActive("heading", { level: 1 }),
|
||||
command: () => toggleHeadingOne(editor),
|
||||
icon: Heading1,
|
||||
});
|
||||
|
||||
export const HeadingTwoItem = (editor: Editor) =>
|
||||
({
|
||||
key: "h2",
|
||||
name: "Heading 2",
|
||||
isActive: () => editor.isActive("heading", { level: 2 }),
|
||||
command: () => toggleHeadingTwo(editor),
|
||||
icon: Heading2,
|
||||
}) as const satisfies EditorMenuItem;
|
||||
export const HeadingTwoItem = (editor: Editor): EditorMenuItem => ({
|
||||
key: "h2",
|
||||
name: "Heading 2",
|
||||
isActive: () => editor.isActive("heading", { level: 2 }),
|
||||
command: () => toggleHeadingTwo(editor),
|
||||
icon: Heading2,
|
||||
});
|
||||
|
||||
export const HeadingThreeItem = (editor: Editor) =>
|
||||
({
|
||||
key: "h3",
|
||||
name: "Heading 3",
|
||||
isActive: () => editor.isActive("heading", { level: 3 }),
|
||||
command: () => toggleHeadingThree(editor),
|
||||
icon: Heading3,
|
||||
}) as const satisfies EditorMenuItem;
|
||||
export const HeadingThreeItem = (editor: Editor): EditorMenuItem => ({
|
||||
key: "h3",
|
||||
name: "Heading 3",
|
||||
isActive: () => editor.isActive("heading", { level: 3 }),
|
||||
command: () => toggleHeadingThree(editor),
|
||||
icon: Heading3,
|
||||
});
|
||||
|
||||
export const HeadingFourItem = (editor: Editor) =>
|
||||
({
|
||||
key: "h4",
|
||||
name: "Heading 4",
|
||||
isActive: () => editor.isActive("heading", { level: 4 }),
|
||||
command: () => toggleHeadingFour(editor),
|
||||
icon: Heading4,
|
||||
}) as const satisfies EditorMenuItem;
|
||||
export const HeadingFourItem = (editor: Editor): EditorMenuItem => ({
|
||||
key: "h4",
|
||||
name: "Heading 4",
|
||||
isActive: () => editor.isActive("heading", { level: 4 }),
|
||||
command: () => toggleHeadingFour(editor),
|
||||
icon: Heading4,
|
||||
});
|
||||
|
||||
export const HeadingFiveItem = (editor: Editor) =>
|
||||
({
|
||||
key: "h5",
|
||||
name: "Heading 5",
|
||||
isActive: () => editor.isActive("heading", { level: 5 }),
|
||||
command: () => toggleHeadingFive(editor),
|
||||
icon: Heading5,
|
||||
}) as const satisfies EditorMenuItem;
|
||||
export const HeadingFiveItem = (editor: Editor): EditorMenuItem => ({
|
||||
key: "h5",
|
||||
name: "Heading 5",
|
||||
isActive: () => editor.isActive("heading", { level: 5 }),
|
||||
command: () => toggleHeadingFive(editor),
|
||||
icon: Heading5,
|
||||
});
|
||||
|
||||
export const HeadingSixItem = (editor: Editor) =>
|
||||
({
|
||||
key: "h6",
|
||||
name: "Heading 6",
|
||||
isActive: () => editor.isActive("heading", { level: 6 }),
|
||||
command: () => toggleHeadingSix(editor),
|
||||
icon: Heading6,
|
||||
}) as const satisfies EditorMenuItem;
|
||||
export const HeadingSixItem = (editor: Editor): EditorMenuItem => ({
|
||||
key: "h6",
|
||||
name: "Heading 6",
|
||||
isActive: () => editor.isActive("heading", { level: 6 }),
|
||||
command: () => toggleHeadingSix(editor),
|
||||
icon: Heading6,
|
||||
});
|
||||
|
||||
export const BoldItem = (editor: Editor) =>
|
||||
({
|
||||
key: "bold",
|
||||
name: "Bold",
|
||||
isActive: () => editor?.isActive("bold"),
|
||||
command: () => toggleBold(editor),
|
||||
icon: BoldIcon,
|
||||
}) as const satisfies EditorMenuItem;
|
||||
export const BoldItem = (editor: Editor): EditorMenuItem => ({
|
||||
key: "bold",
|
||||
name: "Bold",
|
||||
isActive: () => editor?.isActive("bold"),
|
||||
command: () => toggleBold(editor),
|
||||
icon: BoldIcon,
|
||||
});
|
||||
|
||||
export const ItalicItem = (editor: Editor) =>
|
||||
({
|
||||
key: "italic",
|
||||
name: "Italic",
|
||||
isActive: () => editor?.isActive("italic"),
|
||||
command: () => toggleItalic(editor),
|
||||
icon: ItalicIcon,
|
||||
}) as const satisfies EditorMenuItem;
|
||||
export const ItalicItem = (editor: Editor): EditorMenuItem => ({
|
||||
key: "italic",
|
||||
name: "Italic",
|
||||
isActive: () => editor?.isActive("italic"),
|
||||
command: () => toggleItalic(editor),
|
||||
icon: ItalicIcon,
|
||||
});
|
||||
|
||||
export const UnderLineItem = (editor: Editor) =>
|
||||
({
|
||||
key: "underline",
|
||||
name: "Underline",
|
||||
isActive: () => editor?.isActive("underline"),
|
||||
command: () => toggleUnderline(editor),
|
||||
icon: UnderlineIcon,
|
||||
}) as const satisfies EditorMenuItem;
|
||||
export const UnderLineItem = (editor: Editor): EditorMenuItem => ({
|
||||
key: "underline",
|
||||
name: "Underline",
|
||||
isActive: () => editor?.isActive("underline"),
|
||||
command: () => toggleUnderline(editor),
|
||||
icon: UnderlineIcon,
|
||||
});
|
||||
|
||||
export const StrikeThroughItem = (editor: Editor) =>
|
||||
({
|
||||
key: "strikethrough",
|
||||
name: "Strikethrough",
|
||||
isActive: () => editor?.isActive("strike"),
|
||||
command: () => toggleStrike(editor),
|
||||
icon: StrikethroughIcon,
|
||||
}) as const satisfies EditorMenuItem;
|
||||
export const StrikeThroughItem = (editor: Editor): EditorMenuItem => ({
|
||||
key: "strikethrough",
|
||||
name: "Strikethrough",
|
||||
isActive: () => editor?.isActive("strike"),
|
||||
command: () => toggleStrike(editor),
|
||||
icon: StrikethroughIcon,
|
||||
});
|
||||
|
||||
export const BulletListItem = (editor: Editor) =>
|
||||
({
|
||||
key: "bulleted-list",
|
||||
name: "Bulleted list",
|
||||
isActive: () => editor?.isActive("bulletList"),
|
||||
command: () => toggleBulletList(editor),
|
||||
icon: ListIcon,
|
||||
}) as const satisfies EditorMenuItem;
|
||||
export const BulletListItem = (editor: Editor): EditorMenuItem => ({
|
||||
key: "bulleted-list",
|
||||
name: "Bulleted list",
|
||||
isActive: () => editor?.isActive("bulletList"),
|
||||
command: () => toggleBulletList(editor),
|
||||
icon: ListIcon,
|
||||
});
|
||||
|
||||
export const NumberedListItem = (editor: Editor) =>
|
||||
({
|
||||
key: "numbered-list",
|
||||
name: "Numbered list",
|
||||
isActive: () => editor?.isActive("orderedList"),
|
||||
command: () => toggleOrderedList(editor),
|
||||
icon: ListOrderedIcon,
|
||||
}) as const satisfies EditorMenuItem;
|
||||
export const NumberedListItem = (editor: Editor): EditorMenuItem => ({
|
||||
key: "numbered-list",
|
||||
name: "Numbered list",
|
||||
isActive: () => editor?.isActive("orderedList"),
|
||||
command: () => toggleOrderedList(editor),
|
||||
icon: ListOrderedIcon,
|
||||
});
|
||||
|
||||
export const TodoListItem = (editor: Editor) =>
|
||||
({
|
||||
key: "to-do-list",
|
||||
name: "To-do list",
|
||||
isActive: () => editor.isActive("taskItem"),
|
||||
command: () => toggleTaskList(editor),
|
||||
icon: CheckSquare,
|
||||
}) as const satisfies EditorMenuItem;
|
||||
export const TodoListItem = (editor: Editor): EditorMenuItem => ({
|
||||
key: "to-do-list",
|
||||
name: "To-do list",
|
||||
isActive: () => editor.isActive("taskItem"),
|
||||
command: () => toggleTaskList(editor),
|
||||
icon: CheckSquare,
|
||||
});
|
||||
|
||||
export const QuoteItem = (editor: Editor) =>
|
||||
({
|
||||
key: "quote",
|
||||
name: "Quote",
|
||||
isActive: () => editor?.isActive("blockquote"),
|
||||
command: () => toggleBlockquote(editor),
|
||||
icon: QuoteIcon,
|
||||
}) as const satisfies EditorMenuItem;
|
||||
export const QuoteItem = (editor: Editor): EditorMenuItem => ({
|
||||
key: "quote",
|
||||
name: "Quote",
|
||||
isActive: () => editor?.isActive("blockquote"),
|
||||
command: () => toggleBlockquote(editor),
|
||||
icon: QuoteIcon,
|
||||
});
|
||||
|
||||
export const CodeItem = (editor: Editor) =>
|
||||
({
|
||||
key: "code",
|
||||
name: "Code",
|
||||
isActive: () => editor?.isActive("code") || editor?.isActive("codeBlock"),
|
||||
command: () => toggleCodeBlock(editor),
|
||||
icon: CodeIcon,
|
||||
}) as const satisfies EditorMenuItem;
|
||||
export const CodeItem = (editor: Editor): EditorMenuItem => ({
|
||||
key: "code",
|
||||
name: "Code",
|
||||
isActive: () => editor?.isActive("code") || editor?.isActive("codeBlock"),
|
||||
command: () => toggleCodeBlock(editor),
|
||||
icon: CodeIcon,
|
||||
});
|
||||
|
||||
export const TableItem = (editor: Editor) =>
|
||||
({
|
||||
key: "table",
|
||||
name: "Table",
|
||||
isActive: () => editor?.isActive("table"),
|
||||
command: () => insertTableCommand(editor),
|
||||
icon: TableIcon,
|
||||
}) as const satisfies EditorMenuItem;
|
||||
export const TableItem = (editor: Editor): EditorMenuItem => ({
|
||||
key: "table",
|
||||
name: "Table",
|
||||
isActive: () => editor?.isActive("table"),
|
||||
command: () => insertTableCommand(editor),
|
||||
icon: TableIcon,
|
||||
});
|
||||
|
||||
export const ImageItem = (editor: Editor, uploadFile: UploadImage) =>
|
||||
({
|
||||
|
|
@ -240,6 +223,3 @@ export function getEditorMenuItems(editor: Editor | null, uploadFile: UploadImag
|
|||
ImageItem(editor, uploadFile),
|
||||
];
|
||||
}
|
||||
|
||||
export type EditorMenuItemNames =
|
||||
ReturnType<typeof getEditorMenuItems> extends (infer U)[] ? (U extends { key: infer N } ? N : never) : never;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@ import {
|
|||
Heading1,
|
||||
Heading2,
|
||||
Heading3,
|
||||
Heading4,
|
||||
Heading5,
|
||||
Heading6,
|
||||
ImageIcon,
|
||||
List,
|
||||
ListOrdered,
|
||||
|
|
@ -91,7 +94,7 @@ const getSuggestionItems =
|
|||
title: "Text",
|
||||
description: "Just start typing with plain text.",
|
||||
searchTerms: ["p", "paragraph"],
|
||||
icon: <CaseSensitive className="h-3.5 w-3.5" />,
|
||||
icon: <CaseSensitive className="size-3.5" />,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
if (range) {
|
||||
editor.chain().focus().deleteRange(range).clearNodes().run();
|
||||
|
|
@ -100,61 +103,91 @@ const getSuggestionItems =
|
|||
},
|
||||
},
|
||||
{
|
||||
key: "heading_1",
|
||||
key: "h1",
|
||||
title: "Heading 1",
|
||||
description: "Big section heading.",
|
||||
searchTerms: ["title", "big", "large"],
|
||||
icon: <Heading1 className="h-3.5 w-3.5" />,
|
||||
icon: <Heading1 className="size-3.5" />,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
toggleHeadingOne(editor, range);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "heading_2",
|
||||
key: "h2",
|
||||
title: "Heading 2",
|
||||
description: "Medium section heading.",
|
||||
searchTerms: ["subtitle", "medium"],
|
||||
icon: <Heading2 className="h-3.5 w-3.5" />,
|
||||
icon: <Heading2 className="size-3.5" />,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
toggleHeadingTwo(editor, range);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "heading_3",
|
||||
key: "h3",
|
||||
title: "Heading 3",
|
||||
description: "Small section heading.",
|
||||
searchTerms: ["subtitle", "small"],
|
||||
icon: <Heading3 className="h-3.5 w-3.5" />,
|
||||
icon: <Heading3 className="size-3.5" />,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
toggleHeadingThree(editor, range);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "todo_list",
|
||||
key: "h4",
|
||||
title: "Heading 4",
|
||||
description: "Small section heading.",
|
||||
searchTerms: ["subtitle", "small"],
|
||||
icon: <Heading4 className="size-3.5" />,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
toggleHeadingThree(editor, range);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "h5",
|
||||
title: "Heading 5",
|
||||
description: "Small section heading.",
|
||||
searchTerms: ["subtitle", "small"],
|
||||
icon: <Heading5 className="size-3.5" />,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
toggleHeadingThree(editor, range);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "h6",
|
||||
title: "Heading 6",
|
||||
description: "Small section heading.",
|
||||
searchTerms: ["subtitle", "small"],
|
||||
icon: <Heading6 className="size-3.5" />,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
toggleHeadingThree(editor, range);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "to-do-list",
|
||||
title: "To do",
|
||||
description: "Track tasks with a to-do list.",
|
||||
searchTerms: ["todo", "task", "list", "check", "checkbox"],
|
||||
icon: <ListTodo className="h-3.5 w-3.5" />,
|
||||
icon: <ListTodo className="size-3.5" />,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
toggleTaskList(editor, range);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "bullet_list",
|
||||
key: "bulleted-list",
|
||||
title: "Bullet list",
|
||||
description: "Create a simple bullet list.",
|
||||
searchTerms: ["unordered", "point"],
|
||||
icon: <List className="h-3.5 w-3.5" />,
|
||||
icon: <List className="size-3.5" />,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
toggleBulletList(editor, range);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "numbered_list",
|
||||
key: "numbered-list",
|
||||
title: "Numbered list",
|
||||
description: "Create a list with numbering.",
|
||||
searchTerms: ["ordered"],
|
||||
icon: <ListOrdered className="h-3.5 w-3.5" />,
|
||||
icon: <ListOrdered className="size-3.5" />,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
toggleOrderedList(editor, range);
|
||||
},
|
||||
|
|
@ -164,25 +197,25 @@ const getSuggestionItems =
|
|||
title: "Table",
|
||||
description: "Create a table",
|
||||
searchTerms: ["table", "cell", "db", "data", "tabular"],
|
||||
icon: <Table className="h-3.5 w-3.5" />,
|
||||
icon: <Table className="size-3.5" />,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
insertTableCommand(editor, range);
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "quote_block",
|
||||
key: "quote",
|
||||
title: "Quote",
|
||||
description: "Capture a quote.",
|
||||
searchTerms: ["blockquote"],
|
||||
icon: <Quote className="h-3.5 w-3.5" />,
|
||||
icon: <Quote className="size-3.5" />,
|
||||
command: ({ editor, range }: CommandProps) => toggleBlockquote(editor, range),
|
||||
},
|
||||
{
|
||||
key: "code_block",
|
||||
key: "code",
|
||||
title: "Code",
|
||||
description: "Capture a code snippet.",
|
||||
searchTerms: ["codeblock"],
|
||||
icon: <Code2 className="h-3.5 w-3.5" />,
|
||||
icon: <Code2 className="size-3.5" />,
|
||||
command: ({ editor, range }: CommandProps) => editor.chain().focus().deleteRange(range).toggleCodeBlock().run(),
|
||||
},
|
||||
{
|
||||
|
|
@ -190,7 +223,7 @@ const getSuggestionItems =
|
|||
title: "Image",
|
||||
description: "Upload an image from your computer.",
|
||||
searchTerms: ["img", "photo", "picture", "media"],
|
||||
icon: <ImageIcon className="h-3.5 w-3.5" />,
|
||||
icon: <ImageIcon className="size-3.5" />,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
insertImageCommand(editor, uploadFile, null, range);
|
||||
},
|
||||
|
|
@ -200,7 +233,7 @@ const getSuggestionItems =
|
|||
title: "Divider",
|
||||
description: "Visually divide blocks.",
|
||||
searchTerms: ["line", "divider", "horizontal", "rule", "separate"],
|
||||
icon: <MinusSquare className="h-3.5 w-3.5" />,
|
||||
icon: <MinusSquare className="size-3.5" />,
|
||||
command: ({ editor, range }: CommandProps) => {
|
||||
editor.chain().focus().deleteRange(range).setHorizontalRule().run();
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { Selection } from "@tiptap/pm/state";
|
|||
import { EditorProps } from "@tiptap/pm/view";
|
||||
import { useEditor as useCustomEditor, Editor } from "@tiptap/react";
|
||||
// components
|
||||
import { EditorMenuItemNames, getEditorMenuItems } from "@/components/menus";
|
||||
import { getEditorMenuItems } from "@/components/menus";
|
||||
// extensions
|
||||
import { CoreEditorExtensions } from "@/extensions";
|
||||
// helpers
|
||||
|
|
@ -14,7 +14,15 @@ import { CollaborationProvider } from "@/plane-editor/providers";
|
|||
// props
|
||||
import { CoreEditorProps } from "@/props";
|
||||
// types
|
||||
import { DeleteImage, EditorRefApi, IMentionHighlight, IMentionSuggestion, RestoreImage, UploadImage } from "@/types";
|
||||
import {
|
||||
DeleteImage,
|
||||
EditorRefApi,
|
||||
IMentionHighlight,
|
||||
IMentionSuggestion,
|
||||
RestoreImage,
|
||||
TEditorCommands,
|
||||
UploadImage,
|
||||
} from "@/types";
|
||||
|
||||
export type TFileHandler = {
|
||||
cancel: () => void;
|
||||
|
|
@ -147,12 +155,12 @@ export const useEditor = ({
|
|||
insertContentAtSavedSelection(editorRef, content, savedSelection);
|
||||
}
|
||||
},
|
||||
executeMenuItemCommand: (itemName: EditorMenuItemNames) => {
|
||||
executeMenuItemCommand: (itemKey: TEditorCommands) => {
|
||||
const editorItems = getEditorMenuItems(editorRef.current, fileHandler.upload);
|
||||
|
||||
const getEditorMenuItem = (itemName: EditorMenuItemNames) => editorItems.find((item) => item.key === itemName);
|
||||
const getEditorMenuItem = (itemKey: TEditorCommands) => editorItems.find((item) => item.key === itemKey);
|
||||
|
||||
const item = getEditorMenuItem(itemName);
|
||||
const item = getEditorMenuItem(itemKey);
|
||||
if (item) {
|
||||
if (item.key === "image") {
|
||||
item.command(savedSelectionRef.current);
|
||||
|
|
@ -160,13 +168,13 @@ export const useEditor = ({
|
|||
item.command();
|
||||
}
|
||||
} else {
|
||||
console.warn(`No command found for item: ${itemName}`);
|
||||
console.warn(`No command found for item: ${itemKey}`);
|
||||
}
|
||||
},
|
||||
isMenuItemActive: (itemName: EditorMenuItemNames): boolean => {
|
||||
isMenuItemActive: (itemName: TEditorCommands): boolean => {
|
||||
const editorItems = getEditorMenuItems(editorRef.current, fileHandler.upload);
|
||||
|
||||
const getEditorMenuItem = (itemName: EditorMenuItemNames) => editorItems.find((item) => item.key === itemName);
|
||||
const getEditorMenuItem = (itemName: TEditorCommands) => editorItems.find((item) => item.key === itemName);
|
||||
const item = getEditorMenuItem(itemName);
|
||||
return item ? item.isActive() : false;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
// components
|
||||
import { EditorMenuItemNames } from "@/components/menus";
|
||||
// helpers
|
||||
import { IMarking } from "@/helpers/scroll-to-node";
|
||||
// hooks
|
||||
import { TFileHandler } from "@/hooks/use-editor";
|
||||
// types
|
||||
import { IMentionHighlight, IMentionSuggestion } from "@/types";
|
||||
import { IMentionHighlight, IMentionSuggestion, TEditorCommands } from "@/types";
|
||||
|
||||
export type EditorReadOnlyRefApi = {
|
||||
getMarkDown: () => string;
|
||||
|
|
@ -17,8 +15,8 @@ export type EditorReadOnlyRefApi = {
|
|||
|
||||
export interface EditorRefApi extends EditorReadOnlyRefApi {
|
||||
setEditorValueAtCursorPosition: (content: string) => void;
|
||||
executeMenuItemCommand: (itemName: EditorMenuItemNames) => void;
|
||||
isMenuItemActive: (itemName: EditorMenuItemNames) => boolean;
|
||||
executeMenuItemCommand: (itemKey: TEditorCommands) => void;
|
||||
isMenuItemActive: (itemKey: TEditorCommands) => boolean;
|
||||
onStateChange: (callback: () => void) => () => void;
|
||||
setFocusAtPosition: (position: number) => void;
|
||||
isEditorReadyToDiscard: () => boolean;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,34 @@
|
|||
import { ReactNode } from "react";
|
||||
import { Editor, Range } from "@tiptap/core";
|
||||
|
||||
export type TEditorCommands =
|
||||
| "text"
|
||||
| "h1"
|
||||
| "h2"
|
||||
| "h3"
|
||||
| "h4"
|
||||
| "h5"
|
||||
| "h6"
|
||||
| "bold"
|
||||
| "italic"
|
||||
| "underline"
|
||||
| "strikethrough"
|
||||
| "bulleted-list"
|
||||
| "numbered-list"
|
||||
| "to-do-list"
|
||||
| "quote"
|
||||
| "code"
|
||||
| "table"
|
||||
| "image"
|
||||
| "divider";
|
||||
|
||||
export type CommandProps = {
|
||||
editor: Editor;
|
||||
range: Range;
|
||||
};
|
||||
|
||||
export type ISlashCommandItem = {
|
||||
key: string;
|
||||
key: TEditorCommands;
|
||||
title: string;
|
||||
description: string;
|
||||
searchTerms: string[];
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import React, { useEffect, useState, useCallback } from "react";
|
||||
// editor
|
||||
import { EditorMenuItemNames, EditorRefApi } from "@plane/editor";
|
||||
import { EditorRefApi, TEditorCommands } from "@plane/editor";
|
||||
// ui
|
||||
import { Button, Tooltip } from "@plane/ui";
|
||||
// constants
|
||||
|
|
@ -11,7 +11,7 @@ import { TOOLBAR_ITEMS } from "@/constants/editor";
|
|||
import { cn } from "@/helpers/common.helper";
|
||||
|
||||
type Props = {
|
||||
executeCommand: (commandName: EditorMenuItemNames) => void;
|
||||
executeCommand: (commandKey: TEditorCommands) => void;
|
||||
handleSubmit: () => void;
|
||||
isCommentEmpty: boolean;
|
||||
isSubmitting: boolean;
|
||||
|
|
|
|||
|
|
@ -19,12 +19,12 @@ import {
|
|||
Underline,
|
||||
} from "lucide-react";
|
||||
// editor
|
||||
import { EditorMenuItemNames } from "@plane/editor";
|
||||
import { TEditorCommands } from "@plane/editor";
|
||||
|
||||
type TEditorTypes = "lite" | "document";
|
||||
|
||||
export type ToolbarMenuItem = {
|
||||
key: EditorMenuItemNames;
|
||||
key: TEditorCommands;
|
||||
name: string;
|
||||
icon: LucideIcon;
|
||||
shortcut?: string[];
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import React, { useEffect, useState, useCallback } from "react";
|
||||
import { Globe2, Lock, LucideIcon } from "lucide-react";
|
||||
// editor
|
||||
import { EditorMenuItemNames, EditorRefApi } from "@plane/editor";
|
||||
import { EditorRefApi, TEditorCommands } from "@plane/editor";
|
||||
// ui
|
||||
import { Button, Tooltip } from "@plane/ui";
|
||||
// constants
|
||||
|
|
@ -14,7 +14,7 @@ import { cn } from "@/helpers/common.helper";
|
|||
|
||||
type Props = {
|
||||
accessSpecifier?: EIssueCommentAccessSpecifier;
|
||||
executeCommand: (commandName: EditorMenuItemNames) => void;
|
||||
executeCommand: (commandKey: TEditorCommands) => void;
|
||||
handleAccessChange?: (accessKey: EIssueCommentAccessSpecifier) => void;
|
||||
handleSubmit: (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void;
|
||||
isCommentEmpty: boolean;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
import React, { useEffect, useState, useCallback } from "react";
|
||||
import { Check, ChevronDown } from "lucide-react";
|
||||
// editor
|
||||
import { EditorMenuItemNames, EditorRefApi } from "@plane/editor";
|
||||
import { EditorRefApi, TEditorCommands } from "@plane/editor";
|
||||
// ui
|
||||
import { CustomMenu, Tooltip } from "@plane/ui";
|
||||
// constants
|
||||
|
|
@ -18,7 +18,7 @@ type Props = {
|
|||
type ToolbarButtonProps = {
|
||||
item: ToolbarMenuItem;
|
||||
isActive: boolean;
|
||||
executeCommand: (commandName: EditorMenuItemNames) => void;
|
||||
executeCommand: (commandKey: TEditorCommands) => void;
|
||||
};
|
||||
|
||||
const ToolbarButton: React.FC<ToolbarButtonProps> = React.memo((props) => {
|
||||
|
|
|
|||
|
|
@ -20,12 +20,12 @@ import {
|
|||
Underline,
|
||||
} from "lucide-react";
|
||||
// editor
|
||||
import { EditorMenuItemNames } from "@plane/editor";
|
||||
import { TEditorCommands } from "@plane/editor";
|
||||
|
||||
type TEditorTypes = "lite" | "document";
|
||||
|
||||
export type ToolbarMenuItem = {
|
||||
key: EditorMenuItemNames;
|
||||
key: TEditorCommands;
|
||||
name: string;
|
||||
icon: LucideIcon;
|
||||
shortcut?: string[];
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue