@monolith-forensics/monolith-ui 1.9.1-dev.9 → 1.9.3-dev.1

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 (125) hide show
  1. package/dist/Charts/BarChart/BarChart.js +28 -14
  2. package/dist/Charts/BarChart/BarChart.styled.d.ts +7 -2
  3. package/dist/Charts/BarChart/BarChart.styled.js +5 -1
  4. package/dist/Charts/BarChart/BarChart.types.d.ts +13 -5
  5. package/dist/Charts/ChartUtils/chartSizing.d.ts +20 -0
  6. package/dist/Charts/ChartUtils/chartSizing.js +83 -0
  7. package/dist/Charts/ChartUtils/index.d.ts +1 -0
  8. package/dist/Charts/ChartUtils/index.js +1 -0
  9. package/dist/Charts/HeatMap/HeatMap.js +28 -7
  10. package/dist/Charts/HeatMap/HeatMap.styled.d.ts +6 -2
  11. package/dist/Charts/HeatMap/HeatMap.styled.js +3 -0
  12. package/dist/Charts/HeatMap/HeatMap.types.d.ts +7 -1
  13. package/dist/Charts/LineChart/LineChart.js +34 -15
  14. package/dist/Charts/LineChart/LineChart.styled.d.ts +7 -2
  15. package/dist/Charts/LineChart/LineChart.styled.js +5 -1
  16. package/dist/Charts/LineChart/LineChart.types.d.ts +13 -5
  17. package/dist/Charts/PieChart/PieChart.js +48 -33
  18. package/dist/Charts/PieChart/PieChart.styled.d.ts +7 -2
  19. package/dist/Charts/PieChart/PieChart.styled.js +6 -1
  20. package/dist/Charts/PieChart/PieChart.types.d.ts +7 -3
  21. package/dist/DropDownMenu/components/MenuItemList.js +32 -12
  22. package/dist/DropDownMenu/components/StyledContent.js +1 -1
  23. package/dist/DropDownMenu/components/StyledInnerItemContainer.js +1 -0
  24. package/dist/FieldLabel/FieldLabel.js +3 -18
  25. package/dist/FileViewer/FileViewer.js +32 -8
  26. package/dist/FileViewer/viewers/ImageViewer.d.ts +1 -0
  27. package/dist/FileViewer/viewers/ImageViewer.js +36 -15
  28. package/dist/MonolithUIProvider/MonolithUIProvider.d.ts +23 -0
  29. package/dist/RichTextEditor/Components/BubbleMenu.d.ts +3 -3
  30. package/dist/RichTextEditor/Components/BubbleMenu.js +190 -51
  31. package/dist/RichTextEditor/Components/CodeBlockBaseButton.d.ts +18 -0
  32. package/dist/RichTextEditor/Components/CodeBlockBaseButton.js +6 -0
  33. package/dist/RichTextEditor/Components/CodeBlockCopyButton.d.ts +9 -0
  34. package/dist/RichTextEditor/Components/CodeBlockCopyButton.js +42 -0
  35. package/dist/RichTextEditor/Components/CodeBlockFormatButton.d.ts +10 -0
  36. package/dist/RichTextEditor/Components/CodeBlockFormatButton.js +60 -0
  37. package/dist/RichTextEditor/Components/CodeBlockLanguageSelect.d.ts +9 -0
  38. package/dist/RichTextEditor/Components/CodeBlockLanguageSelect.js +30 -0
  39. package/dist/RichTextEditor/Components/CodeBlockNodeView.d.ts +3 -0
  40. package/dist/RichTextEditor/Components/CodeBlockNodeView.js +28 -0
  41. package/dist/RichTextEditor/Components/CodeBlockWrapButton.d.ts +10 -0
  42. package/dist/RichTextEditor/Components/CodeBlockWrapButton.js +17 -0
  43. package/dist/RichTextEditor/Components/LinkEditor.d.ts +8 -0
  44. package/dist/RichTextEditor/Components/LinkEditor.js +94 -0
  45. package/dist/RichTextEditor/Components/TableTools/TableCornerMenu.d.ts +2 -0
  46. package/dist/RichTextEditor/Components/TableTools/TableCornerMenu.js +19 -0
  47. package/dist/RichTextEditor/Components/TableTools/TableInsertControls.d.ts +2 -0
  48. package/dist/RichTextEditor/Components/TableTools/TableInsertControls.js +24 -0
  49. package/dist/RichTextEditor/Components/TableTools/TableRails.d.ts +2 -0
  50. package/dist/RichTextEditor/Components/TableTools/TableRails.js +180 -0
  51. package/dist/RichTextEditor/Components/TableTools/TableToolMenu.d.ts +5 -0
  52. package/dist/RichTextEditor/Components/TableTools/TableToolMenu.js +6 -0
  53. package/dist/RichTextEditor/Components/TableTools/TableTools.actions.d.ts +5 -0
  54. package/dist/RichTextEditor/Components/TableTools/TableTools.actions.js +183 -0
  55. package/dist/RichTextEditor/Components/TableTools/TableTools.commands.d.ts +16 -0
  56. package/dist/RichTextEditor/Components/TableTools/TableTools.commands.js +217 -0
  57. package/dist/RichTextEditor/Components/TableTools/TableTools.constants.d.ts +8 -0
  58. package/dist/RichTextEditor/Components/TableTools/TableTools.constants.js +11 -0
  59. package/dist/RichTextEditor/Components/TableTools/TableTools.d.ts +3 -0
  60. package/dist/RichTextEditor/Components/TableTools/TableTools.geometry.d.ts +23 -0
  61. package/dist/RichTextEditor/Components/TableTools/TableTools.geometry.js +75 -0
  62. package/dist/RichTextEditor/Components/TableTools/TableTools.js +3 -0
  63. package/dist/RichTextEditor/Components/TableTools/TableTools.selectors.d.ts +16 -0
  64. package/dist/RichTextEditor/Components/TableTools/TableTools.selectors.js +53 -0
  65. package/dist/RichTextEditor/Components/TableTools/TableTools.styled.d.ts +40 -0
  66. package/dist/RichTextEditor/Components/TableTools/TableTools.styled.js +167 -0
  67. package/dist/RichTextEditor/Components/TableTools/TableTools.types.d.ts +76 -0
  68. package/dist/RichTextEditor/Components/TableTools/TableTools.types.js +1 -0
  69. package/dist/RichTextEditor/Components/TableTools/TableTools.utils.d.ts +4 -0
  70. package/dist/RichTextEditor/Components/TableTools/TableTools.utils.js +4 -0
  71. package/dist/RichTextEditor/Components/TableTools/TableToolsPopover.d.ts +2 -0
  72. package/dist/RichTextEditor/Components/TableTools/TableToolsPopover.js +12 -0
  73. package/dist/RichTextEditor/Components/TableTools/index.d.ts +3 -0
  74. package/dist/RichTextEditor/Components/TableTools/index.js +2 -0
  75. package/dist/RichTextEditor/Enums/Controls.d.ts +7 -1
  76. package/dist/RichTextEditor/Enums/Controls.js +6 -0
  77. package/dist/RichTextEditor/Enums/Extensions.d.ts +4 -0
  78. package/dist/RichTextEditor/Enums/Extensions.js +4 -0
  79. package/dist/RichTextEditor/Enums/HighlightColors.d.ts +9 -0
  80. package/dist/RichTextEditor/Enums/HighlightColors.js +10 -0
  81. package/dist/RichTextEditor/Enums/SlashCommands.d.ts +4 -1
  82. package/dist/RichTextEditor/Enums/SlashCommands.js +3 -0
  83. package/dist/RichTextEditor/Extensions/SlashCommandList.js +0 -1
  84. package/dist/RichTextEditor/Extensions/getSlashCommand.d.ts +23 -3
  85. package/dist/RichTextEditor/Extensions/getSlashCommand.js +53 -7
  86. package/dist/RichTextEditor/Extensions/getTiptapExtensions.d.ts +15 -2
  87. package/dist/RichTextEditor/Extensions/getTiptapExtensions.js +159 -24
  88. package/dist/RichTextEditor/Plugins/ImageActionsPlugin.js +4 -7
  89. package/dist/RichTextEditor/RichTextEditor.d.ts +9 -4
  90. package/dist/RichTextEditor/RichTextEditor.js +352 -14
  91. package/dist/RichTextEditor/Toolbar/Control.d.ts +6 -2
  92. package/dist/RichTextEditor/Toolbar/Control.js +13 -6
  93. package/dist/RichTextEditor/Toolbar/Controls.d.ts +6 -0
  94. package/dist/RichTextEditor/Toolbar/Controls.js +118 -1
  95. package/dist/RichTextEditor/Toolbar/ControlsGroup.js +17 -6
  96. package/dist/RichTextEditor/Toolbar/Labels.d.ts +1 -0
  97. package/dist/RichTextEditor/Toolbar/Labels.js +1 -0
  98. package/dist/RichTextEditor/Toolbar/Toolbar.d.ts +1 -2
  99. package/dist/RichTextEditor/Toolbar/Toolbar.js +32 -67
  100. package/dist/RichTextEditor/Utils/codeBlockUtils.d.ts +20 -0
  101. package/dist/RichTextEditor/Utils/codeBlockUtils.js +137 -0
  102. package/dist/RichTextEditor/Utils/codeUtils.d.ts +3 -0
  103. package/dist/RichTextEditor/Utils/codeUtils.js +12 -0
  104. package/dist/RichTextEditor/Utils/linkUtils.d.ts +19 -0
  105. package/dist/RichTextEditor/Utils/linkUtils.js +57 -0
  106. package/dist/RichTextEditor/Utils/tableUtils.d.ts +1 -0
  107. package/dist/RichTextEditor/Utils/tableUtils.js +1 -0
  108. package/dist/SegmentedControl/SegmentedControl.js +1 -1
  109. package/dist/SegmentedControl/SegmentedControl.styles.d.ts +1 -0
  110. package/dist/SegmentedControl/SegmentedControl.styles.js +30 -14
  111. package/dist/SegmentedControl/SegmentedControl.utils.d.ts +1 -0
  112. package/dist/SegmentedControl/SegmentedControl.utils.js +5 -2
  113. package/dist/Table/Table.js +4 -3
  114. package/dist/Table/TableComponents.d.ts +3 -0
  115. package/dist/Table/TableComponents.js +47 -0
  116. package/dist/Table/TableHeader.js +1 -1
  117. package/dist/Table/TableMenu/TableMenu.js +4 -3
  118. package/dist/Table/TableProvider.js +39 -0
  119. package/dist/Table/TableRow.js +1 -1
  120. package/dist/Table/types.d.ts +6 -0
  121. package/dist/Utilities/getImageTextContent.d.ts +78 -0
  122. package/dist/Utilities/getImageTextContent.js +222 -0
  123. package/dist/core/controlSizes.js +9 -9
  124. package/dist/theme/variants.js +46 -0
  125. package/package.json +8 -1
@@ -2,9 +2,9 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
2
2
  import styled from "styled-components";
3
3
  import { CodeViewer, ImageViewer, OfficeViewer, PdfViewer, VideoViewer, } from "./viewers";
4
4
  import { FloatingPortal } from "@floating-ui/react";
5
- import { DownloadIcon, XIcon, ZoomInIcon, ZoomOutIcon } from "lucide-react";
5
+ import { DownloadIcon, RotateCwIcon, XIcon, ZoomInIcon, ZoomOutIcon, } from "lucide-react";
6
6
  import { Button } from "../Button";
7
- import { useState } from "react";
7
+ import { useEffect, useState } from "react";
8
8
  import Loader from "../Loader";
9
9
  var ViewerTypes;
10
10
  (function (ViewerTypes) {
@@ -24,7 +24,18 @@ const ZoomableViewerTypes = [
24
24
  ];
25
25
  const RotatableViewerTypes = [ViewerTypes.Image];
26
26
  const OfficeExtensions = ["doc", "docx", "xls", "xlsx", "ppt", "pptx"];
27
- const ImageExtensions = ["jpg", "jpeg", "png", "gif"];
27
+ const ImageExtensions = [
28
+ "jpg",
29
+ "jpeg",
30
+ "png",
31
+ "gif",
32
+ "webp",
33
+ "bmp",
34
+ "svg",
35
+ "avif",
36
+ "tif",
37
+ "tiff",
38
+ ];
28
39
  const VideoExtensions = ["mp4", "webm", "mov"];
29
40
  const AudioExtensions = ["mp3", "wav"];
30
41
  const PDFExtensions = ["pdf"];
@@ -125,10 +136,14 @@ const StyledInnerContainer = styled.div.attrs({
125
136
  }
126
137
  `;
127
138
  const resolveViewerType = (file) => {
128
- var _a, _b;
139
+ var _a, _b, _c;
129
140
  let ext = (_a = file === null || file === void 0 ? void 0 : file.ext) === null || _a === void 0 ? void 0 : _a.toLowerCase();
141
+ const type = (_b = file === null || file === void 0 ? void 0 : file.type) === null || _b === void 0 ? void 0 : _b.toLowerCase();
130
142
  if (!ext) {
131
- ext = (_b = file.name.split(".").pop()) === null || _b === void 0 ? void 0 : _b.toLowerCase();
143
+ ext = (_c = file.name.split(".").pop()) === null || _c === void 0 ? void 0 : _c.toLowerCase();
144
+ }
145
+ if (type === null || type === void 0 ? void 0 : type.startsWith("image/")) {
146
+ return ViewerTypes.Image;
132
147
  }
133
148
  if (!ext) {
134
149
  return ViewerTypes.Code;
@@ -158,19 +173,28 @@ const resolveViewerType = (file) => {
158
173
  };
159
174
  export const FileViewer = ({ file, open, isPending, onClose }) => {
160
175
  const [zoomFactor, setZoomFactor] = useState(1);
176
+ const [rotation, setRotation] = useState(0);
177
+ useEffect(() => {
178
+ setZoomFactor(1);
179
+ setRotation(0);
180
+ }, [file === null || file === void 0 ? void 0 : file.url, file === null || file === void 0 ? void 0 : file.name, open]);
161
181
  if (!open)
162
182
  return null;
163
183
  if (!file)
164
184
  return null;
165
185
  const viewerType = resolveViewerType(file);
186
+ const resetViewerState = () => {
187
+ setZoomFactor(1);
188
+ setRotation(0);
189
+ };
166
190
  const handleBackgroundClick = (e) => {
167
191
  onClose === null || onClose === void 0 ? void 0 : onClose();
168
- setZoomFactor(1);
192
+ resetViewerState();
169
193
  };
170
194
  return (_jsx(FloatingPortal, { preserveTabOrder: true, children: _jsxs(StyledContainer, { className: "mfui-FileViewer", children: [_jsxs(StyledMenu, { className: "FileViewer-menu", children: [_jsx(Button, { variant: "text", onClick: () => {
171
195
  onClose === null || onClose === void 0 ? void 0 : onClose();
172
- setZoomFactor(1);
173
- }, children: _jsx(XIcon, { size: 18 }) }), _jsx("div", { children: file.name }), _jsxs(StyledActionsMenu, { children: [ZoomableViewerTypes.includes(viewerType) && (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "text", disabled: !file.url, children: _jsx(ZoomInIcon, { size: 18, onClick: () => setZoomFactor((prev) => prev * 1.1) }) }), _jsx(Button, { variant: "text", disabled: !file.url, children: _jsx(ZoomOutIcon, { size: 18, onClick: () => setZoomFactor((prev) => prev * 0.9) }) })] })), _jsx("a", { href: file.url, download: file.name, style: { pointerEvents: !file.url ? "none" : "auto" }, children: _jsx(Button, { variant: "text", disabled: !file.url, children: _jsx(DownloadIcon, { size: 18 }) }) })] })] }), file.url ? (_jsxs(StyledInnerContainer, { onClick: handleBackgroundClick, "data-type": viewerType, children: [viewerType === ViewerTypes.PDF && (_jsx(PdfViewer, { file: file, zoomFactor: zoomFactor, isPending: isPending })), viewerType === ViewerTypes.Image && (_jsx(ImageViewer, { file: file, zoomFactor: zoomFactor, isPending: isPending })), viewerType === ViewerTypes.Video && (_jsx(VideoViewer, { file: file, zoomFactor: zoomFactor, isPending: isPending })), viewerType === ViewerTypes.Audio && (_jsx(VideoViewer, { file: file, zoomFactor: zoomFactor, isPending: isPending })), viewerType === ViewerTypes.Office && (_jsx(OfficeViewer, { file: file, isPending: isPending })), viewerType === ViewerTypes.Text && (_jsx(CodeViewer, { file: file, zoomFactor: zoomFactor, isPending: isPending })), viewerType === ViewerTypes.Code && (_jsx(CodeViewer, { file: file, zoomFactor: zoomFactor, isPending: isPending }))] })) : (_jsx(StyledInnerContainer, { children: _jsxs("div", { style: {
196
+ resetViewerState();
197
+ }, children: _jsx(XIcon, { size: 18 }) }), _jsx("div", { children: file.name }), _jsxs(StyledActionsMenu, { children: [ZoomableViewerTypes.includes(viewerType) && (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "text", disabled: !file.url, "aria-label": "Zoom in", title: "Zoom in", onClick: () => setZoomFactor((prev) => prev * 1.1), children: _jsx(ZoomInIcon, { size: 18 }) }), _jsx(Button, { variant: "text", disabled: !file.url, "aria-label": "Zoom out", title: "Zoom out", onClick: () => setZoomFactor((prev) => prev * 0.9), children: _jsx(ZoomOutIcon, { size: 18 }) })] })), RotatableViewerTypes.includes(viewerType) && (_jsx(Button, { variant: "text", disabled: !file.url, "aria-label": "Rotate image", title: "Rotate image", onClick: () => setRotation((prev) => (prev + 90) % 360), children: _jsx(RotateCwIcon, { size: 18 }) })), _jsx("a", { href: file.url, download: file.name, style: { pointerEvents: !file.url ? "none" : "auto" }, children: _jsx(Button, { variant: "text", disabled: !file.url, children: _jsx(DownloadIcon, { size: 18 }) }) })] })] }), file.url ? (_jsxs(StyledInnerContainer, { onClick: handleBackgroundClick, "data-type": viewerType, children: [viewerType === ViewerTypes.PDF && (_jsx(PdfViewer, { file: file, zoomFactor: zoomFactor, isPending: isPending })), viewerType === ViewerTypes.Image && (_jsx(ImageViewer, { file: file, zoomFactor: zoomFactor, rotation: rotation, isPending: isPending })), viewerType === ViewerTypes.Video && (_jsx(VideoViewer, { file: file, zoomFactor: zoomFactor, isPending: isPending })), viewerType === ViewerTypes.Audio && (_jsx(VideoViewer, { file: file, zoomFactor: zoomFactor, isPending: isPending })), viewerType === ViewerTypes.Office && (_jsx(OfficeViewer, { file: file, isPending: isPending })), viewerType === ViewerTypes.Text && (_jsx(CodeViewer, { file: file, zoomFactor: zoomFactor, isPending: isPending })), viewerType === ViewerTypes.Code && (_jsx(CodeViewer, { file: file, zoomFactor: zoomFactor, isPending: isPending }))] })) : (_jsx(StyledInnerContainer, { children: _jsxs("div", { style: {
174
198
  margin: "auto",
175
199
  display: "flex",
176
200
  gap: "10px",
@@ -2,5 +2,6 @@ import { File } from "../FileViewer";
2
2
  export declare const ImageViewer: React.FC<{
3
3
  file: File;
4
4
  zoomFactor?: number;
5
+ rotation?: number;
5
6
  isPending?: boolean;
6
7
  }>;
@@ -10,9 +10,7 @@ const ImageViewerContainer = styled.div `
10
10
  overflow: auto;
11
11
  `;
12
12
  const ImageCanvas = styled.div `
13
- display: flex;
14
- align-items: center;
15
- justify-content: center;
13
+ position: relative;
16
14
  flex: 0 0 auto;
17
15
  min-width: 100%;
18
16
  min-height: 100%;
@@ -20,8 +18,11 @@ const ImageCanvas = styled.div `
20
18
  const Image = styled.img `
21
19
  box-sizing: border-box;
22
20
  display: block;
23
- flex: 0 0 auto;
21
+ position: absolute;
22
+ top: 50%;
23
+ left: 50%;
24
24
  object-fit: contain;
25
+ transform-origin: center;
25
26
 
26
27
  // set orientation
27
28
  image-orientation: from-image;
@@ -36,7 +37,7 @@ const StyledLoader = styled.div `
36
37
  gap: 10px;
37
38
  height: 100%;
38
39
  `;
39
- export const ImageViewer = ({ file, zoomFactor = 1, isPending }) => {
40
+ export const ImageViewer = ({ file, zoomFactor = 1, rotation = 0, isPending }) => {
40
41
  const containerRef = useRef(null);
41
42
  const [imageLoaded, setImageLoaded] = useState(false);
42
43
  const [containerSize, setContainerSize] = useState({
@@ -47,6 +48,8 @@ export const ImageViewer = ({ file, zoomFactor = 1, isPending }) => {
47
48
  naturalWidth: 0,
48
49
  naturalHeight: 0,
49
50
  });
51
+ const normalizedRotation = ((rotation % 360) + 360) % 360;
52
+ const isRotatedSideways = normalizedRotation % 180 !== 0;
50
53
  const fittedDimensions = useMemo(() => {
51
54
  const { naturalWidth, naturalHeight } = originalDimensions;
52
55
  if (naturalWidth === 0 ||
@@ -54,16 +57,33 @@ export const ImageViewer = ({ file, zoomFactor = 1, isPending }) => {
54
57
  containerSize.width === 0 ||
55
58
  containerSize.height === 0) {
56
59
  return {
57
- width: naturalWidth,
58
- height: naturalHeight,
60
+ canvasWidth: isRotatedSideways ? naturalHeight : naturalWidth,
61
+ canvasHeight: isRotatedSideways ? naturalWidth : naturalHeight,
62
+ imageWidth: naturalWidth,
63
+ imageHeight: naturalHeight,
59
64
  };
60
65
  }
61
- const fitScale = Math.min(containerSize.width / naturalWidth, containerSize.height / naturalHeight);
66
+ const rotatedNaturalWidth = isRotatedSideways
67
+ ? naturalHeight
68
+ : naturalWidth;
69
+ const rotatedNaturalHeight = isRotatedSideways
70
+ ? naturalWidth
71
+ : naturalHeight;
72
+ const fitScale = Math.min(containerSize.width / rotatedNaturalWidth, containerSize.height / rotatedNaturalHeight);
73
+ const imageWidth = naturalWidth * fitScale * zoomFactor;
74
+ const imageHeight = naturalHeight * fitScale * zoomFactor;
62
75
  return {
63
- width: naturalWidth * fitScale * zoomFactor,
64
- height: naturalHeight * fitScale * zoomFactor,
76
+ canvasWidth: isRotatedSideways ? imageHeight : imageWidth,
77
+ canvasHeight: isRotatedSideways ? imageWidth : imageHeight,
78
+ imageWidth,
79
+ imageHeight,
65
80
  };
66
- }, [containerSize, originalDimensions, zoomFactor]);
81
+ }, [
82
+ containerSize,
83
+ isRotatedSideways,
84
+ originalDimensions,
85
+ zoomFactor,
86
+ ]);
67
87
  useEffect(() => {
68
88
  if (!file.url)
69
89
  return;
@@ -104,11 +124,12 @@ export const ImageViewer = ({ file, zoomFactor = 1, isPending }) => {
104
124
  return (_jsxs(StyledLoader, { children: [_jsx(Loader, { size: 50 }), _jsx("div", { children: "Loading Image..." })] }));
105
125
  }
106
126
  return (_jsxs(ImageViewerContainer, { ref: containerRef, className: "mfui-ImageViewer", children: [!showImage && (_jsxs(StyledLoader, { children: [_jsx(Loader, { size: 50 }), _jsx("div", { children: "Loading Image..." })] })), showImage && (_jsx(ImageCanvas, { style: {
107
- width: fittedDimensions.width,
108
- height: fittedDimensions.height,
127
+ width: fittedDimensions.canvasWidth,
128
+ height: fittedDimensions.canvasHeight,
109
129
  }, children: _jsx(Image, { src: file.url, alt: file.name ? file.name : "Image", style: {
110
- width: fittedDimensions.width,
111
- height: fittedDimensions.height,
130
+ width: fittedDimensions.imageWidth,
131
+ height: fittedDimensions.imageHeight,
132
+ transform: `translate(-50%, -50%) rotate(${normalizedRotation}deg)`,
112
133
  }, onClick: (e) => {
113
134
  e.stopPropagation();
114
135
  } }) }))] }));
@@ -81,6 +81,29 @@ export interface MonolithDefaultTheme {
81
81
  action: {
82
82
  hover: string;
83
83
  };
84
+ codeBlock?: {
85
+ background: string;
86
+ text: string;
87
+ border: string;
88
+ selection: string;
89
+ syntax: {
90
+ comment: string;
91
+ punctuation: string;
92
+ property: string;
93
+ selector: string;
94
+ operator: string;
95
+ keyword: string;
96
+ string: string;
97
+ number: string;
98
+ function: string;
99
+ variable: string;
100
+ tag: string;
101
+ attribute: string;
102
+ literal: string;
103
+ deleted: string;
104
+ inserted: string;
105
+ };
106
+ };
84
107
  divider: string;
85
108
  };
86
109
  header: {
@@ -1,6 +1,6 @@
1
1
  import { Extensions } from "../Enums";
2
2
  import { DropDownItem, DropDownMenuProps } from "../../DropDownMenu";
3
- import { ReactElement } from "react";
3
+ import { ReactElement, ReactNode } from "react";
4
4
  import { ButtonProps } from "../../Button";
5
5
  import { Editor } from "@tiptap/react";
6
6
  export interface BubbleMenuContentProps {
@@ -17,7 +17,7 @@ export type BubbleItem = {
17
17
  name: Extensions | string;
18
18
  icon?: React.FC<any>;
19
19
  type: "menu";
20
- label?: string | Element;
20
+ label?: ReactNode;
21
21
  items: BubbleMenuDropDownItem[];
22
22
  arrow?: boolean;
23
23
  isActive?: (editor: Editor) => boolean;
@@ -29,7 +29,7 @@ export type BubbleItem = {
29
29
  name: Extensions | string;
30
30
  icon?: React.FC<any>;
31
31
  type: "button";
32
- label?: string | Element;
32
+ label?: ReactNode;
33
33
  arrow?: boolean;
34
34
  isActive?: (editor: Editor) => boolean;
35
35
  buttonRender?: (props: any) => ReactElement;
@@ -1,12 +1,17 @@
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 { Extensions } from "../Enums";
4
- import { BoldIcon, ItalicIcon, UnderlineIcon, CaseSensitiveIcon, ListIcon, ListOrderedIcon, StrikethroughIcon, Heading1Icon, Heading2Icon, Heading3Icon, Heading4Icon, RemoveFormattingIcon, SquircleIcon, } from "lucide-react";
4
+ import { BoldIcon, CodeIcon, ItalicIcon, UnderlineIcon, CaseSensitiveIcon, ListIcon, ListOrderedIcon, SquareCodeIcon, StrikethroughIcon, Heading1Icon, Heading2Icon, Heading3Icon, Heading4Icon, HighlighterIcon, LinkIcon, PaletteIcon, RemoveFormattingIcon, SquircleIcon, } from "lucide-react";
5
5
  import { DropDownMenu, } from "../../DropDownMenu";
6
+ import { useEffect, useState } from "react";
6
7
  import { Button } from "../../Button";
7
8
  import TextColors from "../Enums/TextColors";
8
- const getMenuItems = (editor, customMenuItems, theme) => {
9
- var _a, _b, _c, _d, _e, _f, _g;
9
+ import HighlightColors from "../Enums/HighlightColors";
10
+ import LinkEditor from "./LinkEditor";
11
+ import { hasInlineCode, toggleInlineCode } from "../Utils/codeUtils";
12
+ import { hasSyntaxHighlightedCodeBlock, toggleCodeBlock, } from "../Utils/codeBlockUtils";
13
+ const getMenuItems = (editor, customMenuItems, theme, openLinkEditor) => {
14
+ var _a, _b, _c, _d, _e, _f, _g, _h;
10
15
  const node = (_c = (_b = (_a = editor === null || editor === void 0 ? void 0 : editor.state) === null || _a === void 0 ? void 0 : _a.selection) === null || _b === void 0 ? void 0 : _b.$from) === null || _c === void 0 ? void 0 : _c.parent;
11
16
  const pos = (_e = (_d = editor === null || editor === void 0 ? void 0 : editor.state) === null || _d === void 0 ? void 0 : _d.selection) === null || _e === void 0 ? void 0 : _e.$from;
12
17
  let withinUnorderedList = false;
@@ -22,6 +27,11 @@ const getMenuItems = (editor, customMenuItems, theme) => {
22
27
  }
23
28
  });
24
29
  const attrs = node === null || node === void 0 ? void 0 : node.attrs;
30
+ const supportsSyntaxCodeBlock = hasSyntaxHighlightedCodeBlock(editor);
31
+ const supportsInlineCode = hasInlineCode(editor);
32
+ const supportsColor = Boolean(editor.extensionManager.extensions.find((extension) => extension.name === "color"));
33
+ const supportsHighlight = Boolean(editor.extensionManager.extensions.find((extension) => extension.name === "highlight"));
34
+ const supportsLink = Boolean(editor.extensionManager.extensions.find((extension) => extension.name === "link"));
25
35
  let nodeTypeLabel = "Select Type";
26
36
  let nodeTypeIcon = null;
27
37
  if (withinOrderedList) {
@@ -36,7 +46,11 @@ const getMenuItems = (editor, customMenuItems, theme) => {
36
46
  nodeTypeLabel = "Text";
37
47
  nodeTypeIcon = _jsx(CaseSensitiveIcon, { size: 16 });
38
48
  }
39
- else if (((_g = node === null || node === void 0 ? void 0 : node.type) === null || _g === void 0 ? void 0 : _g.name) === "heading") {
49
+ else if (((_g = node === null || node === void 0 ? void 0 : node.type) === null || _g === void 0 ? void 0 : _g.name) === "codeBlock") {
50
+ nodeTypeLabel = "Code Block";
51
+ nodeTypeIcon = _jsx(SquareCodeIcon, { size: 16 });
52
+ }
53
+ else if (((_h = node === null || node === void 0 ? void 0 : node.type) === null || _h === void 0 ? void 0 : _h.name) === "heading") {
40
54
  const level = attrs === null || attrs === void 0 ? void 0 : attrs.level;
41
55
  nodeTypeLabel = `Heading ${level}`;
42
56
  nodeTypeIcon =
@@ -48,7 +62,6 @@ const getMenuItems = (editor, customMenuItems, theme) => {
48
62
  name: "node_type",
49
63
  label: nodeTypeLabel,
50
64
  type: "menu",
51
- arrow: true,
52
65
  buttonProps: {
53
66
  leftSection: nodeTypeIcon,
54
67
  style: { fontSize: 11, padding: "4px" },
@@ -60,13 +73,17 @@ const getMenuItems = (editor, customMenuItems, theme) => {
60
73
  data: {
61
74
  Icon: CaseSensitiveIcon,
62
75
  command: (editor) => {
63
- // remove ordered list
64
- editor
65
- .chain()
66
- .focus()
67
- .liftListItem("listItem")
68
- .setParagraph()
69
- .run();
76
+ if (editor.isActive("bulletList") ||
77
+ editor.isActive("orderedList")) {
78
+ editor
79
+ .chain()
80
+ .focus()
81
+ .liftListItem("listItem")
82
+ .setParagraph()
83
+ .run();
84
+ return;
85
+ }
86
+ editor.chain().focus().setParagraph().run();
70
87
  },
71
88
  },
72
89
  },
@@ -130,50 +147,107 @@ const getMenuItems = (editor, customMenuItems, theme) => {
130
147
  },
131
148
  },
132
149
  },
150
+ ...(supportsSyntaxCodeBlock
151
+ ? [
152
+ {
153
+ label: "Code Block",
154
+ value: "code_block",
155
+ data: {
156
+ Icon: SquareCodeIcon,
157
+ command: (editor) => {
158
+ toggleCodeBlock(editor);
159
+ },
160
+ },
161
+ },
162
+ ]
163
+ : []),
133
164
  ],
134
165
  dropDownProps: {
135
166
  renderOption: (item) => (_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 5 }, children: [_jsx(item.data.Icon, { size: 16 }), item.label] })),
136
167
  },
137
168
  },
138
- {
139
- name: "color",
140
- label: "Color",
141
- type: "menu",
142
- arrow: true,
143
- buttonProps: {
144
- // leftSection: nodeTypeIcon,
145
- style: { fontSize: 11, padding: "4px" },
146
- },
147
- items: [
169
+ ...(supportsColor
170
+ ? [
148
171
  {
149
- label: "Default",
150
- value: "default",
151
- onClick: () => {
152
- editor === null || editor === void 0 ? void 0 : editor.chain().focus().unsetColor().run();
172
+ name: "color",
173
+ label: _jsx(PaletteIcon, { size: 14 }),
174
+ type: "menu",
175
+ buttonProps: {
176
+ style: { padding: "1px 6px" },
177
+ },
178
+ items: [
179
+ {
180
+ label: "Default",
181
+ value: "default",
182
+ onClick: () => {
183
+ editor === null || editor === void 0 ? void 0 : editor.chain().focus().unsetColor().run();
184
+ },
185
+ },
186
+ ...Object.keys(TextColors).map((color) => {
187
+ const colorKey = color;
188
+ return {
189
+ label: color,
190
+ value: TextColors[colorKey],
191
+ onClick: () => {
192
+ editor === null || editor === void 0 ? void 0 : editor.chain().focus().setColor(TextColors[colorKey]).run();
193
+ },
194
+ };
195
+ }),
196
+ ],
197
+ dropDownProps: {
198
+ renderOption: (item) => (_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 5 }, children: [_jsx(SquircleIcon, { size: 12, color: item.value === "default"
199
+ ? theme.palette.text.primary
200
+ : item.value, style: {
201
+ backgroundColor: item.value === "default"
202
+ ? theme.palette.text.primary
203
+ : item.value,
204
+ borderRadius: "3px",
205
+ } }), item.label] })),
153
206
  },
154
207
  },
155
- ...Object.keys(TextColors).map((color) => {
156
- const colorKey = color;
157
- return {
158
- label: color,
159
- value: TextColors[colorKey],
160
- onClick: () => {
161
- editor === null || editor === void 0 ? void 0 : editor.chain().focus().setColor(TextColors[colorKey]).run();
208
+ ]
209
+ : []),
210
+ ...(supportsHighlight
211
+ ? [
212
+ {
213
+ name: Extensions.Highlight,
214
+ label: _jsx(HighlighterIcon, { size: 14 }),
215
+ type: "menu",
216
+ buttonProps: {
217
+ style: { padding: "1px 6px" },
218
+ },
219
+ items: [
220
+ {
221
+ label: "Default",
222
+ value: "default",
223
+ onClick: () => {
224
+ editor === null || editor === void 0 ? void 0 : editor.chain().focus().unsetHighlight().run();
225
+ },
162
226
  },
163
- };
164
- }),
165
- ],
166
- dropDownProps: {
167
- renderOption: (item) => (_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 5 }, children: [_jsx(SquircleIcon, { size: 12, color: item.value === "default"
168
- ? theme.palette.text.primary
169
- : item.value, style: {
170
- backgroundColor: item.value === "default"
171
- ? theme.palette.text.primary
172
- : item.value,
173
- borderRadius: "3px",
174
- } }), item.label] })),
175
- },
176
- },
227
+ ...Object.keys(HighlightColors).map((color) => {
228
+ const colorKey = color;
229
+ return {
230
+ label: color,
231
+ value: HighlightColors[colorKey],
232
+ onClick: () => {
233
+ editor === null || editor === void 0 ? void 0 : editor.chain().focus().setHighlight({ color: HighlightColors[colorKey] }).run();
234
+ },
235
+ };
236
+ }),
237
+ ],
238
+ dropDownProps: {
239
+ renderOption: (item) => (_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 5 }, children: [_jsx(SquircleIcon, { size: 12, color: item.value === "default"
240
+ ? theme.palette.text.primary
241
+ : item.value, style: {
242
+ backgroundColor: item.value === "default"
243
+ ? "transparent"
244
+ : item.value,
245
+ borderRadius: "3px",
246
+ } }), item.label] })),
247
+ },
248
+ },
249
+ ]
250
+ : []),
177
251
  {
178
252
  name: Extensions.Bold,
179
253
  icon: BoldIcon,
@@ -210,6 +284,45 @@ const getMenuItems = (editor, customMenuItems, theme) => {
210
284
  editor.chain().focus().toggleStrike().run();
211
285
  },
212
286
  },
287
+ ...(supportsLink
288
+ ? [
289
+ {
290
+ name: Extensions.Link,
291
+ icon: LinkIcon,
292
+ type: "button",
293
+ isActive: (editor) => editor.isActive("link"),
294
+ onClick: () => {
295
+ openLinkEditor();
296
+ },
297
+ },
298
+ ]
299
+ : []),
300
+ ...(supportsInlineCode
301
+ ? [
302
+ {
303
+ name: Extensions.Code,
304
+ icon: CodeIcon,
305
+ type: "button",
306
+ isActive: (editor) => editor.isActive("code"),
307
+ onClick: (editor) => {
308
+ toggleInlineCode(editor);
309
+ },
310
+ },
311
+ ]
312
+ : []),
313
+ ...(supportsSyntaxCodeBlock
314
+ ? [
315
+ {
316
+ name: Extensions.CodeBlock,
317
+ icon: SquareCodeIcon,
318
+ type: "button",
319
+ isActive: (editor) => editor.isActive("codeBlock"),
320
+ onClick: (editor) => {
321
+ toggleCodeBlock(editor);
322
+ },
323
+ },
324
+ ]
325
+ : []),
213
326
  {
214
327
  name: Extensions.ClearFormatting,
215
328
  icon: RemoveFormattingIcon,
@@ -226,7 +339,7 @@ const BubbleMenuContent = styled.div `
226
339
  justify-content: space-between;
227
340
  align-items: center;
228
341
  padding: 2px;
229
- gap: 2px;
342
+ gap: 4px;
230
343
 
231
344
  color: ${({ theme }) => theme.palette.text.primary};
232
345
  background-color: ${({ theme }) => theme.palette.input.background};
@@ -242,6 +355,11 @@ const BubbleMenuContent = styled.div `
242
355
  transform: scale(0.25); /* Start at half size */
243
356
  animation: fadeInEffect 90ms forwards;
244
357
 
358
+ button {
359
+ min-width: 28px;
360
+ min-height: 28px;
361
+ }
362
+
245
363
  /* Animation to handle the fade in */
246
364
  @keyframes fadeInEffect {
247
365
  0% {
@@ -258,7 +376,8 @@ const BubbleItemButton = styled(Button) `
258
376
  font-size: 0.5rem;
259
377
  font-weight: 500;
260
378
  padding: 4px;
261
- height: auto;
379
+ height: 28px;
380
+ width: 28px;
262
381
 
263
382
  &.is-active {
264
383
  opacity: 1;
@@ -269,11 +388,31 @@ const BubbleItemButton = styled(Button) `
269
388
  background-color: ${({ theme }) => theme.palette.action.hover};
270
389
  }
271
390
  `;
391
+ const CodeBlockBubbleTools = ({ editor, theme, }) => {
392
+ const nodeTypeMenu = getMenuItems(editor, [], theme, () => undefined).find((item) => item.name === "node_type");
393
+ return (_jsx(_Fragment, { children: (nodeTypeMenu === null || nodeTypeMenu === void 0 ? void 0 : nodeTypeMenu.type) === "menu" && (_jsx(DropDownMenu, Object.assign({ data: nodeTypeMenu.items, size: "xs", arrow: nodeTypeMenu.arrow, buttonProps: nodeTypeMenu.buttonProps, variant: "subtle", buttonRender: nodeTypeMenu.buttonRender, onItemSelect: (item) => { var _a, _b; return (_b = (_a = item === null || item === void 0 ? void 0 : item.data) === null || _a === void 0 ? void 0 : _a.command) === null || _b === void 0 ? void 0 : _b.call(_a, editor, ""); }, dropDownProps: {
394
+ style: { width: 135 },
395
+ } }, nodeTypeMenu.dropDownProps, { children: nodeTypeMenu.icon
396
+ ? (_jsx(nodeTypeMenu.icon, { size: 14 }))
397
+ : (nodeTypeMenu.label || nodeTypeMenu.name) }))) }));
398
+ };
272
399
  const BubbleMenu = ({ className, editor, customMenuItems = [], }) => {
273
400
  const theme = useTheme();
401
+ const [linkEditorOpen, setLinkEditorOpen] = useState(false);
274
402
  const { from, to } = editor.state.selection;
275
403
  const selectedText = editor.state.doc.textBetween(from, to, "\n", "\n");
276
- return (_jsx(BubbleMenuContent, { className: className, children: getMenuItems(editor, customMenuItems, theme).map((item) => {
404
+ const isLinkSelection = editor.isActive("link");
405
+ const isCodeBlockSelection = editor.isActive("codeBlock") && hasSyntaxHighlightedCodeBlock(editor);
406
+ useEffect(() => {
407
+ setLinkEditorOpen(false);
408
+ }, [from, to]);
409
+ if (isLinkSelection || linkEditorOpen) {
410
+ return (_jsx(BubbleMenuContent, { className: className, children: _jsx(LinkEditor, { editor: editor, autoFocus: true, onClose: () => setLinkEditorOpen(false) }) }));
411
+ }
412
+ if (isCodeBlockSelection) {
413
+ return (_jsx(BubbleMenuContent, { className: className, children: _jsx(CodeBlockBubbleTools, { editor: editor, theme: theme }) }));
414
+ }
415
+ return (_jsx(BubbleMenuContent, { className: className, children: getMenuItems(editor, customMenuItems, theme, () => setLinkEditorOpen(true)).map((item) => {
277
416
  var _a;
278
417
  if (item.type === "button") {
279
418
  const isActive = (_a = item.isActive) === null || _a === void 0 ? void 0 : _a.call(item, editor);
@@ -0,0 +1,18 @@
1
+ export declare const CodeBlockBaseButton: import("styled-components/dist/types").IStyledComponentBase<"web", import("styled-components").FastOmit<import("react").ButtonHTMLAttributes<HTMLButtonElement> & {
2
+ ref?: import("react").RefObject<HTMLButtonElement>;
3
+ children?: import("react").ReactNode | string;
4
+ className?: string;
5
+ loading?: boolean;
6
+ leftSection?: import("react").ReactNode;
7
+ rightSection?: import("react").ReactNode;
8
+ href?: string | null;
9
+ download?: string | null;
10
+ fullWidth?: boolean;
11
+ size?: import("../../core").Size;
12
+ variant?: import("../../core").Variant;
13
+ color?: import("../../Button").ButtonColor;
14
+ disabled?: boolean;
15
+ selected?: boolean;
16
+ justify?: "start" | "center" | "end";
17
+ onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
18
+ }, never>> & string & Omit<import("react").FC<import("../../Button").ButtonProps>, keyof import("react").Component<any, {}, any>>;
@@ -0,0 +1,6 @@
1
+ import styled from "styled-components";
2
+ import { Button } from "../../Button";
3
+ export const CodeBlockBaseButton = styled(Button) `
4
+ padding: 5px;
5
+ background-color: ${({ theme }) => theme.palette.background.paper};
6
+ `;
@@ -0,0 +1,9 @@
1
+ import { Editor } from "@tiptap/react";
2
+ type CodeBlockCopyButtonProps = {
3
+ className?: string;
4
+ editor?: Editor | null;
5
+ text?: string;
6
+ size?: "xs" | "sm";
7
+ };
8
+ declare const CodeBlockCopyButton: ({ className, editor, text, size, }: CodeBlockCopyButtonProps) => import("react/jsx-runtime").JSX.Element;
9
+ export default CodeBlockCopyButton;