@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
@@ -60,123 +60,20 @@ const getImageFilename = (image) => {
60
60
  return "image.png";
61
61
  };
62
62
  const getImageBlob = (src) => __awaiter(void 0, void 0, void 0, function* () {
63
- const response = yield fetch(src, {
64
- mode: "cors",
65
- credentials: "omit",
66
- });
63
+ const response = yield fetch(src);
67
64
  if (!response.ok) {
68
65
  throw new Error("Unable to load image.");
69
66
  }
70
- return {
71
- blob: yield response.blob(),
72
- contentType: response.headers.get("content-type") || "",
73
- };
74
- });
75
- const clipboardPngType = "image/png";
76
- const imageMimeTypesByExtension = {
77
- gif: "image/gif",
78
- jpg: "image/jpeg",
79
- jpeg: "image/jpeg",
80
- png: clipboardPngType,
81
- svg: "image/svg+xml",
82
- webp: "image/webp",
83
- };
84
- const normalizeMimeType = (type) => type.toLowerCase().split(";")[0].trim();
85
- const getImageMimeTypeFromSource = (src) => {
86
- var _a;
87
- try {
88
- const url = new URL(src);
89
- const filename = url.pathname.split("/").filter(Boolean).pop();
90
- const extension = (_a = filename === null || filename === void 0 ? void 0 : filename.split(".").pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase();
91
- return extension ? imageMimeTypesByExtension[extension] || "" : "";
92
- }
93
- catch (_b) {
94
- const dataUrlMatch = src.match(/^data:([^;,]+)/);
95
- return (dataUrlMatch === null || dataUrlMatch === void 0 ? void 0 : dataUrlMatch[1]) || "";
96
- }
97
- };
98
- const canWriteClipboardType = (ClipboardItemCtor, type) => {
99
- if (!type)
100
- return false;
101
- if (typeof ClipboardItemCtor.supports === "function") {
102
- return ClipboardItemCtor.supports(type);
103
- }
104
- return type === clipboardPngType;
105
- };
106
- const loadImageSource = (src) => new Promise((resolve, reject) => {
107
- const image = new Image();
108
- image.crossOrigin = "anonymous";
109
- image.onload = () => resolve(image);
110
- image.onerror = () => {
111
- reject(new Error("Unable to prepare image for clipboard."));
112
- };
113
- image.src = src;
114
- });
115
- const renderImageSourceToPngBlob = (src) => __awaiter(void 0, void 0, void 0, function* () {
116
- const image = yield loadImageSource(src);
117
- const width = image.naturalWidth || image.width;
118
- const height = image.naturalHeight || image.height;
119
- if (!width || !height) {
120
- throw new Error("Unable to prepare image for clipboard.");
121
- }
122
- const canvas = document.createElement("canvas");
123
- canvas.width = width;
124
- canvas.height = height;
125
- const context = canvas.getContext("2d");
126
- if (!context) {
127
- throw new Error("Unable to prepare image for clipboard.");
128
- }
129
- context.drawImage(image, 0, 0, width, height);
130
- return new Promise((resolve, reject) => {
131
- canvas.toBlob((blob) => {
132
- if (blob) {
133
- resolve(blob);
134
- }
135
- else {
136
- reject(new Error("Unable to prepare image for clipboard."));
137
- }
138
- }, clipboardPngType);
139
- });
140
- });
141
- const convertBlobToClipboardPng = (blob, fallbackSrc) => __awaiter(void 0, void 0, void 0, function* () {
142
- const objectUrl = URL.createObjectURL(blob);
143
- try {
144
- return yield renderImageSourceToPngBlob(objectUrl);
145
- }
146
- catch (error) {
147
- if (!fallbackSrc || fallbackSrc === objectUrl)
148
- throw error;
149
- return renderImageSourceToPngBlob(fallbackSrc);
150
- }
151
- finally {
152
- URL.revokeObjectURL(objectUrl);
153
- }
154
- });
155
- const getClipboardImageBlob = (image, ClipboardItemCtor) => __awaiter(void 0, void 0, void 0, function* () {
156
- const src = image.currentSrc || image.src;
157
- const { blob, contentType } = yield getImageBlob(src);
158
- const type = normalizeMimeType(blob.type) ||
159
- normalizeMimeType(contentType) ||
160
- getImageMimeTypeFromSource(src);
161
- if (canWriteClipboardType(ClipboardItemCtor, type)) {
162
- return {
163
- blob: blob.type === type ? blob : new Blob([blob], { type }),
164
- type,
165
- };
166
- }
167
- return {
168
- blob: yield convertBlobToClipboardPng(blob, src),
169
- type: clipboardPngType,
170
- };
67
+ return response.blob();
171
68
  });
172
69
  const copyImage = (image) => __awaiter(void 0, void 0, void 0, function* () {
173
70
  var _a;
174
- const ClipboardItemCtor = window
175
- .ClipboardItem;
71
+ const ClipboardItemCtor = window.ClipboardItem;
176
72
  if (!((_a = navigator.clipboard) === null || _a === void 0 ? void 0 : _a.write) || !ClipboardItemCtor) {
177
73
  throw new Error("Image copying is not supported by this browser.");
178
74
  }
179
- const { blob, type } = yield getClipboardImageBlob(image, ClipboardItemCtor);
75
+ const blob = yield getImageBlob(image.src);
76
+ const type = blob.type || "image/png";
180
77
  yield navigator.clipboard.write([
181
78
  new ClipboardItemCtor({
182
79
  [type]: blob,
@@ -188,7 +85,7 @@ const downloadImage = (image) => __awaiter(void 0, void 0, void 0, function* ()
188
85
  let href = image.src;
189
86
  let objectUrl = null;
190
87
  try {
191
- const { blob } = yield getImageBlob(image.src);
88
+ const blob = yield getImageBlob(image.src);
192
89
  objectUrl = URL.createObjectURL(blob);
193
90
  href = objectUrl;
194
91
  }
@@ -113,6 +113,7 @@ export const startImageUpload = (file, view, pos, handleImageUpload) => {
113
113
  src: imageSrc,
114
114
  alt: `${id}.png`,
115
115
  "data-uuid": id,
116
+ crossorigin: "anonymous",
116
117
  title: `Filename: ${id}.png`,
117
118
  });
118
119
  const insertTransaction = view.state.tr
@@ -1,12 +1,15 @@
1
+ import "highlight.js/styles/github-dark.css";
1
2
  import { Editor } from "@tiptap/react";
2
- import { ExtensionType } from "./Extensions/getTiptapExtensions";
3
+ import { ExtensionPreset, ExtensionType } from "./Extensions/getTiptapExtensions";
3
4
  import { HandleImageUrlUpload, HandleImageUpload } from "./Plugins/UploadImagesPlugin";
4
- import { BubbleMenuOptions } from "./Extensions/BubbleMenuExtension";
5
+ import { BubbleMenuOptions } from "./Components/BubbleMenu";
5
6
  import { ToolbarOptions } from "./Toolbar/Toolbar";
6
7
  type RichTextEditorProps = {
7
8
  className?: string;
8
9
  editorInstanceRef?: React.RefObject<Editor | null>;
9
10
  extensions?: ExtensionType[];
11
+ disabledExtensions?: ExtensionType[];
12
+ extensionPreset?: ExtensionPreset;
10
13
  slashCommands?: any[];
11
14
  defaultValue?: string;
12
15
  value?: string;
@@ -8,17 +8,23 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
- import { useEffect, useRef, useState } from "react";
11
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
12
12
  import styled from "styled-components";
13
+ import "highlight.js/styles/github-dark.css";
13
14
  import { EditorContent, useEditor } from "@tiptap/react";
15
+ import { BubbleMenu as TiptapBubbleMenu, } from "@tiptap/react/menus";
16
+ import { isTextSelection } from "@tiptap/core";
14
17
  import { DOMParser as ProseMirrorDOMParser } from "@tiptap/pm/model";
18
+ import { TextSelection } from "@tiptap/pm/state";
15
19
  import { Toolbar } from "./Toolbar";
16
- import getTipTapExtensions from "./Extensions/getTiptapExtensions";
17
- import { Extensions, SlashCommands } from "./Enums";
20
+ import getTipTapExtensions, { resolveExtensions, } from "./Extensions/getTiptapExtensions";
21
+ import { Controls, Extensions, SlashCommands } from "./Enums";
18
22
  import { addImagePlaceholder, removeImagePlaceholder, startImageUpload, } from "./Plugins/UploadImagesPlugin";
19
23
  import SaveBadge from "./Components/SaveBadge";
24
+ import BubbleMenuContent from "./Components/BubbleMenu";
20
25
  import Fonts from "./Enums/Fonts";
21
26
  import RichTextEditorContext from "./Contexts/RichTextEditorContext";
27
+ import { getLinkAttributesAtPosition, getLinkRangeAtPosition, openLink, } from "./Utils/linkUtils";
22
28
  const getImageFilesFromClipboard = (clipboardData) => {
23
29
  return Array.from(clipboardData.files).filter((file) => file.type.includes("image/"));
24
30
  };
@@ -317,6 +323,78 @@ const StyledContent = styled.div `
317
323
  margin: 0;
318
324
  line-height: 1.5rem;
319
325
  }
326
+ .editor-inline-code,
327
+ :not(pre) > code {
328
+ padding: 0.1rem 0.25rem;
329
+ border: 1px solid ${({ theme }) => theme.palette.divider};
330
+ border-radius: 4px;
331
+ background-color: ${({ theme }) => theme.palette.action.hover};
332
+ color: ${({ theme }) => theme.palette.text.secondary};
333
+ font-family:
334
+ ui-monospace, SFMono-Regular, SFMono-Regular, Menlo, Monaco, Consolas,
335
+ "Liberation Mono", "Courier New", monospace;
336
+ font-size: 0.9em;
337
+ box-decoration-break: clone;
338
+ }
339
+ .editor-code-block {
340
+ position: relative;
341
+ margin: 0.5rem 0;
342
+ padding: 0.875rem 1rem;
343
+ overflow-x: auto;
344
+ border: 1px solid #30363d;
345
+ border-radius: 6px;
346
+ background-color: #0d1117;
347
+ color: #c9d1d9;
348
+ font-family:
349
+ ui-monospace, SFMono-Regular, SFMono-Regular, Menlo, Monaco, Consolas,
350
+ "Liberation Mono", "Courier New", monospace;
351
+ font-size: 0.85rem;
352
+ line-height: 1.45rem;
353
+ white-space: pre;
354
+
355
+ &[data-wrap="true"] {
356
+ white-space: pre-wrap;
357
+ word-break: break-word;
358
+ overflow-wrap: anywhere;
359
+ }
360
+
361
+ code {
362
+ display: block;
363
+ min-width: max-content;
364
+ padding: 0;
365
+ border: 0;
366
+ background-color: transparent;
367
+ color: inherit;
368
+ font: inherit;
369
+ }
370
+
371
+ &[data-wrap="true"] code {
372
+ min-width: 0;
373
+ white-space: inherit;
374
+ }
375
+
376
+ .editor-code-block-actions {
377
+ display: flex;
378
+ position: absolute;
379
+ top: 0.4rem;
380
+ right: 0.4rem;
381
+ z-index: 1;
382
+ gap: 0.25rem;
383
+ opacity: 0;
384
+ transition: opacity 120ms ease-in-out;
385
+ }
386
+
387
+ .editor-code-block-action {
388
+ background-color: #161b22;
389
+ color: #c9d1d9;
390
+ border-color: #30363d;
391
+ }
392
+
393
+ &:hover .editor-code-block-actions,
394
+ &:focus-within .editor-code-block-actions {
395
+ opacity: 1;
396
+ }
397
+ }
320
398
  ul {
321
399
  margin: 0;
322
400
  }
@@ -330,8 +408,6 @@ const StyledContent = styled.div `
330
408
  color: ${({ theme }) => theme.palette.text.primary};
331
409
  text-decoration: underline;
332
410
  cursor: pointer;
333
- // Set title attribute
334
- title: "Click to open link";
335
411
  }
336
412
  img {
337
413
  max-width: 100%;
@@ -543,16 +619,96 @@ const StyledContent = styled.div `
543
619
  margin: 0 0.125rem;
544
620
  }
545
621
  `;
546
- export const RichTextEditor = ({ className, editorInstanceRef, defaultValue = "", value, readOnly = false, font, showToolbar = true, saving = false, extensions = [], slashCommands = [], bubbleMenuOptions, toolbarOptions, autoFocus, onChange, handleImageUpload, handleImageUrlUpload, style, }) => {
622
+ export const RichTextEditor = ({ className, editorInstanceRef, defaultValue = "", value, readOnly = false, font, showToolbar = true, saving = false, disabledExtensions = [], extensionPreset = "basic", extensions = [], slashCommands = [], bubbleMenuOptions, toolbarOptions, autoFocus, onChange, handleImageUpload, handleImageUrlUpload, style, }) => {
623
+ const resolvedExtensions = useMemo(() => resolveExtensions({
624
+ disabledExtensions,
625
+ extensionPreset,
626
+ extensions,
627
+ }), [disabledExtensions, extensionPreset, extensions]);
628
+ const resolvedExtensionSet = useMemo(() => new Set(resolvedExtensions), [resolvedExtensions]);
629
+ const resolvedSlashCommands = useMemo(() => slashCommands.filter((command) => {
630
+ if (command === SlashCommands.CodeBlock) {
631
+ return resolvedExtensionSet.has(Extensions.CodeBlock);
632
+ }
633
+ return true;
634
+ }), [resolvedExtensionSet, slashCommands]);
635
+ const resolvedToolbarOptions = useMemo(() => {
636
+ if (!(toolbarOptions === null || toolbarOptions === void 0 ? void 0 : toolbarOptions.controls))
637
+ return toolbarOptions;
638
+ const controlExtensionMap = {
639
+ [Controls.BOLD]: Extensions.Bold,
640
+ [Controls.ITALIC]: Extensions.Italic,
641
+ [Controls.UNDERLINE]: Extensions.Underline,
642
+ [Controls.STRIKE]: Extensions.Strike,
643
+ [Controls.CODE]: Extensions.Code,
644
+ [Controls.CODE_BLOCK]: Extensions.CodeBlock,
645
+ [Controls.BULLET_LIST]: Extensions.BulletList,
646
+ [Controls.ORDERED_LIST]: Extensions.OrderedList,
647
+ [Controls.COLOR]: Extensions.Color,
648
+ [Controls.HIGHLIGHT]: Extensions.Highlight,
649
+ [Controls.LINK]: Extensions.Link,
650
+ [Controls.TEXT_ALIGN_LEFT]: Extensions.TextAlign,
651
+ [Controls.TEXT_ALIGN_CENTER]: Extensions.TextAlign,
652
+ [Controls.TEXT_ALIGN_RIGHT]: Extensions.TextAlign,
653
+ [Controls.TEXT_ALIGN_JUSTIFIED]: Extensions.TextAlign,
654
+ };
655
+ return Object.assign(Object.assign({}, toolbarOptions), { controls: toolbarOptions.controls.filter((control) => {
656
+ if (typeof control !== "string")
657
+ return true;
658
+ const extension = controlExtensionMap[control];
659
+ return !extension || resolvedExtensionSet.has(extension);
660
+ }) });
661
+ }, [resolvedExtensionSet, toolbarOptions]);
547
662
  const isControlled = value !== undefined;
548
- const hasImageExtension = extensions.includes(Extensions.Image);
549
- const hasSlashCommandExtension = extensions.includes(Extensions.SlashCommand);
550
- const hasImageSlashCommand = hasSlashCommandExtension && slashCommands.includes(SlashCommands.Image);
663
+ const hasImageExtension = resolvedExtensionSet.has(Extensions.Image);
664
+ const hasSlashCommandExtension = resolvedExtensionSet.has(Extensions.SlashCommand);
665
+ const hasBubbleMenuExtension = resolvedExtensionSet.has(Extensions.BubbleMenu);
666
+ const hasImageSlashCommand = hasSlashCommandExtension &&
667
+ resolvedSlashCommands.includes(SlashCommands.Image);
551
668
  const onChangeRef = useRef(onChange);
669
+ const bubbleMenuPortalRef = useRef(null);
552
670
  const [fontState, setFontState] = useState(font || Fonts.DEFAULT);
553
671
  useEffect(() => {
554
672
  onChangeRef.current = onChange;
555
673
  }, [onChange]);
674
+ const getBubbleMenuPortalRoot = useCallback(() => {
675
+ if (bubbleMenuPortalRef.current) {
676
+ return bubbleMenuPortalRef.current;
677
+ }
678
+ const portal = document.createElement("div");
679
+ portal.setAttribute("data-monolith-bubble-menu-portal", "");
680
+ document.body.appendChild(portal);
681
+ bubbleMenuPortalRef.current = portal;
682
+ return portal;
683
+ }, []);
684
+ useEffect(() => {
685
+ return () => {
686
+ var _a;
687
+ (_a = bubbleMenuPortalRef.current) === null || _a === void 0 ? void 0 : _a.remove();
688
+ bubbleMenuPortalRef.current = null;
689
+ };
690
+ }, []);
691
+ const shouldShowBubbleMenu = useCallback(({ editor, element, view, state, from, to }) => {
692
+ const { selection } = state;
693
+ const isChildOfMenu = element.contains(document.activeElement);
694
+ const hasEditorFocus = view.hasFocus() || isChildOfMenu;
695
+ const selectedText = state.doc.textBetween(from, to).trim();
696
+ const isEmptyTextBlock = !selectedText && isTextSelection(state.selection);
697
+ if (!hasEditorFocus ||
698
+ selection.empty ||
699
+ isEmptyTextBlock ||
700
+ !editor.isEditable) {
701
+ return false;
702
+ }
703
+ return true;
704
+ }, []);
705
+ const bubbleMenuPositionOptions = useMemo(() => ({
706
+ strategy: "fixed",
707
+ placement: "top",
708
+ offset: 8,
709
+ flip: false,
710
+ shift: { padding: 10 },
711
+ }), []);
556
712
  if (hasImageSlashCommand && !hasImageExtension) {
557
713
  throw new Error("Extensions.Image is required when using the Image slash command.");
558
714
  }
@@ -566,12 +722,29 @@ export const RichTextEditor = ({ className, editorInstanceRef, defaultValue = ""
566
722
  editable: !readOnly,
567
723
  shouldRerenderOnTransaction: true,
568
724
  extensions: getTipTapExtensions({
569
- extensions,
570
- slashCommands,
571
- bubbleMenuOptions,
725
+ disabledExtensions,
726
+ extensions: resolvedExtensions,
727
+ slashCommands: resolvedSlashCommands,
572
728
  handleImageUpload,
573
729
  }),
574
730
  editorProps: {
731
+ handleClick: (view, pos, event) => {
732
+ const linkRange = getLinkRangeAtPosition(view.state, pos);
733
+ const linkAttributes = getLinkAttributesAtPosition(view.state, pos);
734
+ if (!linkRange || !(linkAttributes === null || linkAttributes === void 0 ? void 0 : linkAttributes.href))
735
+ return false;
736
+ const mouseEvent = event;
737
+ mouseEvent.preventDefault();
738
+ mouseEvent.stopPropagation();
739
+ const shouldOpenLink = mouseEvent.metaKey || mouseEvent.ctrlKey || !view.editable;
740
+ if (shouldOpenLink) {
741
+ openLink(linkAttributes.href);
742
+ return true;
743
+ }
744
+ view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, linkRange.from, linkRange.to)));
745
+ view.focus();
746
+ return true;
747
+ },
575
748
  handlePaste: (view, event) => {
576
749
  if (!hasImageExtension || !handleImageUpload)
577
750
  return false;
@@ -632,5 +805,5 @@ export const RichTextEditor = ({ className, editorInstanceRef, defaultValue = ""
632
805
  return (_jsx(StyledContent, { className: className, children: _jsxs(RichTextEditorContext.Provider, { value: {
633
806
  font: fontState,
634
807
  setFont: setFontState,
635
- }, children: [showToolbar && (_jsx(Toolbar, { editor: editor, toolbarOptions: toolbarOptions })), saving && _jsx(SaveBadge, {}), _jsx(EditorContent, { className: "editor-content", editor: editor, "data-font": fontState || null, style: style })] }) }));
808
+ }, children: [showToolbar && (_jsx(Toolbar, { editor: editor, toolbarOptions: resolvedToolbarOptions })), saving && _jsx(SaveBadge, {}), editor && hasBubbleMenuExtension && (_jsx(TiptapBubbleMenu, { editor: editor, pluginKey: "bubbleMenu", updateDelay: 200, appendTo: getBubbleMenuPortalRoot, shouldShow: shouldShowBubbleMenu, options: bubbleMenuPositionOptions, children: _jsx(BubbleMenuContent, { editor: editor, customMenuItems: bubbleMenuOptions === null || bubbleMenuOptions === void 0 ? void 0 : bubbleMenuOptions.customMenuItems }) })), _jsx(EditorContent, { className: "editor-content", editor: editor, "data-font": fontState || null, style: style })] }) }));
636
809
  };
@@ -1,13 +1,17 @@
1
1
  import { Editor } from "@tiptap/react";
2
+ import { ButtonProps } from "../../Button";
2
3
  export type ControlProps = {
3
4
  className?: string;
4
5
  editor: Editor | null;
5
6
  isActive?: any;
6
- operation: {
7
+ operation?: {
7
8
  name: string;
8
9
  attributes?: any;
9
10
  };
11
+ onClick?: (editor: Editor | null) => void;
12
+ disabled?: boolean;
10
13
  label: string;
11
14
  icon: any;
15
+ size?: ButtonProps["size"];
12
16
  };
13
- export declare const Control: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<ControlProps, never>> & string & Omit<({ className, editor, isActive, operation, label, icon: Icon, }: ControlProps) => import("react/jsx-runtime").JSX.Element, keyof import("react").Component<any, {}, any>>;
17
+ export declare const Control: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<ControlProps, never>> & string & Omit<({ className, editor, isActive, operation, onClick, disabled, label, icon: Icon, size, }: ControlProps) => import("react/jsx-runtime").JSX.Element, keyof import("react").Component<any, {}, any>>;
@@ -1,23 +1,30 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import styled from "styled-components";
3
3
  import Labels from "./Labels";
4
- export const Control = styled(({ className, editor, isActive, operation, label, icon: Icon, }) => {
4
+ import { Button } from "../../Button";
5
+ export const Control = styled(({ className, editor, isActive, operation, onClick, disabled, label, icon: Icon, size = "xs", }) => {
5
6
  var _a;
6
7
  const _label = Labels[label];
7
8
  const active = (isActive === null || isActive === void 0 ? void 0 : isActive.name)
8
9
  ? (_a = editor === null || editor === void 0 ? void 0 : editor.isActive) === null || _a === void 0 ? void 0 : _a.call(editor, isActive.name, isActive.attributes)
9
10
  : false;
10
- return (_jsx("button", { className: className + (active ? " active" : ""), "aria-label": _label, "data-active": active, title: _label, onClick: () => {
11
+ return (_jsx(Button, { className: className + (active ? " active" : ""), "aria-label": _label, "data-active": active, title: _label, disabled: disabled, onClick: () => {
12
+ if (onClick) {
13
+ onClick(editor);
14
+ return;
15
+ }
16
+ if (!operation)
17
+ return;
11
18
  const focus = editor === null || editor === void 0 ? void 0 : editor.chain().focus();
12
19
  focus[operation.name](operation.attributes).run();
13
- }, children: _jsx(Icon, { size: "16px" }) }));
20
+ }, size: size, children: _jsx(Icon, { size: "16px" }) }));
14
21
  }) `
15
22
  display: flex;
16
23
  justify-content: center;
17
24
  align-items: center;
18
- width: 1.5rem;
19
- height: 1.5rem;
20
- padding: 0px;
25
+
26
+ padding: 5px;
27
+
21
28
  background-color: transparent;
22
29
  cursor: pointer;
23
30
  color: ${({ theme }) => theme.palette.text.primary};
@@ -8,6 +8,8 @@ export declare const BoldControl: ({ editor }: ControlProps) => import("react/js
8
8
  export declare const ItalicControl: ({ editor }: ControlProps) => import("react/jsx-runtime").JSX.Element;
9
9
  export declare const UnderlineControl: ({ editor }: ControlProps) => import("react/jsx-runtime").JSX.Element;
10
10
  export declare const StrikeThroughControl: ({ editor }: ControlProps) => import("react/jsx-runtime").JSX.Element;
11
+ export declare const CodeControl: ({ editor }: ControlProps) => import("react/jsx-runtime").JSX.Element;
12
+ export declare const CodeBlockControl: ({ editor }: ControlProps) => import("react/jsx-runtime").JSX.Element;
11
13
  export declare const Heading1Control: ({ editor }: ControlProps) => import("react/jsx-runtime").JSX.Element;
12
14
  export declare const Heading2Control: ({ editor }: ControlProps) => import("react/jsx-runtime").JSX.Element;
13
15
  export declare const Heading3Control: ({ editor }: ControlProps) => import("react/jsx-runtime").JSX.Element;
@@ -1,6 +1,10 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { IconBold, IconItalic, IconUnderline, IconStrikethrough, IconH1, IconH2, IconH3, IconH4, IconList, IconListNumbers, IconAlignLeft, IconAlignRight, IconAlignCenter, IconAlignJustified, IconCornerUpLeft, IconCornerUpRight, } from "@tabler/icons-react";
3
+ import { CodeIcon } from "lucide-react";
4
+ import { SquareCodeIcon } from "lucide-react";
3
5
  import { Control } from "./Control";
6
+ import { hasInlineCode, toggleInlineCode } from "../Utils/codeUtils";
7
+ import { hasSyntaxHighlightedCodeBlock, toggleCodeBlock, } from "../Utils/codeBlockUtils";
4
8
  export const UndoControl = ({ editor }) => {
5
9
  return (_jsx(Control, { editor: editor, label: "undoControlLabel", operation: {
6
10
  name: "undo",
@@ -39,6 +43,16 @@ export const StrikeThroughControl = ({ editor }) => {
39
43
  name: "toggleStrike",
40
44
  }, icon: IconStrikethrough }));
41
45
  };
46
+ export const CodeControl = ({ editor }) => {
47
+ return (_jsx(Control, { editor: editor, label: "codeControlLabel", isActive: {
48
+ name: "code",
49
+ }, onClick: toggleInlineCode, disabled: !hasInlineCode(editor), icon: CodeIcon }));
50
+ };
51
+ export const CodeBlockControl = ({ editor }) => {
52
+ return (_jsx(Control, { editor: editor, label: "codeBlockControlLabel", isActive: {
53
+ name: "codeBlock",
54
+ }, onClick: toggleCodeBlock, disabled: !hasSyntaxHighlightedCodeBlock(editor), icon: SquareCodeIcon }));
55
+ };
42
56
  export const Heading1Control = ({ editor }) => {
43
57
  return (_jsx(Control, { editor: editor, label: "h1ControlLabel", isActive: {
44
58
  name: "heading",
@@ -9,6 +9,7 @@ const ControlsGroup = styled(forwardRef(({ className, children }, ref) => {
9
9
  })) `
10
10
  & {
11
11
  display: flex;
12
+ flex: 0 0 auto;
12
13
  justify-content: flex-start;
13
14
  align-items: center;
14
15
  }