@monolith-forensics/monolith-ui 1.9.1-dev.1 → 1.9.1-dev.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/DropDownMenu/components/MenuItemList.js +32 -12
  2. package/dist/DropDownMenu/components/StyledInnerItemContainer.js +1 -0
  3. package/dist/RichTextEditor/Components/BubbleMenu.d.ts +8 -8
  4. package/dist/RichTextEditor/Components/BubbleMenu.js +198 -93
  5. package/dist/RichTextEditor/Components/CodeBlockCopyButton.d.ts +9 -0
  6. package/dist/RichTextEditor/Components/CodeBlockCopyButton.js +45 -0
  7. package/dist/RichTextEditor/Components/CodeBlockFormatButton.d.ts +10 -0
  8. package/dist/RichTextEditor/Components/CodeBlockFormatButton.js +60 -0
  9. package/dist/RichTextEditor/Components/CodeBlockLanguageSelect.d.ts +6 -0
  10. package/dist/RichTextEditor/Components/CodeBlockLanguageSelect.js +21 -0
  11. package/dist/RichTextEditor/Components/CodeBlockNodeView.d.ts +3 -0
  12. package/dist/RichTextEditor/Components/CodeBlockNodeView.js +27 -0
  13. package/dist/RichTextEditor/Components/CodeBlockWrapButton.d.ts +10 -0
  14. package/dist/RichTextEditor/Components/CodeBlockWrapButton.js +17 -0
  15. package/dist/RichTextEditor/Components/LinkEditor.d.ts +8 -0
  16. package/dist/RichTextEditor/Components/LinkEditor.js +94 -0
  17. package/dist/RichTextEditor/Enums/Controls.d.ts +5 -1
  18. package/dist/RichTextEditor/Enums/Controls.js +4 -0
  19. package/dist/RichTextEditor/Enums/Extensions.d.ts +4 -0
  20. package/dist/RichTextEditor/Enums/Extensions.js +4 -0
  21. package/dist/RichTextEditor/Enums/HighlightColors.d.ts +9 -0
  22. package/dist/RichTextEditor/Enums/HighlightColors.js +10 -0
  23. package/dist/RichTextEditor/Enums/SlashCommands.d.ts +1 -0
  24. package/dist/RichTextEditor/Enums/SlashCommands.js +1 -0
  25. package/dist/RichTextEditor/Extensions/getSlashCommand.js +16 -1
  26. package/dist/RichTextEditor/Extensions/getTiptapExtensions.d.ts +10 -2
  27. package/dist/RichTextEditor/Extensions/getTiptapExtensions.js +158 -31
  28. package/dist/RichTextEditor/Plugins/ImageActionsPlugin.js +6 -109
  29. package/dist/RichTextEditor/Plugins/UploadImagesPlugin.js +1 -0
  30. package/dist/RichTextEditor/RichTextEditor.d.ts +5 -2
  31. package/dist/RichTextEditor/RichTextEditor.js +186 -13
  32. package/dist/RichTextEditor/Toolbar/Control.d.ts +6 -2
  33. package/dist/RichTextEditor/Toolbar/Control.js +13 -6
  34. package/dist/RichTextEditor/Toolbar/Controls.d.ts +2 -0
  35. package/dist/RichTextEditor/Toolbar/Controls.js +14 -0
  36. package/dist/RichTextEditor/Toolbar/ControlsGroup.js +1 -0
  37. package/dist/RichTextEditor/Toolbar/Toolbar.js +62 -9
  38. package/dist/RichTextEditor/Utils/codeBlockUtils.d.ts +20 -0
  39. package/dist/RichTextEditor/Utils/codeBlockUtils.js +137 -0
  40. package/dist/RichTextEditor/Utils/codeUtils.d.ts +3 -0
  41. package/dist/RichTextEditor/Utils/codeUtils.js +12 -0
  42. package/dist/RichTextEditor/Utils/linkUtils.d.ts +19 -0
  43. package/dist/RichTextEditor/Utils/linkUtils.js +57 -0
  44. package/package.json +8 -1
  45. package/dist/RichTextEditor/Extensions/BubbleMenuExtension.d.ts +0 -7
  46. package/dist/RichTextEditor/Extensions/BubbleMenuExtension.js +0 -157
@@ -0,0 +1,21 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { CodeXmlIcon } from "lucide-react";
3
+ import { DropDownMenu } from "../../DropDownMenu";
4
+ import { CODE_BLOCK_LANGUAGES, getCodeBlockLanguage, getCodeBlockLanguageOption, setCodeBlockLanguage, } from "../Utils/codeBlockUtils";
5
+ const CodeBlockLanguageSelect = ({ editor }) => {
6
+ const language = getCodeBlockLanguage(editor);
7
+ const selectedLanguage = getCodeBlockLanguageOption(language);
8
+ return (_jsx(DropDownMenu, { data: CODE_BLOCK_LANGUAGES, value: [selectedLanguage], enableSelectedOptionStyling: true, size: "xs", variant: "outlined", disabled: !(editor === null || editor === void 0 ? void 0 : editor.isActive("codeBlock")), onItemSelect: (item) => {
9
+ setCodeBlockLanguage(editor, item.value);
10
+ }, buttonProps: {
11
+ title: "Select code language",
12
+ leftSection: _jsx(CodeXmlIcon, { size: 12 }),
13
+ style: { padding: "1px 6px" },
14
+ }, dropDownProps: {
15
+ style: {
16
+ width: 150,
17
+ height: 250,
18
+ },
19
+ }, children: selectedLanguage.label }));
20
+ };
21
+ export default CodeBlockLanguageSelect;
@@ -0,0 +1,3 @@
1
+ import { ReactNodeViewProps } from "@tiptap/react";
2
+ declare const CodeBlockNodeView: ({ editor, getPos, node, updateAttributes, }: ReactNodeViewProps) => import("react/jsx-runtime").JSX.Element;
3
+ export default CodeBlockNodeView;
@@ -0,0 +1,27 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
+ import { NodeViewContent, NodeViewWrapper, } from "@tiptap/react";
12
+ import CodeBlockCopyButton from "./CodeBlockCopyButton";
13
+ import CodeBlockWrapButton from "./CodeBlockWrapButton";
14
+ import CodeBlockFormatButton from "./CodeBlockFormatButton";
15
+ import { formatCodeBlockText, replaceCodeBlockContent, } from "../Utils/codeBlockUtils";
16
+ const CodeBlockNodeView = ({ editor, getPos, node, updateAttributes, }) => {
17
+ const language = node.attrs.language;
18
+ const wrap = Boolean(node.attrs.wrap);
19
+ return (_jsxs(NodeViewWrapper, { as: "pre", className: "editor-code-block", "data-language": language || "plaintext", "data-wrap": wrap ? "true" : "false", children: [_jsxs("div", { className: "editor-code-block-actions", contentEditable: false, children: [_jsx(CodeBlockWrapButton, { className: "editor-code-block-action", active: wrap, onToggle: () => updateAttributes({ wrap: !wrap }) }), _jsx(CodeBlockFormatButton, { className: "editor-code-block-action", language: language, onFormat: () => __awaiter(void 0, void 0, void 0, function* () {
20
+ const pos = getPos();
21
+ if (typeof pos !== "number")
22
+ return;
23
+ const formatted = yield formatCodeBlockText(node.textContent, language);
24
+ replaceCodeBlockContent(editor, pos + 1, pos + node.nodeSize - 1, formatted);
25
+ }) }), _jsx(CodeBlockCopyButton, { className: "editor-code-block-action", text: node.textContent })] }), _jsx(NodeViewContent, { as: "code", className: `hljs language-${language || "plaintext"}`, spellCheck: false })] }));
26
+ };
27
+ export default CodeBlockNodeView;
@@ -0,0 +1,10 @@
1
+ import { Editor } from "@tiptap/react";
2
+ type CodeBlockWrapButtonProps = {
3
+ className?: string;
4
+ editor?: Editor | null;
5
+ active?: boolean;
6
+ onToggle?: () => void;
7
+ size?: "xs" | "sm";
8
+ };
9
+ declare const CodeBlockWrapButton: ({ className, editor, active, onToggle, size, }: CodeBlockWrapButtonProps) => import("react/jsx-runtime").JSX.Element;
10
+ export default CodeBlockWrapButton;
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { WrapTextIcon } from "lucide-react";
3
+ import { Button } from "../../Button";
4
+ import { getCodeBlockWrap, toggleCodeBlockWrap, } from "../Utils/codeBlockUtils";
5
+ const CodeBlockWrapButton = ({ className, editor, active, onToggle, size = "xs", }) => {
6
+ const isWrapped = active !== null && active !== void 0 ? active : getCodeBlockWrap(editor || null);
7
+ return (_jsx(Button, { className: className, size: size, variant: "outlined", title: isWrapped ? "Disable code wrapping" : "Enable code wrapping", "aria-label": isWrapped ? "Disable code wrapping" : "Enable code wrapping", selected: isWrapped, disabled: !onToggle && !(editor === null || editor === void 0 ? void 0 : editor.isActive("codeBlock")), onClick: (event) => {
8
+ event.preventDefault();
9
+ event.stopPropagation();
10
+ if (onToggle) {
11
+ onToggle();
12
+ return;
13
+ }
14
+ toggleCodeBlockWrap(editor || null);
15
+ }, children: _jsx(WrapTextIcon, { size: 14 }) }));
16
+ };
17
+ export default CodeBlockWrapButton;
@@ -0,0 +1,8 @@
1
+ import { Editor } from "@tiptap/react";
2
+ type LinkEditorProps = {
3
+ editor: Editor;
4
+ onClose?: () => void;
5
+ autoFocus?: boolean;
6
+ };
7
+ export declare const LinkEditor: React.FC<LinkEditorProps>;
8
+ export default LinkEditor;
@@ -0,0 +1,94 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useMemo, useRef, useState, } from "react";
3
+ import styled from "styled-components";
4
+ import { ExternalLinkIcon, SaveIcon, UnlinkIcon } from "lucide-react";
5
+ import Input from "../../Input";
6
+ import { Button } from "../../Button";
7
+ import { getLinkAttributes, normalizeLinkUrl, openLink, } from "../Utils/linkUtils";
8
+ const LinkEditorContent = styled.form `
9
+ display: flex;
10
+ align-items: center;
11
+ gap: 6px;
12
+ min-width: 280px;
13
+ `;
14
+ const LinkInput = styled(Input) `
15
+ min-width: 190px;
16
+ `;
17
+ const LinkActions = styled.div `
18
+ display: flex;
19
+ align-items: center;
20
+ gap: 4px;
21
+ `;
22
+ const LinkEditorButton = styled(Button) `
23
+ padding: 0 6px;
24
+ `;
25
+ const getInitialHref = (editor) => editor.getAttributes("link").href || "";
26
+ export const LinkEditor = ({ editor, onClose, autoFocus, }) => {
27
+ const inputRef = useRef(null);
28
+ const [href, setHref] = useState(() => getInitialHref(editor));
29
+ const currentHref = getInitialHref(editor);
30
+ const normalizedLink = useMemo(() => normalizeLinkUrl(href), [href]);
31
+ const hasLink = Boolean(currentHref);
32
+ useEffect(() => {
33
+ setHref(getInitialHref(editor));
34
+ }, [editor, editor.state.selection.from, editor.state.selection.to]);
35
+ useEffect(() => {
36
+ if (!autoFocus)
37
+ return;
38
+ window.requestAnimationFrame(() => {
39
+ var _a, _b;
40
+ (_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
41
+ (_b = inputRef.current) === null || _b === void 0 ? void 0 : _b.select();
42
+ });
43
+ }, [autoFocus]);
44
+ const handleSave = () => {
45
+ if (!normalizedLink.isValid)
46
+ return;
47
+ const { from, to, empty } = editor.state.selection;
48
+ const attributes = getLinkAttributes(normalizedLink.href);
49
+ if (empty && hasLink) {
50
+ editor.chain().focus().extendMarkRange("link").setLink(attributes).run();
51
+ }
52
+ else if (empty) {
53
+ editor
54
+ .chain()
55
+ .focus()
56
+ .insertContent({
57
+ type: "text",
58
+ text: normalizedLink.href,
59
+ marks: [
60
+ {
61
+ type: "link",
62
+ attrs: attributes,
63
+ },
64
+ ],
65
+ })
66
+ .run();
67
+ }
68
+ else {
69
+ editor
70
+ .chain()
71
+ .focus()
72
+ .setTextSelection({ from, to })
73
+ .setLink(attributes)
74
+ .run();
75
+ }
76
+ onClose === null || onClose === void 0 ? void 0 : onClose();
77
+ };
78
+ const handleRemove = () => {
79
+ editor.chain().focus().extendMarkRange("link").unsetLink().run();
80
+ onClose === null || onClose === void 0 ? void 0 : onClose();
81
+ };
82
+ const handleSubmit = (event) => {
83
+ event.preventDefault();
84
+ handleSave();
85
+ };
86
+ const handleKeyDown = (event) => {
87
+ if (event.key === "Escape") {
88
+ event.preventDefault();
89
+ onClose === null || onClose === void 0 ? void 0 : onClose();
90
+ }
91
+ };
92
+ return (_jsxs(LinkEditorContent, { onSubmit: handleSubmit, children: [_jsx(LinkInput, { ref: inputRef, "aria-label": "Enter URL", placeholder: "https://example.com/", size: "xs", variant: "outlined", value: href, onChange: (event) => setHref(event.target.value), onKeyDown: handleKeyDown }), _jsxs(LinkActions, { children: [hasLink && (_jsxs(_Fragment, { children: [_jsx(LinkEditorButton, { "aria-label": "Open link", title: "Open link", size: "xs", variant: "subtle", type: "button", onClick: () => openLink(currentHref), children: _jsx(ExternalLinkIcon, { size: 14 }) }), _jsx(LinkEditorButton, { "aria-label": "Remove link", title: "Remove link", size: "xs", variant: "subtle", type: "button", onClick: handleRemove, children: _jsx(UnlinkIcon, { size: 14 }) })] })), _jsx(LinkEditorButton, { "aria-label": "Save link", title: "Save link", size: "xs", variant: "subtle", type: "submit", disabled: !normalizedLink.isValid, children: _jsx(SaveIcon, { size: 14 }) })] })] }));
93
+ };
94
+ export default LinkEditor;
@@ -5,6 +5,8 @@ export declare enum Controls {
5
5
  ITALIC = "italic",
6
6
  UNDERLINE = "underline",
7
7
  STRIKE = "strike",
8
+ CODE = "code",
9
+ CODE_BLOCK = "codeBlock",
8
10
  HEADING_1 = "heading_1",
9
11
  HEADING_2 = "heading_2",
10
12
  HEADING_3 = "heading_3",
@@ -16,5 +18,7 @@ export declare enum Controls {
16
18
  TEXT_ALIGN_RIGHT = "textAlignRight",
17
19
  TEXT_ALIGN_JUSTIFIED = "textAlignJustified",
18
20
  FONT = "font",
19
- COLOR = "color"
21
+ COLOR = "color",
22
+ HIGHLIGHT = "highlight",
23
+ LINK = "link"
20
24
  }
@@ -6,6 +6,8 @@ export var Controls;
6
6
  Controls["ITALIC"] = "italic";
7
7
  Controls["UNDERLINE"] = "underline";
8
8
  Controls["STRIKE"] = "strike";
9
+ Controls["CODE"] = "code";
10
+ Controls["CODE_BLOCK"] = "codeBlock";
9
11
  Controls["HEADING_1"] = "heading_1";
10
12
  Controls["HEADING_2"] = "heading_2";
11
13
  Controls["HEADING_3"] = "heading_3";
@@ -18,4 +20,6 @@ export var Controls;
18
20
  Controls["TEXT_ALIGN_JUSTIFIED"] = "textAlignJustified";
19
21
  Controls["FONT"] = "font";
20
22
  Controls["COLOR"] = "color";
23
+ Controls["HIGHLIGHT"] = "highlight";
24
+ Controls["LINK"] = "link";
21
25
  })(Controls || (Controls = {}));
@@ -4,7 +4,11 @@ export declare enum Extensions {
4
4
  Underline = "underline",
5
5
  Bold = "bold",
6
6
  Italic = "italic",
7
+ Code = "code",
8
+ CodeBlock = "codeBlock",
7
9
  Color = "color",
10
+ Highlight = "highlight",
11
+ Link = "link",
8
12
  TextStyle = "textStyle",
9
13
  Strike = "strike",
10
14
  BulletList = "bulletList",
@@ -5,7 +5,11 @@ export var Extensions;
5
5
  Extensions["Underline"] = "underline";
6
6
  Extensions["Bold"] = "bold";
7
7
  Extensions["Italic"] = "italic";
8
+ Extensions["Code"] = "code";
9
+ Extensions["CodeBlock"] = "codeBlock";
8
10
  Extensions["Color"] = "color";
11
+ Extensions["Highlight"] = "highlight";
12
+ Extensions["Link"] = "link";
9
13
  Extensions["TextStyle"] = "textStyle";
10
14
  Extensions["Strike"] = "strike";
11
15
  Extensions["BulletList"] = "bulletList";
@@ -0,0 +1,9 @@
1
+ declare enum HighlightColors {
2
+ Yellow = "rgba(250, 204, 21, 0.38)",
3
+ Green = "rgba(34, 197, 94, 0.34)",
4
+ Blue = "rgba(59, 130, 246, 0.34)",
5
+ Pink = "rgba(236, 72, 153, 0.32)",
6
+ Purple = "rgba(168, 85, 247, 0.34)",
7
+ Orange = "rgba(249, 115, 22, 0.34)"
8
+ }
9
+ export default HighlightColors;
@@ -0,0 +1,10 @@
1
+ var HighlightColors;
2
+ (function (HighlightColors) {
3
+ HighlightColors["Yellow"] = "rgba(250, 204, 21, 0.38)";
4
+ HighlightColors["Green"] = "rgba(34, 197, 94, 0.34)";
5
+ HighlightColors["Blue"] = "rgba(59, 130, 246, 0.34)";
6
+ HighlightColors["Pink"] = "rgba(236, 72, 153, 0.32)";
7
+ HighlightColors["Purple"] = "rgba(168, 85, 247, 0.34)";
8
+ HighlightColors["Orange"] = "rgba(249, 115, 22, 0.34)";
9
+ })(HighlightColors || (HighlightColors = {}));
10
+ export default HighlightColors;
@@ -6,6 +6,7 @@ export declare enum SlashCommands {
6
6
  Heading4 = "Heading 4",
7
7
  BulletList = "Bullet List",
8
8
  NumberedList = "Numbered List",
9
+ CodeBlock = "Code Block",
9
10
  CurrentDate = "Current Date",
10
11
  CurrentTimestamp = "Current Timestamp",
11
12
  Image = "Image"
@@ -7,6 +7,7 @@ export var SlashCommands;
7
7
  SlashCommands["Heading4"] = "Heading 4";
8
8
  SlashCommands["BulletList"] = "Bullet List";
9
9
  SlashCommands["NumberedList"] = "Numbered List";
10
+ SlashCommands["CodeBlock"] = "Code Block";
10
11
  SlashCommands["CurrentDate"] = "Current Date";
11
12
  SlashCommands["CurrentTimestamp"] = "Current Timestamp";
12
13
  SlashCommands["Image"] = "Image";
@@ -11,12 +11,13 @@ import { Extension } from "@tiptap/core";
11
11
  import Suggestion from "@tiptap/suggestion";
12
12
  import { ReactRenderer } from "@tiptap/react";
13
13
  import tippy from "tippy.js";
14
- import { Heading1, Heading2, Heading3, Heading4, List, ListOrdered, Text, Image as ImageIcon, Calendar, ClockIcon, } from "lucide-react";
14
+ import { Heading1, Heading2, Heading3, Heading4, List, ListOrdered, Text, Image as ImageIcon, Calendar, ClockIcon, SquareCodeIcon, } from "lucide-react";
15
15
  import { startImageUpload, } from "../Plugins/UploadImagesPlugin.js";
16
16
  import { PluginKey } from "@tiptap/pm/state";
17
17
  import SlashCommandList from "./SlashCommandList";
18
18
  import { SlashCommands } from "../Enums";
19
19
  import moment from "moment/moment.js";
20
+ import { DEFAULT_CODE_BLOCK_LANGUAGE } from "../Utils/codeBlockUtils";
20
21
  const SlashCommandPluginKey = new PluginKey("slash-command");
21
22
  const getCommandItems = (values, options) => {
22
23
  var _a;
@@ -115,6 +116,20 @@ const getCommandItems = (values, options) => {
115
116
  editor.chain().focus().deleteRange(range).toggleOrderedList().run();
116
117
  },
117
118
  },
119
+ {
120
+ title: SlashCommands.CodeBlock,
121
+ description: "Create a syntax-highlighted code block.",
122
+ searchTerms: ["code", "pre", "snippet"],
123
+ icon: SquareCodeIcon,
124
+ command: ({ editor, range }) => {
125
+ editor
126
+ .chain()
127
+ .focus()
128
+ .deleteRange(range)
129
+ .setCodeBlock({ language: DEFAULT_CODE_BLOCK_LANGUAGE })
130
+ .run();
131
+ },
132
+ },
118
133
  {
119
134
  title: SlashCommands.CurrentDate,
120
135
  description: "Insert the current date.",
@@ -1,12 +1,20 @@
1
1
  import { Extension } from "@tiptap/core";
2
2
  import { HandleImageUpload } from "../Plugins";
3
3
  import { Extensions } from "../Enums";
4
- import { BubbleMenuOptions } from "./BubbleMenuExtension";
4
+ export type ExtensionPreset = "minimal" | "basic" | "full";
5
5
  export type ExtensionType = (typeof Extensions)[keyof typeof Extensions];
6
+ export declare const BASIC_EXTENSIONS: ExtensionType[];
7
+ export declare const MINIMAL_EXTENSIONS: ExtensionType[];
8
+ export declare const FULL_EXTENSIONS: ExtensionType[];
9
+ export declare const resolveExtensions: ({ disabledExtensions, extensionPreset, extensions, }: {
10
+ disabledExtensions?: ExtensionType[];
11
+ extensionPreset?: ExtensionPreset;
12
+ extensions?: ExtensionType[];
13
+ }) => ExtensionType[];
6
14
  interface GetTipTapExtensionsProps {
15
+ disabledExtensions?: ExtensionType[];
7
16
  extensions?: ExtensionType[];
8
17
  slashCommands?: any[];
9
- bubbleMenuOptions?: BubbleMenuOptions;
10
18
  handleImageUpload?: HandleImageUpload;
11
19
  }
12
20
  declare const getTipTapExtensions: (props: GetTipTapExtensionsProps) => Extension[];
@@ -1,22 +1,45 @@
1
1
  import TiptapImage from "@tiptap/extension-image";
2
2
  import StarterKit from "@tiptap/starter-kit";
3
+ import { CodeBlockLowlight } from "@tiptap/extension-code-block-lowlight";
3
4
  import HorizontalRule from "@tiptap/extension-horizontal-rule";
4
5
  import TextAlign from "@tiptap/extension-text-align";
5
- import { Table, TableCell, TableHeader, TableRow } from "@tiptap/extension-table";
6
+ import { Table, TableCell, TableHeader, TableRow, } from "@tiptap/extension-table";
6
7
  import { Focus, Placeholder } from "@tiptap/extensions";
7
8
  import { Color } from "@tiptap/extension-color";
9
+ import { Highlight } from "@tiptap/extension-highlight";
10
+ import { Link } from "@tiptap/extension-link";
8
11
  import { TextStyle } from "@tiptap/extension-text-style";
9
12
  import { InputRule, Extension } from "@tiptap/core";
13
+ import { ReactNodeViewRenderer } from "@tiptap/react";
14
+ import { common, createLowlight } from "lowlight";
10
15
  import { ImageActionsPlugin, UploadImagesPlugin, } from "../Plugins";
11
16
  import getSlashCommand from "./getSlashCommand";
12
17
  import { Extensions } from "../Enums";
13
- import BubbleMenu from "./BubbleMenuExtension";
18
+ import { LINK_REL, LINK_TARGET, normalizeLinkUrl } from "../Utils/linkUtils";
19
+ import CodeBlockNodeView from "../Components/CodeBlockNodeView";
20
+ import { DEFAULT_CODE_BLOCK_LANGUAGE } from "../Utils/codeBlockUtils";
21
+ const lowlight = createLowlight(common);
22
+ const CustomCodeBlockLowlight = CodeBlockLowlight.extend({
23
+ addAttributes() {
24
+ var _a;
25
+ return Object.assign(Object.assign({}, (_a = this.parent) === null || _a === void 0 ? void 0 : _a.call(this)), { wrap: {
26
+ default: false,
27
+ parseHTML: (element) => element.getAttribute("data-wrap") === "true",
28
+ renderHTML: (attributes) => attributes.wrap ? { "data-wrap": "true" } : {},
29
+ } });
30
+ },
31
+ addNodeView() {
32
+ return ReactNodeViewRenderer(CodeBlockNodeView);
33
+ },
34
+ });
14
35
  const CustomImage = TiptapImage.extend({
15
36
  // Add data-uuid attribute to image
16
37
  addAttributes() {
17
38
  var _a;
18
39
  return Object.assign(Object.assign({}, (_a = this.parent) === null || _a === void 0 ? void 0 : _a.call(this)), { "data-uuid": {
19
40
  default: null,
41
+ }, crossorigin: {
42
+ default: "anonymous",
20
43
  } });
21
44
  },
22
45
  addProseMirrorPlugins() {
@@ -40,27 +63,107 @@ const CustomStorage = Extension.create({
40
63
  };
41
64
  },
42
65
  });
43
- const getTipTapExtensions = ({ extensions = [], slashCommands = [], bubbleMenuOptions, handleImageUpload, }) => {
66
+ export const BASIC_EXTENSIONS = [
67
+ Extensions.Bold,
68
+ Extensions.Italic,
69
+ Extensions.Underline,
70
+ Extensions.Strike,
71
+ Extensions.Code,
72
+ Extensions.BulletList,
73
+ Extensions.OrderedList,
74
+ Extensions.TextStyle,
75
+ Extensions.Color,
76
+ Extensions.Highlight,
77
+ Extensions.Link,
78
+ Extensions.TextAlign,
79
+ Extensions.Focus,
80
+ Extensions.CustomStorage,
81
+ ];
82
+ export const MINIMAL_EXTENSIONS = [
83
+ Extensions.Focus,
84
+ Extensions.CustomStorage,
85
+ ];
86
+ export const FULL_EXTENSIONS = [
87
+ ...BASIC_EXTENSIONS,
88
+ Extensions.CodeBlock,
89
+ Extensions.HorizontalRule,
90
+ Extensions.Table,
91
+ Extensions.TableCell,
92
+ Extensions.TableHeader,
93
+ Extensions.TableRow,
94
+ Extensions.Placeholder,
95
+ Extensions.SlashCommand,
96
+ Extensions.BubbleMenu,
97
+ ];
98
+ const EXTENSION_PRESETS = {
99
+ minimal: MINIMAL_EXTENSIONS,
100
+ basic: BASIC_EXTENSIONS,
101
+ full: FULL_EXTENSIONS,
102
+ };
103
+ export const resolveExtensions = ({ disabledExtensions = [], extensionPreset = "basic", extensions = [], }) => {
104
+ const disabled = new Set(disabledExtensions);
105
+ const resolved = new Set([
106
+ ...(EXTENSION_PRESETS[extensionPreset] || BASIC_EXTENSIONS),
107
+ ...extensions,
108
+ ]);
109
+ if (resolved.has(Extensions.Color)) {
110
+ resolved.add(Extensions.TextStyle);
111
+ }
112
+ if (resolved.has(Extensions.Table)) {
113
+ resolved.add(Extensions.TableRow);
114
+ resolved.add(Extensions.TableCell);
115
+ resolved.add(Extensions.TableHeader);
116
+ }
117
+ disabled.forEach((extension) => resolved.delete(extension));
118
+ return Array.from(resolved);
119
+ };
120
+ const getTipTapExtensions = ({ disabledExtensions = [], extensions = [], slashCommands = [], handleImageUpload, }) => {
121
+ const disabled = new Set(disabledExtensions);
122
+ const enabled = new Set(extensions);
123
+ const isEnabled = (extension) => enabled.has(extension) && !disabled.has(extension);
44
124
  return [
45
125
  {
46
126
  name: "starterKit",
47
- category: "default",
48
127
  extension: StarterKit.configure({
49
- bulletList: {
50
- HTMLAttributes: {
51
- class: "",
52
- },
53
- },
54
- orderedList: {
55
- HTMLAttributes: {
56
- class: "",
57
- },
58
- },
59
- listItem: {
60
- HTMLAttributes: {
61
- class: "",
62
- },
63
- },
128
+ bold: isEnabled(Extensions.Bold) ? {} : false,
129
+ italic: isEnabled(Extensions.Italic) ? {} : false,
130
+ underline: isEnabled(Extensions.Underline) ? {} : false,
131
+ strike: isEnabled(Extensions.Strike) ? {} : false,
132
+ bulletList: isEnabled(Extensions.BulletList)
133
+ ? {
134
+ HTMLAttributes: {
135
+ class: "",
136
+ },
137
+ }
138
+ : false,
139
+ orderedList: isEnabled(Extensions.OrderedList)
140
+ ? {
141
+ HTMLAttributes: {
142
+ class: "",
143
+ },
144
+ }
145
+ : false,
146
+ listItem: isEnabled(Extensions.BulletList) ||
147
+ isEnabled(Extensions.OrderedList)
148
+ ? {
149
+ HTMLAttributes: {
150
+ class: "",
151
+ },
152
+ }
153
+ : false,
154
+ listKeymap: isEnabled(Extensions.BulletList) ||
155
+ isEnabled(Extensions.OrderedList)
156
+ ? {}
157
+ : false,
158
+ link: false,
159
+ code: isEnabled(Extensions.Code)
160
+ ? {
161
+ HTMLAttributes: {
162
+ class: "editor-inline-code",
163
+ },
164
+ }
165
+ : false,
166
+ codeBlock: false,
64
167
  horizontalRule: false,
65
168
  dropcursor: {
66
169
  color: "#DBEAFE",
@@ -69,24 +172,53 @@ const getTipTapExtensions = ({ extensions = [], slashCommands = [], bubbleMenuOp
69
172
  gapcursor: false,
70
173
  }),
71
174
  },
175
+ {
176
+ name: Extensions.CodeBlock,
177
+ extension: CustomCodeBlockLowlight.configure({
178
+ lowlight,
179
+ defaultLanguage: DEFAULT_CODE_BLOCK_LANGUAGE,
180
+ enableTabIndentation: true,
181
+ HTMLAttributes: {
182
+ class: "editor-code-block",
183
+ },
184
+ }),
185
+ },
72
186
  {
73
187
  name: Extensions.TextStyle,
74
- category: "default",
75
188
  extension: TextStyle,
76
189
  },
77
190
  {
78
191
  name: Extensions.Color,
79
- category: "default",
80
192
  extension: Color,
81
193
  },
194
+ {
195
+ name: Extensions.Highlight,
196
+ extension: Highlight.configure({ multicolor: true }),
197
+ },
198
+ {
199
+ name: Extensions.Link,
200
+ extension: Link.configure({
201
+ autolink: true,
202
+ linkOnPaste: true,
203
+ openOnClick: false,
204
+ enableClickSelection: false,
205
+ defaultProtocol: "https",
206
+ protocols: ["http", "https"],
207
+ isAllowedUri: (url) => normalizeLinkUrl(url).isValid,
208
+ shouldAutoLink: (url) => normalizeLinkUrl(url).isValid,
209
+ HTMLAttributes: {
210
+ class: "editor-link",
211
+ target: LINK_TARGET,
212
+ rel: LINK_REL,
213
+ },
214
+ }),
215
+ },
82
216
  {
83
217
  name: Extensions.TextAlign,
84
- category: "default",
85
218
  extension: TextAlign.configure({ types: ["heading", "paragraph"] }),
86
219
  },
87
220
  {
88
221
  name: Extensions.Focus,
89
- category: "default",
90
222
  extension: Focus.configure({ className: "has-focus", mode: "all" }),
91
223
  },
92
224
  // patch to fix horizontal rule bug: https://github.com/ueberdosis/tiptap/pull/3859#issuecomment-1536799740
@@ -157,14 +289,8 @@ const getTipTapExtensions = ({ extensions = [], slashCommands = [], bubbleMenuOp
157
289
  },
158
290
  {
159
291
  name: Extensions.CustomStorage,
160
- category: "default",
161
292
  extension: CustomStorage,
162
293
  },
163
- {
164
- name: Extensions.BubbleMenu,
165
- category: "default",
166
- extension: BubbleMenu.configure(bubbleMenuOptions),
167
- },
168
294
  {
169
295
  name: Extensions.SlashCommand,
170
296
  extension: getSlashCommand({
@@ -174,8 +300,9 @@ const getTipTapExtensions = ({ extensions = [], slashCommands = [], bubbleMenuOp
174
300
  },
175
301
  ]
176
302
  .filter((ext) => {
177
- return (extensions.includes(ext.name) ||
178
- ext.category === "default");
303
+ if (ext.name === "starterKit")
304
+ return true;
305
+ return isEnabled(ext.name);
179
306
  })
180
307
  .map((ext) => ext.extension);
181
308
  };