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

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 (51) hide show
  1. package/dist/DropDownMenu/components/MenuItemList.js +32 -12
  2. package/dist/DropDownMenu/components/StyledInnerItemContainer.js +1 -0
  3. package/dist/MonolithUIProvider/MonolithUIProvider.d.ts +23 -0
  4. package/dist/RichTextEditor/Components/BubbleMenu.d.ts +8 -8
  5. package/dist/RichTextEditor/Components/BubbleMenu.js +195 -93
  6. package/dist/RichTextEditor/Components/CodeBlockBaseButton.d.ts +18 -0
  7. package/dist/RichTextEditor/Components/CodeBlockBaseButton.js +6 -0
  8. package/dist/RichTextEditor/Components/CodeBlockCopyButton.d.ts +9 -0
  9. package/dist/RichTextEditor/Components/CodeBlockCopyButton.js +42 -0
  10. package/dist/RichTextEditor/Components/CodeBlockFormatButton.d.ts +10 -0
  11. package/dist/RichTextEditor/Components/CodeBlockFormatButton.js +60 -0
  12. package/dist/RichTextEditor/Components/CodeBlockLanguageSelect.d.ts +9 -0
  13. package/dist/RichTextEditor/Components/CodeBlockLanguageSelect.js +30 -0
  14. package/dist/RichTextEditor/Components/CodeBlockNodeView.d.ts +3 -0
  15. package/dist/RichTextEditor/Components/CodeBlockNodeView.js +28 -0
  16. package/dist/RichTextEditor/Components/CodeBlockWrapButton.d.ts +10 -0
  17. package/dist/RichTextEditor/Components/CodeBlockWrapButton.js +17 -0
  18. package/dist/RichTextEditor/Components/LinkEditor.d.ts +8 -0
  19. package/dist/RichTextEditor/Components/LinkEditor.js +94 -0
  20. package/dist/RichTextEditor/Enums/Controls.d.ts +5 -1
  21. package/dist/RichTextEditor/Enums/Controls.js +4 -0
  22. package/dist/RichTextEditor/Enums/Extensions.d.ts +4 -0
  23. package/dist/RichTextEditor/Enums/Extensions.js +4 -0
  24. package/dist/RichTextEditor/Enums/HighlightColors.d.ts +9 -0
  25. package/dist/RichTextEditor/Enums/HighlightColors.js +10 -0
  26. package/dist/RichTextEditor/Enums/SlashCommands.d.ts +2 -0
  27. package/dist/RichTextEditor/Enums/SlashCommands.js +2 -0
  28. package/dist/RichTextEditor/Extensions/SlashCommandList.js +0 -1
  29. package/dist/RichTextEditor/Extensions/getSlashCommand.js +25 -1
  30. package/dist/RichTextEditor/Extensions/getTiptapExtensions.d.ts +10 -2
  31. package/dist/RichTextEditor/Extensions/getTiptapExtensions.js +158 -31
  32. package/dist/RichTextEditor/Plugins/ImageActionsPlugin.js +6 -109
  33. package/dist/RichTextEditor/Plugins/UploadImagesPlugin.js +1 -0
  34. package/dist/RichTextEditor/RichTextEditor.d.ts +4 -2
  35. package/dist/RichTextEditor/RichTextEditor.js +323 -13
  36. package/dist/RichTextEditor/Toolbar/Control.d.ts +6 -2
  37. package/dist/RichTextEditor/Toolbar/Control.js +13 -6
  38. package/dist/RichTextEditor/Toolbar/Controls.d.ts +2 -0
  39. package/dist/RichTextEditor/Toolbar/Controls.js +14 -0
  40. package/dist/RichTextEditor/Toolbar/ControlsGroup.js +1 -0
  41. package/dist/RichTextEditor/Toolbar/Toolbar.js +61 -9
  42. package/dist/RichTextEditor/Utils/codeBlockUtils.d.ts +20 -0
  43. package/dist/RichTextEditor/Utils/codeBlockUtils.js +137 -0
  44. package/dist/RichTextEditor/Utils/codeUtils.d.ts +3 -0
  45. package/dist/RichTextEditor/Utils/codeUtils.js +12 -0
  46. package/dist/RichTextEditor/Utils/linkUtils.d.ts +19 -0
  47. package/dist/RichTextEditor/Utils/linkUtils.js +57 -0
  48. package/dist/theme/variants.js +46 -0
  49. package/package.json +8 -1
  50. package/dist/RichTextEditor/Extensions/BubbleMenuExtension.d.ts +0 -7
  51. package/dist/RichTextEditor/Extensions/BubbleMenuExtension.js +0 -157
@@ -8,17 +8,77 @@ 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
13
  import { EditorContent, useEditor } from "@tiptap/react";
14
+ import { BubbleMenu as TiptapBubbleMenu, } from "@tiptap/react/menus";
15
+ import { isTextSelection } from "@tiptap/core";
14
16
  import { DOMParser as ProseMirrorDOMParser } from "@tiptap/pm/model";
17
+ import { TextSelection } from "@tiptap/pm/state";
15
18
  import { Toolbar } from "./Toolbar";
16
- import getTipTapExtensions from "./Extensions/getTiptapExtensions";
17
- import { Extensions, SlashCommands } from "./Enums";
19
+ import getTipTapExtensions, { resolveExtensions, } from "./Extensions/getTiptapExtensions";
20
+ import { Controls, Extensions, SlashCommands } from "./Enums";
18
21
  import { addImagePlaceholder, removeImagePlaceholder, startImageUpload, } from "./Plugins/UploadImagesPlugin";
19
22
  import SaveBadge from "./Components/SaveBadge";
23
+ import BubbleMenuContent from "./Components/BubbleMenu";
20
24
  import Fonts from "./Enums/Fonts";
21
25
  import RichTextEditorContext from "./Contexts/RichTextEditorContext";
26
+ import { getLinkAttributesAtPosition, getLinkRangeAtPosition, openLink, } from "./Utils/linkUtils";
27
+ const codeBlockFallbacks = {
28
+ light: {
29
+ background: "#f6f8fa",
30
+ text: "#24292f",
31
+ border: "#d0d7de",
32
+ selection: "#0969da2e",
33
+ syntax: {
34
+ comment: "#6e7781",
35
+ punctuation: "#24292f",
36
+ property: "#0550ae",
37
+ selector: "#116329",
38
+ operator: "#cf222e",
39
+ keyword: "#cf222e",
40
+ string: "#0a3069",
41
+ number: "#0550ae",
42
+ function: "#8250df",
43
+ variable: "#953800",
44
+ tag: "#116329",
45
+ attribute: "#0550ae",
46
+ literal: "#0550ae",
47
+ deleted: "#82071e",
48
+ inserted: "#116329",
49
+ },
50
+ },
51
+ dark: {
52
+ background: "#0d1117",
53
+ text: "#c9d1d9",
54
+ border: "#30363d",
55
+ selection: "#1f6feb40",
56
+ syntax: {
57
+ comment: "#8b949e",
58
+ punctuation: "#c9d1d9",
59
+ property: "#79c0ff",
60
+ selector: "#7ee787",
61
+ operator: "#ff7b72",
62
+ keyword: "#ff7b72",
63
+ string: "#a5d6ff",
64
+ number: "#79c0ff",
65
+ function: "#d2a8ff",
66
+ variable: "#ffa657",
67
+ tag: "#7ee787",
68
+ attribute: "#79c0ff",
69
+ literal: "#79c0ff",
70
+ deleted: "#ffa198",
71
+ inserted: "#aff5b4",
72
+ },
73
+ },
74
+ };
75
+ const getCodeBlockTheme = (theme) => {
76
+ if (theme.palette.codeBlock)
77
+ return theme.palette.codeBlock;
78
+ return theme.palette.mode === "DARK"
79
+ ? codeBlockFallbacks.dark
80
+ : codeBlockFallbacks.light;
81
+ };
22
82
  const getImageFilesFromClipboard = (clipboardData) => {
23
83
  return Array.from(clipboardData.files).filter((file) => file.type.includes("image/"));
24
84
  };
@@ -317,6 +377,158 @@ const StyledContent = styled.div `
317
377
  margin: 0;
318
378
  line-height: 1.5rem;
319
379
  }
380
+ .editor-inline-code,
381
+ :not(pre) > code {
382
+ padding: 0.1rem 0.25rem;
383
+ border: 1px solid ${({ theme }) => theme.palette.divider};
384
+ border-radius: 4px;
385
+ background-color: ${({ theme }) => theme.palette.action.hover};
386
+ color: ${({ theme }) => theme.palette.text.secondary};
387
+ font-family:
388
+ ui-monospace, SFMono-Regular, SFMono-Regular, Menlo, Monaco, Consolas,
389
+ "Liberation Mono", "Courier New", monospace;
390
+ font-size: 0.9em;
391
+ box-decoration-break: clone;
392
+ }
393
+ .editor-code-block {
394
+ position: relative;
395
+ margin: 0.5rem 0;
396
+ padding: 1rem 0.875rem;
397
+ overflow-x: auto;
398
+ border: 1px solid ${({ theme }) => getCodeBlockTheme(theme).border};
399
+ border-radius: 6px;
400
+ background-color: ${({ theme }) => getCodeBlockTheme(theme).background};
401
+ color: ${({ theme }) => getCodeBlockTheme(theme).text};
402
+ font-family:
403
+ ui-monospace, SFMono-Regular, SFMono-Regular, Menlo, Monaco, Consolas,
404
+ "Liberation Mono", "Courier New", monospace;
405
+ font-size: 0.85rem;
406
+ line-height: 1.45rem;
407
+ white-space: pre;
408
+
409
+ ::selection {
410
+ background-color: ${({ theme }) => getCodeBlockTheme(theme).selection};
411
+ }
412
+
413
+ &[data-wrap="true"] {
414
+ white-space: pre-wrap;
415
+ word-break: break-word;
416
+ overflow-wrap: anywhere;
417
+ }
418
+
419
+ code {
420
+ display: block;
421
+ min-width: max-content;
422
+ padding: 0;
423
+ border: 0;
424
+ background-color: transparent;
425
+ color: inherit;
426
+ font: inherit;
427
+ }
428
+
429
+ &[data-wrap="true"] code {
430
+ min-width: 0;
431
+ white-space: inherit;
432
+ }
433
+
434
+ .editor-code-block-actions {
435
+ display: flex;
436
+ align-items: center;
437
+ position: absolute;
438
+ top: 0.4rem;
439
+ right: 0.4rem;
440
+ z-index: 1;
441
+ gap: 0.25rem;
442
+ opacity: 0;
443
+ transition: opacity 120ms ease-in-out;
444
+ }
445
+
446
+ &:hover .editor-code-block-actions,
447
+ &:focus-within .editor-code-block-actions {
448
+ opacity: 1;
449
+ }
450
+
451
+ .hljs-comment,
452
+ .hljs-quote {
453
+ color: ${({ theme }) => getCodeBlockTheme(theme).syntax.comment};
454
+ }
455
+
456
+ .hljs-punctuation {
457
+ color: ${({ theme }) => getCodeBlockTheme(theme).syntax.punctuation};
458
+ }
459
+
460
+ .hljs-property,
461
+ .hljs-attr,
462
+ .hljs-attribute,
463
+ .hljs-doctag {
464
+ color: ${({ theme }) => getCodeBlockTheme(theme).syntax.property};
465
+ }
466
+
467
+ .hljs-selector-tag,
468
+ .hljs-selector-id,
469
+ .hljs-selector-class,
470
+ .hljs-selector-attr,
471
+ .hljs-selector-pseudo {
472
+ color: ${({ theme }) => getCodeBlockTheme(theme).syntax.selector};
473
+ }
474
+
475
+ .hljs-operator,
476
+ .hljs-params {
477
+ color: ${({ theme }) => getCodeBlockTheme(theme).syntax.operator};
478
+ }
479
+
480
+ .hljs-keyword,
481
+ .hljs-meta .hljs-keyword,
482
+ .hljs-template-tag,
483
+ .hljs-template-variable {
484
+ color: ${({ theme }) => getCodeBlockTheme(theme).syntax.keyword};
485
+ }
486
+
487
+ .hljs-string,
488
+ .hljs-regexp {
489
+ color: ${({ theme }) => getCodeBlockTheme(theme).syntax.string};
490
+ }
491
+
492
+ .hljs-number {
493
+ color: ${({ theme }) => getCodeBlockTheme(theme).syntax.number};
494
+ }
495
+
496
+ .hljs-title,
497
+ .hljs-title.function_,
498
+ .hljs-title.class_ {
499
+ color: ${({ theme }) => getCodeBlockTheme(theme).syntax.function};
500
+ }
501
+
502
+ .hljs-variable,
503
+ .hljs-name,
504
+ .hljs-section,
505
+ .hljs-symbol {
506
+ color: ${({ theme }) => getCodeBlockTheme(theme).syntax.variable};
507
+ }
508
+
509
+ .hljs-tag {
510
+ color: ${({ theme }) => getCodeBlockTheme(theme).syntax.tag};
511
+ }
512
+
513
+ .hljs-built_in,
514
+ .hljs-type,
515
+ .hljs-literal {
516
+ color: ${({ theme }) => getCodeBlockTheme(theme).syntax.literal};
517
+ }
518
+
519
+ .hljs-meta,
520
+ .hljs-link {
521
+ color: ${({ theme }) => getCodeBlockTheme(theme).syntax.attribute};
522
+ }
523
+
524
+ .hljs-deletion {
525
+ color: ${({ theme }) => getCodeBlockTheme(theme).syntax.deleted};
526
+ }
527
+
528
+ .hljs-addition {
529
+ color: ${({ theme }) => getCodeBlockTheme(theme).syntax.inserted};
530
+ }
531
+ }
320
532
  ul {
321
533
  margin: 0;
322
534
  }
@@ -330,8 +542,6 @@ const StyledContent = styled.div `
330
542
  color: ${({ theme }) => theme.palette.text.primary};
331
543
  text-decoration: underline;
332
544
  cursor: pointer;
333
- // Set title attribute
334
- title: "Click to open link";
335
545
  }
336
546
  img {
337
547
  max-width: 100%;
@@ -543,16 +753,99 @@ const StyledContent = styled.div `
543
753
  margin: 0 0.125rem;
544
754
  }
545
755
  `;
546
- export const RichTextEditor = ({ className, editorInstanceRef, defaultValue = "", value, readOnly = false, font, showToolbar = true, saving = false, extensions = [], slashCommands = [], bubbleMenuOptions, toolbarOptions, autoFocus, onChange, handleImageUpload, handleImageUrlUpload, style, }) => {
756
+ 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, }) => {
757
+ const resolvedExtensions = useMemo(() => resolveExtensions({
758
+ disabledExtensions,
759
+ extensionPreset,
760
+ extensions,
761
+ }), [disabledExtensions, extensionPreset, extensions]);
762
+ const resolvedExtensionSet = useMemo(() => new Set(resolvedExtensions), [resolvedExtensions]);
763
+ const resolvedSlashCommands = useMemo(() => slashCommands.filter((command) => {
764
+ if (command === SlashCommands.Code) {
765
+ return resolvedExtensionSet.has(Extensions.Code);
766
+ }
767
+ if (command === SlashCommands.CodeBlock) {
768
+ return resolvedExtensionSet.has(Extensions.CodeBlock);
769
+ }
770
+ return true;
771
+ }), [resolvedExtensionSet, slashCommands]);
772
+ const resolvedToolbarOptions = useMemo(() => {
773
+ if (!(toolbarOptions === null || toolbarOptions === void 0 ? void 0 : toolbarOptions.controls))
774
+ return toolbarOptions;
775
+ const controlExtensionMap = {
776
+ [Controls.BOLD]: Extensions.Bold,
777
+ [Controls.ITALIC]: Extensions.Italic,
778
+ [Controls.UNDERLINE]: Extensions.Underline,
779
+ [Controls.STRIKE]: Extensions.Strike,
780
+ [Controls.CODE]: Extensions.Code,
781
+ [Controls.CODE_BLOCK]: Extensions.CodeBlock,
782
+ [Controls.BULLET_LIST]: Extensions.BulletList,
783
+ [Controls.ORDERED_LIST]: Extensions.OrderedList,
784
+ [Controls.COLOR]: Extensions.Color,
785
+ [Controls.HIGHLIGHT]: Extensions.Highlight,
786
+ [Controls.LINK]: Extensions.Link,
787
+ [Controls.TEXT_ALIGN_LEFT]: Extensions.TextAlign,
788
+ [Controls.TEXT_ALIGN_CENTER]: Extensions.TextAlign,
789
+ [Controls.TEXT_ALIGN_RIGHT]: Extensions.TextAlign,
790
+ [Controls.TEXT_ALIGN_JUSTIFIED]: Extensions.TextAlign,
791
+ };
792
+ return Object.assign(Object.assign({}, toolbarOptions), { controls: toolbarOptions.controls.filter((control) => {
793
+ if (typeof control !== "string")
794
+ return true;
795
+ const extension = controlExtensionMap[control];
796
+ return !extension || resolvedExtensionSet.has(extension);
797
+ }) });
798
+ }, [resolvedExtensionSet, toolbarOptions]);
547
799
  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);
800
+ const hasImageExtension = resolvedExtensionSet.has(Extensions.Image);
801
+ const hasSlashCommandExtension = resolvedExtensionSet.has(Extensions.SlashCommand);
802
+ const hasBubbleMenuExtension = resolvedExtensionSet.has(Extensions.BubbleMenu);
803
+ const hasImageSlashCommand = hasSlashCommandExtension &&
804
+ resolvedSlashCommands.includes(SlashCommands.Image);
551
805
  const onChangeRef = useRef(onChange);
806
+ const bubbleMenuPortalRef = useRef(null);
552
807
  const [fontState, setFontState] = useState(font || Fonts.DEFAULT);
553
808
  useEffect(() => {
554
809
  onChangeRef.current = onChange;
555
810
  }, [onChange]);
811
+ const getBubbleMenuPortalRoot = useCallback(() => {
812
+ if (bubbleMenuPortalRef.current) {
813
+ return bubbleMenuPortalRef.current;
814
+ }
815
+ const portal = document.createElement("div");
816
+ portal.setAttribute("data-monolith-bubble-menu-portal", "");
817
+ document.body.appendChild(portal);
818
+ bubbleMenuPortalRef.current = portal;
819
+ return portal;
820
+ }, []);
821
+ useEffect(() => {
822
+ return () => {
823
+ var _a;
824
+ (_a = bubbleMenuPortalRef.current) === null || _a === void 0 ? void 0 : _a.remove();
825
+ bubbleMenuPortalRef.current = null;
826
+ };
827
+ }, []);
828
+ const shouldShowBubbleMenu = useCallback(({ editor, element, view, state, from, to }) => {
829
+ const { selection } = state;
830
+ const isChildOfMenu = element.contains(document.activeElement);
831
+ const hasEditorFocus = view.hasFocus() || isChildOfMenu;
832
+ const selectedText = state.doc.textBetween(from, to).trim();
833
+ const isEmptyTextBlock = !selectedText && isTextSelection(state.selection);
834
+ if (!hasEditorFocus ||
835
+ selection.empty ||
836
+ isEmptyTextBlock ||
837
+ !editor.isEditable) {
838
+ return false;
839
+ }
840
+ return true;
841
+ }, []);
842
+ const bubbleMenuPositionOptions = useMemo(() => ({
843
+ strategy: "fixed",
844
+ placement: "top",
845
+ offset: 8,
846
+ flip: false,
847
+ shift: { padding: 10 },
848
+ }), []);
556
849
  if (hasImageSlashCommand && !hasImageExtension) {
557
850
  throw new Error("Extensions.Image is required when using the Image slash command.");
558
851
  }
@@ -566,12 +859,29 @@ export const RichTextEditor = ({ className, editorInstanceRef, defaultValue = ""
566
859
  editable: !readOnly,
567
860
  shouldRerenderOnTransaction: true,
568
861
  extensions: getTipTapExtensions({
569
- extensions,
570
- slashCommands,
571
- bubbleMenuOptions,
862
+ disabledExtensions,
863
+ extensions: resolvedExtensions,
864
+ slashCommands: resolvedSlashCommands,
572
865
  handleImageUpload,
573
866
  }),
574
867
  editorProps: {
868
+ handleClick: (view, pos, event) => {
869
+ const linkRange = getLinkRangeAtPosition(view.state, pos);
870
+ const linkAttributes = getLinkAttributesAtPosition(view.state, pos);
871
+ if (!linkRange || !(linkAttributes === null || linkAttributes === void 0 ? void 0 : linkAttributes.href))
872
+ return false;
873
+ const mouseEvent = event;
874
+ mouseEvent.preventDefault();
875
+ mouseEvent.stopPropagation();
876
+ const shouldOpenLink = mouseEvent.metaKey || mouseEvent.ctrlKey || !view.editable;
877
+ if (shouldOpenLink) {
878
+ openLink(linkAttributes.href);
879
+ return true;
880
+ }
881
+ view.dispatch(view.state.tr.setSelection(TextSelection.create(view.state.doc, linkRange.from, linkRange.to)));
882
+ view.focus();
883
+ return true;
884
+ },
575
885
  handlePaste: (view, event) => {
576
886
  if (!hasImageExtension || !handleImageUpload)
577
887
  return false;
@@ -632,5 +942,5 @@ export const RichTextEditor = ({ className, editorInstanceRef, defaultValue = ""
632
942
  return (_jsx(StyledContent, { className: className, children: _jsxs(RichTextEditorContext.Provider, { value: {
633
943
  font: fontState,
634
944
  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 })] }) }));
945
+ }, 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
946
  };
@@ -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
  }
@@ -1,33 +1,41 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import styled, { useTheme } from "styled-components";
3
3
  import ControlsGroup from "./ControlsGroup";
4
- import { UndoControl, RedoControl, BoldControl, ItalicControl, UnderlineControl, StrikeThroughControl, Heading1Control, Heading2Control, Heading3Control, Heading4Control, BulletListControl, OrderedListControl, AlignLeftControl, AlignCenterControl, AlignRightControl, AlignJustifiedControl, } from "./Controls";
4
+ import { UndoControl, RedoControl, BoldControl, ItalicControl, UnderlineControl, StrikeThroughControl, CodeControl, CodeBlockControl, Heading1Control, Heading2Control, Heading3Control, Heading4Control, BulletListControl, OrderedListControl, AlignLeftControl, AlignCenterControl, AlignRightControl, AlignJustifiedControl, } from "./Controls";
5
5
  import { Controls } from "../Enums";
6
6
  import { DropDownMenu } from "../../DropDownMenu";
7
7
  import Fonts from "../Enums/Fonts";
8
- import { useContext } from "react";
8
+ import { useContext, useState } from "react";
9
9
  import RichTextEditorContext from "../Contexts/RichTextEditorContext";
10
10
  import { Button } from "../../Button";
11
+ import { Popover } from "../../Popover";
11
12
  import TextColors from "../Enums/TextColors";
12
- import { SquircleIcon } from "lucide-react";
13
+ import HighlightColors from "../Enums/HighlightColors";
14
+ import LinkEditor from "../Components/LinkEditor";
15
+ import CodeBlockWrapButton from "../Components/CodeBlockWrapButton";
16
+ import CodeBlockFormatButton from "../Components/CodeBlockFormatButton";
17
+ import { hasSyntaxHighlightedCodeBlock } from "../Utils/codeBlockUtils";
18
+ import { HighlighterIcon, LinkIcon, PaletteIcon, SquircleIcon, TypeIcon, } from "lucide-react";
13
19
  export const Toolbar = styled(({ className, editor, toolbarOptions }) => {
14
20
  var _a;
15
21
  const theme = useTheme();
16
22
  const { controls } = toolbarOptions || {};
23
+ const [linkPopoverOpen, setLinkPopoverOpen] = useState(false);
17
24
  const customItems = controls === null || controls === void 0 ? void 0 : controls.filter((control) => typeof control !== "string" &&
18
25
  (control.type === "menu" || control.type === "button"));
19
26
  const { font, setFont } = useContext(RichTextEditorContext);
27
+ const showCodeBlockLanguageSelect = (editor === null || editor === void 0 ? void 0 : editor.isActive("codeBlock")) && hasSyntaxHighlightedCodeBlock(editor);
20
28
  return (_jsxs("div", { className: className, children: [(_a = customItems === null || customItems === void 0 ? void 0 : customItems.map) === null || _a === void 0 ? void 0 : _a.call(customItems, (item, index) => {
21
29
  var _a, _b;
22
30
  if (item.type === "button") {
23
- return (_jsx(Button, Object.assign({}, item.options, { children: (_a = item === null || item === void 0 ? void 0 : item.options) === null || _a === void 0 ? void 0 : _a.label }), index));
31
+ return (_jsx(Button, Object.assign({ size: "xs" }, item.options, { children: (_a = item === null || item === void 0 ? void 0 : item.options) === null || _a === void 0 ? void 0 : _a.label }), index));
24
32
  }
25
33
  else if (item.type === "menu") {
26
34
  return (_jsx(DropDownMenu, Object.assign({ dropDownProps: {
27
35
  style: {
28
36
  width: 135,
29
37
  },
30
- } }, item.options, { children: (_b = item === null || item === void 0 ? void 0 : item.options) === null || _b === void 0 ? void 0 : _b.label }), index));
38
+ } }, item.options, { size: "xs", children: (_b = item === null || item === void 0 ? void 0 : item.options) === null || _b === void 0 ? void 0 : _b.label }), index));
31
39
  }
32
40
  }), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.FONT)) && (_jsx(DropDownMenu, { data: Object.values(Fonts).map((font) => ({
33
41
  label: font,
@@ -35,12 +43,13 @@ export const Toolbar = styled(({ className, editor, toolbarOptions }) => {
35
43
  onClick: () => {
36
44
  setFont(font);
37
45
  },
38
- })), size: "xxs", variant: "outlined", arrow: true, dropDownProps: {
46
+ })), size: "xs", variant: "outlined", dropDownProps: {
39
47
  style: {
40
48
  width: 135,
41
49
  },
42
50
  }, buttonProps: {
43
51
  title: "Select Font",
52
+ leftSection: _jsx(TypeIcon, { size: 12 }),
44
53
  }, children: (font || Fonts.DEFAULT) })), _jsxs(ControlsGroup, { children: [(controls === null || controls === void 0 ? void 0 : controls.includes(Controls.UNDO)) && _jsx(UndoControl, { editor: editor }), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.REDO)) && _jsx(RedoControl, { editor: editor })] }), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.COLOR)) && (_jsx(DropDownMenu, { data: [
45
54
  {
46
55
  label: "Default",
@@ -66,20 +75,63 @@ export const Toolbar = styled(({ className, editor, toolbarOptions }) => {
66
75
  ? theme.palette.text.primary
67
76
  : item.value,
68
77
  borderRadius: "3px",
69
- } }), item.label] })), size: "xxs", variant: "outlined", arrow: true, buttonProps: {
78
+ } }), item.label] })), size: "xs", variant: "outlined", buttonProps: {
70
79
  title: "Select Color",
80
+ style: { padding: "1px 6px" },
81
+ }, dropDownProps: {
82
+ style: {
83
+ width: 120,
84
+ },
85
+ }, children: _jsx(PaletteIcon, { size: 14 }) })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.HIGHLIGHT)) && (_jsx(DropDownMenu, { data: [
86
+ {
87
+ label: "Default",
88
+ value: "default",
89
+ onClick: () => {
90
+ editor === null || editor === void 0 ? void 0 : editor.chain().focus().unsetHighlight().run();
91
+ },
92
+ },
93
+ ...Object.keys(HighlightColors).map((color) => {
94
+ const colorKey = color;
95
+ return {
96
+ label: color,
97
+ value: HighlightColors[colorKey],
98
+ onClick: () => {
99
+ editor === null || editor === void 0 ? void 0 : editor.chain().focus().setHighlight({ color: HighlightColors[colorKey] }).run();
100
+ },
101
+ };
102
+ }),
103
+ ], renderOption: (item) => (_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 5 }, children: [_jsx(SquircleIcon, { size: 12, color: item.value === "default"
104
+ ? theme.palette.text.primary
105
+ : item.value, style: {
106
+ backgroundColor: item.value === "default"
107
+ ? "transparent"
108
+ : item.value,
109
+ borderRadius: "3px",
110
+ } }), item.label] })), size: "xs", variant: "outlined", buttonProps: {
111
+ title: "Select Highlight",
112
+ style: { padding: "1px 6px" },
71
113
  }, dropDownProps: {
72
114
  style: {
73
115
  width: 100,
116
+ height: 210,
74
117
  },
75
- }, children: "Color" })), _jsxs(ControlsGroup, { children: [(controls === null || controls === void 0 ? void 0 : controls.includes(Controls.BOLD)) && _jsx(BoldControl, { editor: editor }), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.ITALIC)) && (_jsx(ItalicControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.UNDERLINE)) && (_jsx(UnderlineControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.STRIKE)) && (_jsx(StrikeThroughControl, { editor: editor }))] }), _jsxs(ControlsGroup, { children: [(controls === null || controls === void 0 ? void 0 : controls.includes(Controls.HEADING_1)) && (_jsx(Heading1Control, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.HEADING_2)) && (_jsx(Heading2Control, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.HEADING_3)) && (_jsx(Heading3Control, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.HEADING_4)) && (_jsx(Heading4Control, { editor: editor }))] }), _jsxs(ControlsGroup, { children: [(controls === null || controls === void 0 ? void 0 : controls.includes(Controls.BULLET_LIST)) && (_jsx(BulletListControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.ORDERED_LIST)) && (_jsx(OrderedListControl, { editor: editor }))] }), _jsxs(ControlsGroup, { children: [(controls === null || controls === void 0 ? void 0 : controls.includes(Controls.TEXT_ALIGN_LEFT)) && (_jsx(AlignLeftControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.TEXT_ALIGN_CENTER)) && (_jsx(AlignCenterControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.TEXT_ALIGN_RIGHT)) && (_jsx(AlignRightControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.TEXT_ALIGN_JUSTIFIED)) && (_jsx(AlignJustifiedControl, { editor: editor }))] })] }));
118
+ }, children: _jsx(HighlighterIcon, { size: 14 }) })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.LINK)) && (_jsxs(Popover, { opened: linkPopoverOpen, onChange: setLinkPopoverOpen, position: "bottom", width: 330, trapFocus: true, children: [_jsx(Popover.Target, { children: _jsx(Button, { size: "xs", variant: "outlined", title: "Link", "aria-label": "Link", selected: linkPopoverOpen || Boolean(editor === null || editor === void 0 ? void 0 : editor.isActive("link")), disabled: !editor, style: { padding: "1px 6px" }, children: _jsx(LinkIcon, { size: 14 }) }) }), _jsx(Popover.Dropdown, { children: editor && (_jsx(LinkEditor, { editor: editor, autoFocus: linkPopoverOpen, onClose: () => setLinkPopoverOpen(false) })) })] })), _jsxs(ControlsGroup, { children: [(controls === null || controls === void 0 ? void 0 : controls.includes(Controls.BOLD)) && _jsx(BoldControl, { editor: editor }), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.ITALIC)) && (_jsx(ItalicControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.UNDERLINE)) && (_jsx(UnderlineControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.STRIKE)) && (_jsx(StrikeThroughControl, { editor: editor }))] }), _jsxs(ControlsGroup, { children: [(controls === null || controls === void 0 ? void 0 : controls.includes(Controls.CODE)) && _jsx(CodeControl, { editor: editor }), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.CODE_BLOCK)) && (_jsx(CodeBlockControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.CODE_BLOCK)) &&
119
+ showCodeBlockLanguageSelect && (_jsxs(_Fragment, { children: [_jsx(CodeBlockWrapButton, { editor: editor }), _jsx(CodeBlockFormatButton, { editor: editor })] }))] }), _jsxs(ControlsGroup, { children: [(controls === null || controls === void 0 ? void 0 : controls.includes(Controls.HEADING_1)) && (_jsx(Heading1Control, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.HEADING_2)) && (_jsx(Heading2Control, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.HEADING_3)) && (_jsx(Heading3Control, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.HEADING_4)) && (_jsx(Heading4Control, { editor: editor }))] }), _jsxs(ControlsGroup, { children: [(controls === null || controls === void 0 ? void 0 : controls.includes(Controls.BULLET_LIST)) && (_jsx(BulletListControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.ORDERED_LIST)) && (_jsx(OrderedListControl, { editor: editor }))] }), _jsxs(ControlsGroup, { children: [(controls === null || controls === void 0 ? void 0 : controls.includes(Controls.TEXT_ALIGN_LEFT)) && (_jsx(AlignLeftControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.TEXT_ALIGN_CENTER)) && (_jsx(AlignCenterControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.TEXT_ALIGN_RIGHT)) && (_jsx(AlignRightControl, { editor: editor })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.TEXT_ALIGN_JUSTIFIED)) && (_jsx(AlignJustifiedControl, { editor: editor }))] })] }));
76
120
  }) `
77
121
  display: flex;
78
122
  flex-direction: row;
123
+ flex-wrap: wrap;
79
124
  justify-content: center;
80
125
  align-items: center;
81
126
  gap: 5px;
127
+ row-gap: 6px;
128
+ width: 100%;
82
129
  margin-bottom: 10px;
83
130
  border-radius: 5px 5px 0 0;
84
131
  border: 1px solid transparent;
132
+
133
+ > button,
134
+ > .mfui-DropDownMenu {
135
+ flex: 0 0 auto;
136
+ }
85
137
  `;
@@ -0,0 +1,20 @@
1
+ import { Editor } from "@tiptap/react";
2
+ export type CodeBlockLanguage = {
3
+ label: string;
4
+ value: string;
5
+ };
6
+ export declare const DEFAULT_CODE_BLOCK_LANGUAGE = "plaintext";
7
+ export declare const CODE_BLOCK_LANGUAGES: CodeBlockLanguage[];
8
+ export declare const getCodeBlockLanguage: (editor: Editor | null) => string;
9
+ export declare const getCodeBlockLanguageOption: (language?: string) => CodeBlockLanguage;
10
+ export declare const canFormatCodeBlockLanguage: (language?: string) => boolean;
11
+ export declare const formatCodeBlockText: (text: string, language?: string) => Promise<string>;
12
+ export declare const hasSyntaxHighlightedCodeBlock: (editor: Editor | null) => boolean;
13
+ export declare const setCodeBlockLanguage: (editor: Editor | null, language: string) => void;
14
+ export declare const getCodeBlockWrap: (editor: Editor | null) => boolean;
15
+ export declare const toggleCodeBlockWrap: (editor: Editor | null) => void;
16
+ export declare const toggleCodeBlock: (editor: Editor | null) => void;
17
+ export declare const getActiveCodeBlockText: (editor: Editor | null) => string;
18
+ export declare const replaceCodeBlockContent: (editor: Editor, from: number, to: number, text: string) => boolean;
19
+ export declare const formatActiveCodeBlock: (editor: Editor | null) => Promise<void>;
20
+ export declare const copyCodeBlockText: (text: string) => Promise<void>;