@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
@@ -56,11 +56,18 @@ const buildGroupedDisplayList = (items) => {
56
56
  const ListViewPort = styled.div.attrs({ className: "ListViewPort" }) `
57
57
  display: flex;
58
58
  flex-direction: column;
59
+ flex: 1 1 auto;
60
+ min-height: 0;
59
61
  width: 100%;
60
62
  `;
63
+ const MenuItemListRoot = styled.div `
64
+ display: flex;
65
+ flex-direction: column;
66
+ height: 100%;
67
+ min-height: 0;
68
+ `;
61
69
  const ListScroller = styled.div `
62
70
  scrollbar-color: ${({ theme }) => `${theme.scrollbar.thumb} ${theme.scrollbar.track}`};
63
- scrollbar-gutter: stable;
64
71
  scrollbar-width: thin;
65
72
 
66
73
  &::-webkit-scrollbar {
@@ -234,16 +241,6 @@ export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, dy
234
241
  list.addEventListener("scroll", handleOnScroll);
235
242
  return () => list.removeEventListener("scroll", handleOnScroll);
236
243
  }, [dynamicOptionHeight, handleOnScroll, isLoading, renderOption]);
237
- useLayoutEffect(() => {
238
- var _a;
239
- if (targetElm.current) {
240
- const viewPortDimensions = (_a = targetElm.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect();
241
- setViewPortDimensions({
242
- width: viewPortDimensions.width,
243
- height: viewPortDimensions.height,
244
- });
245
- }
246
- }, [targetElm.current, isLoading]);
247
244
  const overscanCount = 10;
248
245
  const sizeTokens = getControlSizeTokens(size || "sm");
249
246
  const itemHeight = sizeTokens.menuRowHeight;
@@ -267,6 +264,29 @@ export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, dy
267
264
  ? estimatedHeight
268
265
  : 200;
269
266
  const width = "100%";
267
+ useLayoutEffect(() => {
268
+ const target = targetElm.current;
269
+ if (!target)
270
+ return;
271
+ const updateDimensions = () => {
272
+ const nextDimensions = target.getBoundingClientRect();
273
+ setViewPortDimensions((currentDimensions) => {
274
+ const width = Math.ceil(nextDimensions.width);
275
+ const height = Math.floor(nextDimensions.height);
276
+ if (currentDimensions.width === width &&
277
+ currentDimensions.height === height) {
278
+ return currentDimensions;
279
+ }
280
+ return { width, height };
281
+ });
282
+ };
283
+ updateDimensions();
284
+ if (typeof ResizeObserver === "undefined")
285
+ return;
286
+ const observer = new ResizeObserver(updateDimensions);
287
+ observer.observe(target);
288
+ return () => observer.disconnect();
289
+ }, [displayItemsKey, isLoading]);
270
290
  const setItemSize = useCallback((index, measuredSize) => {
271
291
  var _a;
272
292
  if (itemSizeMap.current[index] === measuredSize)
@@ -335,7 +355,7 @@ export const MenuItemList = ({ menuItems, searchable, onSearch, manualSearch, dy
335
355
  (item === null || item === void 0 ? void 0 : item.label) ||
336
356
  (typeof item === "string" || typeof item === "number" ? item : null) }, index));
337
357
  };
338
- return (_jsxs("div", { children: [searchable && (_jsx(SearchInput, { variant: "outlined", size: size, placeholder: "Search", defaultValue: searchValue, onChange: (e) => {
358
+ return (_jsxs(MenuItemListRoot, { children: [searchable && (_jsx(SearchInput, { variant: "outlined", size: size, placeholder: "Search", defaultValue: searchValue, onChange: (e) => {
339
359
  if (!manualSearch) {
340
360
  handleSearch(e);
341
361
  }
@@ -5,5 +5,6 @@ export const StyledInnerItemContainer = styled.div.attrs({
5
5
  display: flex;
6
6
  flex-direction: column;
7
7
  flex: 1 1 auto;
8
+ min-height: 0;
8
9
  overflow: hidden;
9
10
  `;
@@ -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,14 +1,11 @@
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
- export interface BubbleMenuProps {
6
+ export interface BubbleMenuContentProps {
7
7
  className?: string;
8
8
  editor: Editor;
9
- rect: DOMRect;
10
- open: boolean;
11
- onOpen?: (element: HTMLElement) => void;
12
9
  customMenuItems?: BubbleItem[];
13
10
  }
14
11
  interface BubbleMenuDropDownItem extends DropDownItem {
@@ -20,7 +17,7 @@ export type BubbleItem = {
20
17
  name: Extensions | string;
21
18
  icon?: React.FC<any>;
22
19
  type: "menu";
23
- label?: string | Element;
20
+ label?: ReactNode;
24
21
  items: BubbleMenuDropDownItem[];
25
22
  arrow?: boolean;
26
23
  isActive?: (editor: Editor) => boolean;
@@ -32,12 +29,15 @@ export type BubbleItem = {
32
29
  name: Extensions | string;
33
30
  icon?: React.FC<any>;
34
31
  type: "button";
35
- label?: string | Element;
32
+ label?: ReactNode;
36
33
  arrow?: boolean;
37
34
  isActive?: (editor: Editor) => boolean;
38
35
  buttonRender?: (props: any) => ReactElement;
39
36
  buttonProps?: Partial<ButtonProps>;
40
37
  onClick?: (editor: Editor) => void;
41
38
  };
42
- declare const BubbleMenu: React.FC<BubbleMenuProps>;
39
+ export type BubbleMenuOptions = {
40
+ customMenuItems?: BubbleItem[];
41
+ };
42
+ declare const BubbleMenu: React.FC<BubbleMenuContentProps>;
43
43
  export default BubbleMenu;
@@ -1,14 +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 { FloatingPortal, useFloating } from "@floating-ui/react";
7
- import { useEffect, useRef } from "react";
6
+ import { useEffect, useState } from "react";
8
7
  import { Button } from "../../Button";
9
8
  import TextColors from "../Enums/TextColors";
10
- const getMenuItems = (editor, customMenuItems, theme) => {
11
- 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;
12
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;
13
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;
14
17
  let withinUnorderedList = false;
@@ -24,6 +27,11 @@ const getMenuItems = (editor, customMenuItems, theme) => {
24
27
  }
25
28
  });
26
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"));
27
35
  let nodeTypeLabel = "Select Type";
28
36
  let nodeTypeIcon = null;
29
37
  if (withinOrderedList) {
@@ -38,7 +46,11 @@ const getMenuItems = (editor, customMenuItems, theme) => {
38
46
  nodeTypeLabel = "Text";
39
47
  nodeTypeIcon = _jsx(CaseSensitiveIcon, { size: 16 });
40
48
  }
41
- 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") {
42
54
  const level = attrs === null || attrs === void 0 ? void 0 : attrs.level;
43
55
  nodeTypeLabel = `Heading ${level}`;
44
56
  nodeTypeIcon =
@@ -50,7 +62,6 @@ const getMenuItems = (editor, customMenuItems, theme) => {
50
62
  name: "node_type",
51
63
  label: nodeTypeLabel,
52
64
  type: "menu",
53
- arrow: true,
54
65
  buttonProps: {
55
66
  leftSection: nodeTypeIcon,
56
67
  style: { fontSize: 11, padding: "4px" },
@@ -62,13 +73,17 @@ const getMenuItems = (editor, customMenuItems, theme) => {
62
73
  data: {
63
74
  Icon: CaseSensitiveIcon,
64
75
  command: (editor) => {
65
- // remove ordered list
66
- editor
67
- .chain()
68
- .focus()
69
- .liftListItem("listItem")
70
- .setParagraph()
71
- .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();
72
87
  },
73
88
  },
74
89
  },
@@ -132,50 +147,120 @@ const getMenuItems = (editor, customMenuItems, theme) => {
132
147
  },
133
148
  },
134
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
+ : []),
135
164
  ],
136
165
  dropDownProps: {
137
166
  renderOption: (item) => (_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 5 }, children: [_jsx(item.data.Icon, { size: 16 }), item.label] })),
138
167
  },
139
168
  },
140
- {
141
- name: "color",
142
- label: "Color",
143
- type: "menu",
144
- arrow: true,
145
- buttonProps: {
146
- // leftSection: nodeTypeIcon,
147
- style: { fontSize: 11, padding: "4px" },
148
- },
149
- items: [
169
+ ...(supportsColor
170
+ ? [
150
171
  {
151
- label: "Default",
152
- value: "default",
153
- onClick: () => {
154
- 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: { fontSize: 11, padding: "4px" },
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] })),
155
206
  },
156
207
  },
157
- ...Object.keys(TextColors).map((color) => {
158
- const colorKey = color;
159
- return {
160
- label: color,
161
- value: TextColors[colorKey],
162
- onClick: () => {
163
- 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: { fontSize: 11, padding: "4px" },
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
+ },
164
226
  },
165
- };
166
- }),
167
- ],
168
- dropDownProps: {
169
- renderOption: (item) => (_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 5 }, children: [_jsx(SquircleIcon, { size: 12, color: item.value === "default"
170
- ? theme.palette.text.primary
171
- : item.value, style: {
172
- backgroundColor: item.value === "default"
173
- ? theme.palette.text.primary
174
- : item.value,
175
- borderRadius: "3px",
176
- } }), item.label] })),
177
- },
178
- },
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
+ : []),
251
+ ...(supportsLink
252
+ ? [
253
+ {
254
+ name: Extensions.Link,
255
+ icon: LinkIcon,
256
+ type: "button",
257
+ isActive: (editor) => editor.isActive("link"),
258
+ onClick: () => {
259
+ openLinkEditor();
260
+ },
261
+ },
262
+ ]
263
+ : []),
179
264
  {
180
265
  name: Extensions.Bold,
181
266
  icon: BoldIcon,
@@ -212,6 +297,32 @@ const getMenuItems = (editor, customMenuItems, theme) => {
212
297
  editor.chain().focus().toggleStrike().run();
213
298
  },
214
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
+ : []),
215
326
  {
216
327
  name: Extensions.ClearFormatting,
217
328
  icon: RemoveFormattingIcon,
@@ -224,12 +335,11 @@ const getMenuItems = (editor, customMenuItems, theme) => {
224
335
  ];
225
336
  };
226
337
  const BubbleMenuContent = styled.div `
227
- position: fixed;
228
338
  display: flex;
229
339
  justify-content: space-between;
230
340
  align-items: center;
231
341
  padding: 2px;
232
- gap: 2px;
342
+ gap: 4px;
233
343
 
234
344
  color: ${({ theme }) => theme.palette.text.primary};
235
345
  background-color: ${({ theme }) => theme.palette.input.background};
@@ -272,51 +382,43 @@ const BubbleItemButton = styled(Button) `
272
382
  background-color: ${({ theme }) => theme.palette.action.hover};
273
383
  }
274
384
  `;
275
- const BubbleMenu = ({ editor, rect, open, onOpen, customMenuItems = [], }) => {
276
- var _a;
277
- const menuRef = useRef(null);
278
- const { refs, elements } = useFloating();
385
+ const CodeBlockBubbleTools = ({ editor, theme, }) => {
386
+ const nodeTypeMenu = getMenuItems(editor, [], theme, () => undefined).find((item) => item.name === "node_type");
387
+ 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: {
388
+ style: { width: 135 },
389
+ } }, nodeTypeMenu.dropDownProps, { children: nodeTypeMenu.icon
390
+ ? (_jsx(nodeTypeMenu.icon, { size: 14 }))
391
+ : (nodeTypeMenu.label || nodeTypeMenu.name) }))) }));
392
+ };
393
+ const BubbleMenu = ({ className, editor, customMenuItems = [], }) => {
279
394
  const theme = useTheme();
280
- useEffect(() => {
281
- if (open && onOpen) {
282
- onOpen(elements.floating);
283
- }
284
- }, [open, onOpen, elements.floating]);
285
- const elementWidth = ((_a = elements.floating) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 0;
395
+ const [linkEditorOpen, setLinkEditorOpen] = useState(false);
286
396
  const { from, to } = editor.state.selection;
287
397
  const selectedText = editor.state.doc.textBetween(from, to, "\n", "\n");
288
- let top = (rect === null || rect === void 0 ? void 0 : rect.top) ? rect.top - 50 : 0;
289
- if (top < 10) {
290
- top = 10; // add some padding
291
- }
292
- let left = (rect === null || rect === void 0 ? void 0 : rect.left) ? rect.left + rect.width / 2 - elementWidth / 2 : 0;
293
- if (left < 10) {
294
- left = 10; // add some padding
398
+ const isLinkSelection = editor.isActive("link");
399
+ const isCodeBlockSelection = editor.isActive("codeBlock") && hasSyntaxHighlightedCodeBlock(editor);
400
+ useEffect(() => {
401
+ setLinkEditorOpen(false);
402
+ }, [from, to]);
403
+ if (isLinkSelection || linkEditorOpen) {
404
+ return (_jsx(BubbleMenuContent, { className: className, children: _jsx(LinkEditor, { editor: editor, autoFocus: true, onClose: () => setLinkEditorOpen(false) }) }));
295
405
  }
296
- // Check if the menu is overflowing on the right
297
- const rightOverflow = left + elementWidth - window.innerWidth;
298
- if (rightOverflow > -10) {
299
- left -= rightOverflow + 10; // add some padding
406
+ if (isCodeBlockSelection) {
407
+ return (_jsx(BubbleMenuContent, { className: className, children: _jsx(CodeBlockBubbleTools, { editor: editor, theme: theme }) }));
300
408
  }
301
- return (_jsx(FloatingPortal, { preserveTabOrder: true, children: open && (_jsx(BubbleMenuContent, { ref: (ref) => {
302
- refs.setFloating(ref);
303
- menuRef.current = ref;
304
- }, style: {
305
- top,
306
- left,
307
- }, children: getMenuItems(editor, customMenuItems, theme).map((item) => {
308
- var _a;
309
- if (item.type === "button") {
310
- const isActive = (_a = item.isActive) === null || _a === void 0 ? void 0 : _a.call(item, editor);
311
- return (_jsx(BubbleItemButton, { variant: "subtle", onClick: () => { var _a; return (_a = item === null || item === void 0 ? void 0 : item.onClick) === null || _a === void 0 ? void 0 : _a.call(item, editor); }, color: isActive ? "primary" : undefined, selected: isActive, children: item.icon && _jsx(item.icon, { size: 14 }) }, item.name));
312
- }
313
- if (item.type === "menu") {
314
- return (_jsx(DropDownMenu, Object.assign({ data: item.items, size: "xs", arrow: item.arrow, buttonProps: item.buttonProps, variant: "subtle", buttonRender: item.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, selectedText); }, dropDownProps: {
315
- style: { width: 135 },
316
- } }, item.dropDownProps, { children: item.icon
317
- ? (_jsx(item.icon, { size: 14 }))
318
- : (item.label || item.name) }), item.name));
319
- }
320
- }) })) }));
409
+ return (_jsx(BubbleMenuContent, { className: className, children: getMenuItems(editor, customMenuItems, theme, () => setLinkEditorOpen(true)).map((item) => {
410
+ var _a;
411
+ if (item.type === "button") {
412
+ const isActive = (_a = item.isActive) === null || _a === void 0 ? void 0 : _a.call(item, editor);
413
+ return (_jsx(BubbleItemButton, { variant: "subtle", onClick: () => { var _a; return (_a = item === null || item === void 0 ? void 0 : item.onClick) === null || _a === void 0 ? void 0 : _a.call(item, editor); }, color: isActive ? "primary" : undefined, selected: isActive, children: item.icon && _jsx(item.icon, { size: 14 }) }, item.name));
414
+ }
415
+ if (item.type === "menu") {
416
+ return (_jsx(DropDownMenu, Object.assign({ data: item.items, size: "xs", arrow: item.arrow, buttonProps: item.buttonProps, variant: "subtle", buttonRender: item.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, selectedText); }, dropDownProps: {
417
+ style: { width: 135 },
418
+ } }, item.dropDownProps, { children: item.icon
419
+ ? (_jsx(item.icon, { size: 14 }))
420
+ : (item.label || item.name) }), item.name));
421
+ }
422
+ }) }));
321
423
  };
322
424
  export default BubbleMenu;
@@ -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;
@@ -0,0 +1,42 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { jsx as _jsx } from "react/jsx-runtime";
11
+ import { useEffect, useState } from "react";
12
+ import { CheckIcon, CopyIcon } from "lucide-react";
13
+ import { copyCodeBlockText, getActiveCodeBlockText, } from "../Utils/codeBlockUtils";
14
+ import { CodeBlockBaseButton } from "./CodeBlockBaseButton";
15
+ const CodeBlockCopyButton = ({ className, editor, text, size = "xs", }) => {
16
+ const [copied, setCopied] = useState(false);
17
+ const [copyFailed, setCopyFailed] = useState(false);
18
+ const code = text !== null && text !== void 0 ? text : getActiveCodeBlockText(editor || null);
19
+ useEffect(() => {
20
+ if (!copied && !copyFailed)
21
+ return;
22
+ const timeout = window.setTimeout(() => {
23
+ setCopied(false);
24
+ setCopyFailed(false);
25
+ }, 1400);
26
+ return () => window.clearTimeout(timeout);
27
+ }, [copied, copyFailed]);
28
+ return (_jsx(CodeBlockBaseButton, { className: className, size: size, variant: "outlined", title: copyFailed ? "Unable to copy" : copied ? "Copied" : "Copy code", "aria-label": copyFailed ? "Unable to copy code" : copied ? "Copied" : "Copy code", disabled: !code, onClick: (event) => __awaiter(void 0, void 0, void 0, function* () {
29
+ event.preventDefault();
30
+ event.stopPropagation();
31
+ try {
32
+ yield copyCodeBlockText(code);
33
+ setCopied(true);
34
+ setCopyFailed(false);
35
+ }
36
+ catch (_a) {
37
+ setCopied(false);
38
+ setCopyFailed(true);
39
+ }
40
+ }), children: copied ? _jsx(CheckIcon, { size: 14 }) : _jsx(CopyIcon, { size: 14 }) }));
41
+ };
42
+ export default CodeBlockCopyButton;
@@ -0,0 +1,10 @@
1
+ import { Editor } from "@tiptap/react";
2
+ type CodeBlockFormatButtonProps = {
3
+ className?: string;
4
+ editor?: Editor | null;
5
+ language?: string;
6
+ onFormat?: () => Promise<void>;
7
+ size?: "xs" | "sm";
8
+ };
9
+ declare const CodeBlockFormatButton: ({ className, editor, language, onFormat, size, }: CodeBlockFormatButtonProps) => import("react/jsx-runtime").JSX.Element;
10
+ export default CodeBlockFormatButton;