Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: editor extensions #5871

Draft
wants to merge 3 commits into
base: preview
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/editor/src/core/extensions/code/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,7 @@ export const CustomCodeBlockExtension = CodeBlockLowlight.extend({
lowlight,
defaultLanguage: "plaintext",
exitOnTripleEnter: false,
HTMLAttributes: {
class: "",
},
});
74 changes: 12 additions & 62 deletions packages/editor/src/core/extensions/core-without-props.ts
Original file line number Diff line number Diff line change
@@ -1,63 +1,26 @@
import TaskItem from "@tiptap/extension-task-item";
import TaskList from "@tiptap/extension-task-list";
import { Extension, Mark, Node } from "@tiptap/core";
import TextStyle from "@tiptap/extension-text-style";
import TiptapUnderline from "@tiptap/extension-underline";
import StarterKit from "@tiptap/starter-kit";
// extensions
// helpers
import { isValidHttpUrl } from "@/helpers/common";
import { CustomCodeBlockExtensionWithoutProps } from "./code/without-props";
import { CustomCodeInlineExtension } from "./code-inline";
import { CustomColorExtension } from "./custom-color";
import { CustomLinkExtension } from "./custom-link";
import { CustomHorizontalRule } from "./horizontal-rule";
import { ImageExtensionWithoutProps } from "./image";
import { CustomImageComponentWithoutProps } from "./image/image-component-without-props";
import { ImageExtensionWithoutProps } from "./image";
import { IssueWidgetWithoutProps } from "./issue-embed/issue-embed-without-props";
import { CustomMentionWithoutProps } from "./mentions/mentions-without-props";
import { CustomQuoteExtension } from "./quote";
import { TableHeader, TableCell, TableRow, Table } from "./table";
import { CustomColorExtension } from "./custom-color";
import { CustomStarterKit } from "./starter-kit";
import { CustomTableExtension } from "./table";
import { CustomTodoListExtension } from "./todo-list";

export const CoreEditorExtensionsWithoutProps = [
StarterKit.configure({
bulletList: {
HTMLAttributes: {
class: "list-disc pl-7 space-y-2",
},
},
orderedList: {
HTMLAttributes: {
class: "list-decimal pl-7 space-y-2",
},
},
listItem: {
HTMLAttributes: {
class: "not-prose space-y-2",
},
},
code: false,
codeBlock: false,
horizontalRule: false,
blockquote: false,
dropcursor: false,
}),
export const CoreEditorExtensionsWithoutProps: (Extension<any, any> | Node<any, any> | Mark<any, any>)[] = [
CustomStarterKit,
CustomQuoteExtension,
CustomHorizontalRule.configure({
HTMLAttributes: {
class: "my-4 border-custom-border-400",
},
}),
CustomLinkExtension.configure({
openOnClick: true,
autolink: true,
linkOnPaste: true,
protocols: ["http", "https"],
validate: (url: string) => isValidHttpUrl(url),
HTMLAttributes: {
class:
"text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer",
},
}),
CustomHorizontalRule,
CustomLinkExtension,
ImageExtensionWithoutProps().configure({
HTMLAttributes: {
class: "rounded-md",
Expand All @@ -66,23 +29,10 @@ export const CoreEditorExtensionsWithoutProps = [
CustomImageComponentWithoutProps(),
TiptapUnderline,
TextStyle,
TaskList.configure({
HTMLAttributes: {
class: "not-prose pl-2 space-y-2",
},
}),
TaskItem.configure({
HTMLAttributes: {
class: "flex",
},
nested: true,
}),
...CustomTodoListExtension(),
CustomCodeInlineExtension,
CustomCodeBlockExtensionWithoutProps,
Table,
TableHeader,
TableCell,
TableRow,
...CustomTableExtension,
CustomMentionWithoutProps(),
CustomColorExtension,
];
Expand Down
12 changes: 12 additions & 0 deletions packages/editor/src/core/extensions/custom-link/extension.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Mark, markPasteRule, mergeAttributes, PasteRuleMatch } from "@tiptap/core";
import { Plugin } from "@tiptap/pm/state";
import { find, registerCustomProtocol, reset } from "linkifyjs";
// helpers
import { isValidHttpUrl } from "@/helpers/common";
import { autolink } from "./helpers/autolink";
import { clickHandler } from "./helpers/clickHandler";
import { pasteHandler } from "./helpers/pasteHandler";
Expand Down Expand Up @@ -242,4 +244,14 @@ export const CustomLinkExtension = Mark.create<LinkOptions>({

return plugins;
},
}).configure({
openOnClick: true,
autolink: true,
linkOnPaste: true,
protocols: ["http", "https"],
validate: (url: string) => isValidHttpUrl(url),
HTMLAttributes: {
class:
"text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer",
},
});
105 changes: 15 additions & 90 deletions packages/editor/src/core/extensions/extensions.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import { Extension, Mark, Node } from "@tiptap/core";
import CharacterCount from "@tiptap/extension-character-count";
import Placeholder from "@tiptap/extension-placeholder";
import TaskItem from "@tiptap/extension-task-item";
import TaskList from "@tiptap/extension-task-list";
import TextStyle from "@tiptap/extension-text-style";
import TiptapUnderline from "@tiptap/extension-underline";
import StarterKit from "@tiptap/starter-kit";
import { Markdown } from "tiptap-markdown";
// extensions
import {
Expand All @@ -17,18 +14,16 @@ import {
CustomKeymap,
CustomLinkExtension,
CustomMention,
CustomPlaceholderExtension,
CustomQuoteExtension,
CustomStarterKit,
CustomTableExtension,
CustomTodoListExtension,
CustomTypographyExtension,
DropHandlerExtension,
ImageExtension,
ListKeymap,
Table,
TableCell,
TableHeader,
TableRow,
} from "@/extensions";
// helpers
import { isValidHttpUrl } from "@/helpers/common";
// types
import { IMentionHighlight, IMentionSuggestion, TFileHandler } from "@/types";

Expand All @@ -43,55 +38,19 @@ type TArguments = {
tabIndex?: number;
};

export const CoreEditorExtensions = (args: TArguments) => {
export const CoreEditorExtensions = (args: TArguments): (Extension<any, any> | Node<any, any> | Mark<any, any>)[] => {
const { enableHistory, fileHandler, mentionConfig, placeholder, tabIndex } = args;

return [
StarterKit.configure({
bulletList: {
HTMLAttributes: {
class: "list-disc pl-7 space-y-2",
},
},
orderedList: {
HTMLAttributes: {
class: "list-decimal pl-7 space-y-2",
},
},
listItem: {
HTMLAttributes: {
class: "not-prose space-y-2",
},
},
code: false,
codeBlock: false,
horizontalRule: false,
blockquote: false,
dropcursor: {
class: "text-custom-text-300",
},
CustomStarterKit.configure({
...(enableHistory ? {} : { history: false }),
}),
CustomQuoteExtension,
DropHandlerExtension(),
CustomHorizontalRule.configure({
HTMLAttributes: {
class: "my-4 border-custom-border-400",
},
}),
CustomHorizontalRule,
CustomKeymap,
ListKeymap({ tabIndex }),
CustomLinkExtension.configure({
openOnClick: true,
autolink: true,
linkOnPaste: true,
protocols: ["http", "https"],
validate: (url: string) => isValidHttpUrl(url),
HTMLAttributes: {
class:
"text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer",
},
}),
CustomLinkExtension,
CustomTypographyExtension,
ImageExtension(fileHandler).configure({
HTMLAttributes: {
Expand All @@ -101,57 +60,23 @@ export const CoreEditorExtensions = (args: TArguments) => {
CustomImageExtension(fileHandler),
TiptapUnderline,
TextStyle,
TaskList.configure({
HTMLAttributes: {
class: "not-prose pl-2 space-y-2",
},
}),
TaskItem.configure({
HTMLAttributes: {
class: "relative",
},
nested: true,
}),
CustomCodeBlockExtension.configure({
HTMLAttributes: {
class: "",
},
}),
...CustomTodoListExtension(),
CustomCodeBlockExtension,
CustomCodeMarkPlugin,
CustomCodeInlineExtension,
Markdown.configure({
html: true,
transformPastedText: true,
breaks: true,
}),
Table,
TableHeader,
TableCell,
TableRow,
...CustomTableExtension,
CustomMention({
mentionSuggestions: mentionConfig.mentionSuggestions,
mentionHighlights: mentionConfig.mentionHighlights,
readonly: false,
readOnly: false,
}),
Placeholder.configure({
placeholder: ({ editor, node }) => {
if (node.type.name === "heading") return `Heading ${node.attrs.level}`;

if (editor.storage.imageComponent.uploadInProgress) return "";

const shouldHidePlaceholder =
editor.isActive("table") || editor.isActive("codeBlock") || editor.isActive("image");

if (shouldHidePlaceholder) return "";

if (placeholder) {
if (typeof placeholder === "string") return placeholder;
else return placeholder(editor.isFocused, editor.getHTML());
}

return "Press '/' for commands...";
},
includeChildren: true,
CustomPlaceholderExtension({
placeholder,
}),
CharacterCount,
CustomColorExtension,
Expand Down
4 changes: 4 additions & 0 deletions packages/editor/src/core/extensions/horizontal-rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,8 @@ export const CustomHorizontalRule = Node.create<HorizontalRuleOptions>({
}),
];
},
}).configure({
HTMLAttributes: {
class: "my-4 border-custom-border-400",
},
});
6 changes: 4 additions & 2 deletions packages/editor/src/core/extensions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ export * from "./custom-color";
export * from "./drop";
export * from "./enter-key-extension";
export * from "./extensions";
export * from "./headers";
export * from "./horizontal-rule";
export * from "./keymap";
export * from "./placeholder";
export * from "./quote";
export * from "./read-only-extensions";
export * from "./side-menu";
export * from "./slash-commands";
export * from "./headers";
export * from "./starter-kit";
export * from "./todo-list";
13 changes: 6 additions & 7 deletions packages/editor/src/core/extensions/mentions/extension.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ interface CustomMentionOptions extends MentionOptions {
export const CustomMention = ({
mentionHighlights,
mentionSuggestions,
readonly,
readOnly,
}: {
mentionSuggestions?: () => Promise<IMentionSuggestion[]>;
mentionHighlights?: () => Promise<IMentionHighlight[]>;
readonly: boolean;
readOnly: boolean;
}) =>
Mention.extend<CustomMentionOptions>({
addStorage(this) {
Expand Down Expand Up @@ -69,7 +69,7 @@ export const CustomMention = ({
HTMLAttributes: {
class: "mention",
},
readonly: readonly,
readonly: readOnly,
mentionHighlights,
suggestion: {
// @ts-expect-error - Tiptap types are incorrect
Expand Down Expand Up @@ -107,10 +107,9 @@ export const CustomMention = ({
return;
}

popup &&
popup[0].setProps({
getReferenceClientRect: props.clientRect,
});
popup?.[0].setProps({
getReferenceClientRect: props.clientRect,
});
},

onKeyDown: (props: { event: KeyboardEvent }) => {
Expand Down
30 changes: 30 additions & 0 deletions packages/editor/src/core/extensions/placeholder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Placeholder from "@tiptap/extension-placeholder";

type Props = {
placeholder?: string | ((isFocused: boolean, value: string) => string);
};

export const CustomPlaceholderExtension = (props: Props) => {
const { placeholder } = props;

return Placeholder.configure({
placeholder: ({ editor, node }) => {
if (node.type.name === "heading") return `Heading ${node.attrs.level}`;

if (editor.storage.imageComponent.uploadInProgress) return "";

const shouldHidePlaceholder =
editor.isActive("table") || editor.isActive("codeBlock") || editor.isActive("image");

if (shouldHidePlaceholder) return "";

if (placeholder) {
if (typeof placeholder === "string") return placeholder;
else return placeholder(editor.isFocused, editor.getHTML());
}

return "Press '/' for commands...";
},
includeChildren: true,
});
};
Loading
Loading