@monolith-forensics/monolith-ui 1.3.2 → 1.3.3
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.
- package/dist/RichTextEditor/Enums/Controls.d.ts +2 -1
- package/dist/RichTextEditor/Enums/Controls.js +1 -0
- package/dist/RichTextEditor/Enums/SlashCommands.d.ts +1 -0
- package/dist/RichTextEditor/Enums/SlashCommands.js +1 -0
- package/dist/RichTextEditor/Extensions/CustomTableView.d.ts +22 -0
- package/dist/RichTextEditor/Extensions/CustomTableView.js +137 -0
- package/dist/RichTextEditor/Extensions/SlashCommandList.d.ts +6 -4
- package/dist/RichTextEditor/Extensions/SlashCommandList.js +15 -1
- package/dist/RichTextEditor/Extensions/getSlashCommand.d.ts +12 -1
- package/dist/RichTextEditor/Extensions/getSlashCommand.js +10 -1
- package/dist/RichTextEditor/Extensions/getTiptapExtensions.js +7 -19
- package/dist/RichTextEditor/Plugins/UploadImagesPlugin.js +2 -1
- package/dist/RichTextEditor/RichTextEditor.js +102 -3
- package/dist/RichTextEditor/Toolbar/Toolbar.d.ts +2 -2
- package/dist/RichTextEditor/Toolbar/Toolbar.js +92 -13
- package/dist/RichTextEditor/Toolbar/useToolbarState.d.ts +30 -0
- package/dist/RichTextEditor/Toolbar/useToolbarState.js +44 -0
- package/package.json +18 -17
|
@@ -7,6 +7,7 @@ export var SlashCommands;
|
|
|
7
7
|
SlashCommands["Heading4"] = "Heading 4";
|
|
8
8
|
SlashCommands["BulletList"] = "Bullet List";
|
|
9
9
|
SlashCommands["NumberedList"] = "Numbered List";
|
|
10
|
+
SlashCommands["Table"] = "Table";
|
|
10
11
|
SlashCommands["CurrentDate"] = "Current Date";
|
|
11
12
|
SlashCommands["CurrentTimestamp"] = "Current Timestamp";
|
|
12
13
|
SlashCommands["Image"] = "Image";
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { TableView as DefaultTableView } from "@tiptap/extension-table";
|
|
2
|
+
import { EditorView } from "@tiptap/pm/view";
|
|
3
|
+
import type { Node as PMNode } from "prosemirror-model";
|
|
4
|
+
export declare class CustomTableView extends DefaultTableView {
|
|
5
|
+
private addColumnBtn;
|
|
6
|
+
private tableMenuBtn;
|
|
7
|
+
private tableMenu;
|
|
8
|
+
private isOpen;
|
|
9
|
+
private selectionHandler;
|
|
10
|
+
private clickOutsideHandler;
|
|
11
|
+
private view;
|
|
12
|
+
constructor(node: PMNode, cellMinWidth: number, view: EditorView);
|
|
13
|
+
update(node: PMNode): boolean;
|
|
14
|
+
destroy(): void;
|
|
15
|
+
private renderTableMenu;
|
|
16
|
+
private renderAddColumnBtn;
|
|
17
|
+
private updateColumnButtonVisibility;
|
|
18
|
+
private updateTableMenuVisibility;
|
|
19
|
+
private toggleMenu;
|
|
20
|
+
private openMenu;
|
|
21
|
+
private closeMenu;
|
|
22
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { TableView as DefaultTableView } from "@tiptap/extension-table";
|
|
2
|
+
import { addColumnAfter, } from "prosemirror-tables";
|
|
3
|
+
/** Walk up from $pos to find the nearest ancestor table. */
|
|
4
|
+
function findTable(state) {
|
|
5
|
+
const { $from } = state.selection;
|
|
6
|
+
return findAncestorOfType($from, "table");
|
|
7
|
+
}
|
|
8
|
+
/** Generic ancestor finder by node.type.name */
|
|
9
|
+
function findAncestorOfType($pos, typeName) {
|
|
10
|
+
var _a;
|
|
11
|
+
for (let depth = $pos.depth; depth >= 0; depth--) {
|
|
12
|
+
const node = $pos.node(depth);
|
|
13
|
+
if (((_a = node.type) === null || _a === void 0 ? void 0 : _a.name) === typeName) {
|
|
14
|
+
const pos = depth === 0 ? 0 : $pos.before(depth);
|
|
15
|
+
return { node, pos };
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
export class CustomTableView extends DefaultTableView {
|
|
21
|
+
// NOTE: signature has NO getPos
|
|
22
|
+
constructor(node, cellMinWidth, view) {
|
|
23
|
+
// keep default resizing/DOM from the base TableView
|
|
24
|
+
super(node, cellMinWidth);
|
|
25
|
+
this.isOpen = true;
|
|
26
|
+
this.view = view;
|
|
27
|
+
this.addColumnBtn = null;
|
|
28
|
+
this.tableMenuBtn = null;
|
|
29
|
+
this.tableMenu = null;
|
|
30
|
+
this.selectionHandler = null;
|
|
31
|
+
this.clickOutsideHandler = () => { };
|
|
32
|
+
// this.renderTableMenu();
|
|
33
|
+
this.renderAddColumnBtn();
|
|
34
|
+
}
|
|
35
|
+
update(node) {
|
|
36
|
+
const ok = super.update(node);
|
|
37
|
+
if (ok)
|
|
38
|
+
this.updateColumnButtonVisibility();
|
|
39
|
+
// if (ok) this.updateTableMenuVisibility();
|
|
40
|
+
return ok;
|
|
41
|
+
}
|
|
42
|
+
destroy() {
|
|
43
|
+
if (this.selectionHandler) {
|
|
44
|
+
this.view.dom.ownerDocument.removeEventListener("selectionchange", this.selectionHandler);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
renderTableMenu() {
|
|
48
|
+
var _a;
|
|
49
|
+
const tableMenuContainer = document.createElement("div");
|
|
50
|
+
tableMenuContainer.className = "tiptap-table-menu-container";
|
|
51
|
+
this.tableMenuBtn = document.createElement("div");
|
|
52
|
+
this.tableMenuBtn.textContent = "⋮";
|
|
53
|
+
this.tableMenuBtn.title = "Table menu";
|
|
54
|
+
this.tableMenuBtn.className = "tiptap-table-menu-btn";
|
|
55
|
+
tableMenuContainer.appendChild(this.tableMenuBtn);
|
|
56
|
+
this.tableMenu = document.createElement("div");
|
|
57
|
+
this.tableMenu.className = "tiptap-table-menu";
|
|
58
|
+
this.tableMenu.style.display = this.isOpen ? "block" : "none";
|
|
59
|
+
tableMenuContainer.appendChild(this.tableMenu);
|
|
60
|
+
this.tableMenuBtn.addEventListener("mousedown", (e) => e.preventDefault());
|
|
61
|
+
this.tableMenuBtn.addEventListener("click", () => {
|
|
62
|
+
this.toggleMenu();
|
|
63
|
+
});
|
|
64
|
+
(_a = this.table.parentElement) === null || _a === void 0 ? void 0 : _a.appendChild(tableMenuContainer);
|
|
65
|
+
// Visibility & lifecycle
|
|
66
|
+
this.selectionHandler = () => this.updateTableMenuVisibility();
|
|
67
|
+
this.view.dom.ownerDocument.addEventListener("selectionchange", this.selectionHandler);
|
|
68
|
+
this.updateTableMenuVisibility();
|
|
69
|
+
this.clickOutsideHandler = (e) => {
|
|
70
|
+
var _a;
|
|
71
|
+
if (!this.isOpen)
|
|
72
|
+
return;
|
|
73
|
+
const target = e.target;
|
|
74
|
+
if (!((_a = this.tableMenu) === null || _a === void 0 ? void 0 : _a.contains(target)) && target !== this.tableMenuBtn) {
|
|
75
|
+
this.closeMenu();
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
this.view.dom.ownerDocument.addEventListener("mousedown", this.clickOutsideHandler);
|
|
79
|
+
}
|
|
80
|
+
renderAddColumnBtn() {
|
|
81
|
+
var _a;
|
|
82
|
+
// Create the left-side button
|
|
83
|
+
this.addColumnBtn = document.createElement("div");
|
|
84
|
+
this.addColumnBtn.textContent = "+";
|
|
85
|
+
this.addColumnBtn.title = "Add column";
|
|
86
|
+
this.addColumnBtn.className = "tiptap-table-addcol-btn";
|
|
87
|
+
this.addColumnBtn.addEventListener("mousedown", (e) => e.preventDefault());
|
|
88
|
+
this.addColumnBtn.addEventListener("click", () => {
|
|
89
|
+
addColumnAfter(this.view.state, this.view.dispatch);
|
|
90
|
+
this.view.focus();
|
|
91
|
+
});
|
|
92
|
+
// The default TableView sets up a wrapper div at this.dom
|
|
93
|
+
if (getComputedStyle(this.dom).position === "static") {
|
|
94
|
+
this.dom.style.position = "relative";
|
|
95
|
+
}
|
|
96
|
+
(_a = this.table.parentElement) === null || _a === void 0 ? void 0 : _a.appendChild(this.addColumnBtn);
|
|
97
|
+
// Toggle visibility on selection changes
|
|
98
|
+
const doc = this.view.dom.ownerDocument;
|
|
99
|
+
this.selectionHandler = () => this.updateColumnButtonVisibility();
|
|
100
|
+
doc.addEventListener("selectionchange", this.selectionHandler);
|
|
101
|
+
this.updateColumnButtonVisibility();
|
|
102
|
+
}
|
|
103
|
+
updateColumnButtonVisibility() {
|
|
104
|
+
const found = findTable(this.view.state);
|
|
105
|
+
const isInsideThisTable = !!found && found.node === this.node;
|
|
106
|
+
if (this.addColumnBtn) {
|
|
107
|
+
this.addColumnBtn.style.display = isInsideThisTable ? "flex" : "none";
|
|
108
|
+
}
|
|
109
|
+
if (this.tableMenuBtn) {
|
|
110
|
+
this.tableMenuBtn.style.display = isInsideThisTable ? "flex" : "none";
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
updateTableMenuVisibility() {
|
|
114
|
+
const found = findTable(this.view.state);
|
|
115
|
+
const inside = !!found && found.node === this.node;
|
|
116
|
+
if (!inside)
|
|
117
|
+
this.closeMenu();
|
|
118
|
+
// Optional: update position relative to table (e.g., snap left/top)
|
|
119
|
+
// You can also use the selected cell rect for context-sensitive placement.
|
|
120
|
+
}
|
|
121
|
+
toggleMenu() {
|
|
122
|
+
this.isOpen ? this.closeMenu() : this.openMenu();
|
|
123
|
+
}
|
|
124
|
+
openMenu() {
|
|
125
|
+
this.isOpen = true;
|
|
126
|
+
if (this.tableMenu) {
|
|
127
|
+
this.tableMenu.style.display = "block";
|
|
128
|
+
this.tableMenu.focus();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
closeMenu() {
|
|
132
|
+
this.isOpen = false;
|
|
133
|
+
if (this.tableMenu) {
|
|
134
|
+
this.tableMenu.style.display = "none";
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { SuggestionItem } from "./getSlashCommand";
|
|
2
|
+
import { Editor, Range } from "@tiptap/react";
|
|
1
3
|
interface SlashCommandListProps {
|
|
2
4
|
className?: string;
|
|
3
|
-
items:
|
|
4
|
-
command: (item:
|
|
5
|
-
editor:
|
|
6
|
-
range:
|
|
5
|
+
items: SuggestionItem[];
|
|
6
|
+
command: (item: SuggestionItem) => void;
|
|
7
|
+
editor: Editor;
|
|
8
|
+
range: Range;
|
|
7
9
|
}
|
|
8
10
|
declare const SlashCommandList: ({ items, command, editor, range, }: SlashCommandListProps) => import("react/jsx-runtime").JSX.Element | null;
|
|
9
11
|
export default SlashCommandList;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useLayoutEffect, useRef, useState, } from "react";
|
|
3
3
|
import styled from "styled-components";
|
|
4
|
+
import { useToolbarState } from "../Toolbar/useToolbarState";
|
|
5
|
+
import { SlashCommands } from "../Enums";
|
|
4
6
|
const SlashCommandListContainer = styled.div `
|
|
5
7
|
display: flex;
|
|
6
8
|
flex-direction: column;
|
|
@@ -38,6 +40,11 @@ const SlashCommandItem = styled.button `
|
|
|
38
40
|
&.selected {
|
|
39
41
|
background-color: ${({ theme }) => theme.palette.action.hover};
|
|
40
42
|
}
|
|
43
|
+
|
|
44
|
+
&:disabled {
|
|
45
|
+
opacity: 0.5;
|
|
46
|
+
cursor: not-allowed;
|
|
47
|
+
}
|
|
41
48
|
`;
|
|
42
49
|
const CommandIcon = styled.div `
|
|
43
50
|
display: flex;
|
|
@@ -78,6 +85,7 @@ const updateScrollView = (container, item) => {
|
|
|
78
85
|
};
|
|
79
86
|
const SlashCommandList = ({ items, command, editor, range, }) => {
|
|
80
87
|
const [selectedIndex, setSelectedIndex] = useState(0);
|
|
88
|
+
const { isInsideTable } = useToolbarState(editor);
|
|
81
89
|
const selectItem = useCallback((index) => {
|
|
82
90
|
const item = items[index];
|
|
83
91
|
if (item) {
|
|
@@ -105,6 +113,9 @@ const SlashCommandList = ({ items, command, editor, range, }) => {
|
|
|
105
113
|
return true;
|
|
106
114
|
}
|
|
107
115
|
if (e.key === "Enter") {
|
|
116
|
+
if (items[selectedIndex].disabled) {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
108
119
|
selectItem(selectedIndex);
|
|
109
120
|
return true;
|
|
110
121
|
}
|
|
@@ -127,7 +138,10 @@ const SlashCommandList = ({ items, command, editor, range, }) => {
|
|
|
127
138
|
updateScrollView(container, item);
|
|
128
139
|
}, [selectedIndex]);
|
|
129
140
|
return items.length > 0 ? (_jsx(SlashCommandListContainer, { ref: commandListContainer, className: "slash-command", children: items.map((item, index) => {
|
|
130
|
-
|
|
141
|
+
if (item.title === SlashCommands.Table && isInsideTable) {
|
|
142
|
+
item.disabled = true;
|
|
143
|
+
}
|
|
144
|
+
return (_jsxs(SlashCommandItem, { className: `slash-command-item ${index === selectedIndex ? "selected" : ""}`, onClick: () => selectItem(index), disabled: item.disabled, children: [_jsx(CommandIcon, { className: "item-icon", children: _jsx(item.icon, { size: 18 }) }), _jsxs("div", { children: [_jsx(CommandTitle, { className: "item-title", children: item.title }), _jsx(CommandDescription, { className: "item-description", children: item.description })] })] }, index));
|
|
131
145
|
}) })) : null;
|
|
132
146
|
};
|
|
133
147
|
export default SlashCommandList;
|
|
@@ -1,7 +1,18 @@
|
|
|
1
|
-
import { Extension } from "@tiptap/core";
|
|
1
|
+
import { Extension, Editor } from "@tiptap/core";
|
|
2
2
|
import { HandleImageUpload } from "../Plugins/UploadImagesPlugin.js";
|
|
3
3
|
import { SlashCommands } from "../Enums";
|
|
4
4
|
type CommandName = keyof typeof SlashCommands;
|
|
5
|
+
export type SuggestionItem = {
|
|
6
|
+
title: CommandName;
|
|
7
|
+
description: string;
|
|
8
|
+
searchTerms?: string[];
|
|
9
|
+
icon: any;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
command: (props: {
|
|
12
|
+
editor: Editor;
|
|
13
|
+
range: any;
|
|
14
|
+
}) => void;
|
|
15
|
+
};
|
|
5
16
|
interface SlashCommandOptions {
|
|
6
17
|
handleImageUpload?: HandleImageUpload;
|
|
7
18
|
commands?: CommandName[];
|
|
@@ -11,7 +11,7 @@ import { Extension } from "@tiptap/core";
|
|
|
11
11
|
import Suggestion from "@tiptap/suggestion";
|
|
12
12
|
import { ReactRenderer } from "@tiptap/react";
|
|
13
13
|
import tippy from "tippy.js";
|
|
14
|
-
import { Heading1, Heading2, Heading3, Heading4, List, ListOrdered, Text, Image as ImageIcon, Calendar, ClockIcon, } from "lucide-react";
|
|
14
|
+
import { Heading1, Heading2, Heading3, Heading4, List, ListOrdered, Text, Image as ImageIcon, Calendar, ClockIcon, Table, } from "lucide-react";
|
|
15
15
|
import { startImageUpload, } from "../Plugins/UploadImagesPlugin.js";
|
|
16
16
|
import { PluginKey } from "@tiptap/pm/state";
|
|
17
17
|
import SlashCommandList from "./SlashCommandList";
|
|
@@ -115,6 +115,15 @@ const getCommandItems = (values, options) => {
|
|
|
115
115
|
editor.chain().focus().deleteRange(range).toggleOrderedList().run();
|
|
116
116
|
},
|
|
117
117
|
},
|
|
118
|
+
{
|
|
119
|
+
title: SlashCommands.Table,
|
|
120
|
+
description: "Create a table.",
|
|
121
|
+
searchTerms: ["table"],
|
|
122
|
+
icon: Table,
|
|
123
|
+
command: ({ editor, range }) => {
|
|
124
|
+
editor.chain().focus().deleteRange(range).insertTable().run();
|
|
125
|
+
},
|
|
126
|
+
},
|
|
118
127
|
{
|
|
119
128
|
title: SlashCommands.CurrentDate,
|
|
120
129
|
description: "Insert the current date.",
|
|
@@ -3,13 +3,10 @@ import StarterKit from "@tiptap/starter-kit";
|
|
|
3
3
|
import HorizontalRule from "@tiptap/extension-horizontal-rule";
|
|
4
4
|
import Underline from "@tiptap/extension-underline";
|
|
5
5
|
import TextAlign from "@tiptap/extension-text-align";
|
|
6
|
-
import
|
|
7
|
-
import TableCell from "@tiptap/extension-table-cell";
|
|
8
|
-
import TableHeader from "@tiptap/extension-table-header";
|
|
9
|
-
import TableRow from "@tiptap/extension-table-row";
|
|
6
|
+
import { TableKit } from "@tiptap/extension-table";
|
|
10
7
|
import Placeholder from "@tiptap/extension-placeholder";
|
|
11
8
|
import { Color } from "@tiptap/extension-color";
|
|
12
|
-
import TextStyle from "@tiptap/extension-text-style";
|
|
9
|
+
import { TextStyle } from "@tiptap/extension-text-style";
|
|
13
10
|
import { InputRule, Extension } from "@tiptap/core";
|
|
14
11
|
import Focus from "@tiptap/extension-focus";
|
|
15
12
|
import { UploadImagesPlugin } from "../Plugins";
|
|
@@ -121,22 +118,13 @@ const getTipTapExtensions = ({ extensions = [], slashCommands = [], bubbleMenuOp
|
|
|
121
118
|
},
|
|
122
119
|
{
|
|
123
120
|
name: Extensions.Table,
|
|
124
|
-
extension:
|
|
125
|
-
|
|
121
|
+
extension: TableKit.configure({
|
|
122
|
+
table: {
|
|
123
|
+
resizable: true,
|
|
124
|
+
// View: CustomTableView,
|
|
125
|
+
},
|
|
126
126
|
}),
|
|
127
127
|
},
|
|
128
|
-
{
|
|
129
|
-
name: Extensions.TableRow,
|
|
130
|
-
extension: TableRow,
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
name: Extensions.TableHeader,
|
|
134
|
-
extension: TableHeader,
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
name: Extensions.TableCell,
|
|
138
|
-
extension: TableCell,
|
|
139
|
-
},
|
|
140
128
|
{
|
|
141
129
|
name: Extensions.Image,
|
|
142
130
|
extension: CustomImage.configure({
|
|
@@ -107,7 +107,8 @@ export const UploadImagesPlugin = () => new Plugin({
|
|
|
107
107
|
},
|
|
108
108
|
props: {
|
|
109
109
|
decorations(state) {
|
|
110
|
-
|
|
110
|
+
const decos = this.getState(state);
|
|
111
|
+
return decos !== null && decos !== void 0 ? decos : null;
|
|
111
112
|
},
|
|
112
113
|
},
|
|
113
114
|
});
|
|
@@ -59,23 +59,120 @@ const StyledContent = styled.div `
|
|
|
59
59
|
word-break: break-word;
|
|
60
60
|
text-rendering: optimizeLegibility;
|
|
61
61
|
|
|
62
|
+
.tableWrapper {
|
|
63
|
+
position: relative;
|
|
64
|
+
|
|
65
|
+
.tiptap-table-menu-container {
|
|
66
|
+
position: absolute;
|
|
67
|
+
left: -20px;
|
|
68
|
+
top: 0;
|
|
69
|
+
|
|
70
|
+
display: flex;
|
|
71
|
+
flex-direction: column;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.tiptap-table-menu {
|
|
75
|
+
display: none;
|
|
76
|
+
flex-direction: column;
|
|
77
|
+
align-items: center;
|
|
78
|
+
justify-content: center;
|
|
79
|
+
background-color: ${({ theme }) => theme.palette.background.default};
|
|
80
|
+
border-radius: 4px;
|
|
81
|
+
border: 1px solid ${({ theme }) => theme.palette.divider};
|
|
82
|
+
padding: 10px;
|
|
83
|
+
width: 100px;
|
|
84
|
+
height: 100px;
|
|
85
|
+
|
|
86
|
+
z-index: 1000;
|
|
87
|
+
position: absolute;
|
|
88
|
+
top: 30px;
|
|
89
|
+
left: 0px;
|
|
90
|
+
|
|
91
|
+
&.show {
|
|
92
|
+
display: flex;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.tiptap-table-menu-btn {
|
|
97
|
+
display: none;
|
|
98
|
+
align-items: center;
|
|
99
|
+
justify-content: center;
|
|
100
|
+
flex-direction: column;
|
|
101
|
+
cursor: pointer;
|
|
102
|
+
|
|
103
|
+
padding: 3px;
|
|
104
|
+
border-radius: 4px;
|
|
105
|
+
color: ${({ theme }) => theme.palette.text.secondary};
|
|
106
|
+
font-weight: 500;
|
|
107
|
+
font-size: 1.25rem;
|
|
108
|
+
|
|
109
|
+
&:hover {
|
|
110
|
+
background-color: ${({ theme }) => theme.palette.action.hover};
|
|
111
|
+
color: ${({ theme }) => theme.palette.text.primary};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.tiptap-table-addcol-btn {
|
|
116
|
+
display: none;
|
|
117
|
+
align-items: center;
|
|
118
|
+
justify-content: center;
|
|
119
|
+
flex-direction: column;
|
|
120
|
+
cursor: pointer;
|
|
121
|
+
position: absolute;
|
|
122
|
+
right: -20px;
|
|
123
|
+
top: 0;
|
|
124
|
+
width: 20px;
|
|
125
|
+
height: 100%;
|
|
126
|
+
background-color: transparent;
|
|
127
|
+
font-weight: 500;
|
|
128
|
+
border-radius: 0 4px 4px 0;
|
|
129
|
+
border-top: 1px solid ${({ theme }) => theme.palette.action.hover};
|
|
130
|
+
border-bottom: 1px solid ${({ theme }) => theme.palette.action.hover};
|
|
131
|
+
border-right: 1px solid ${({ theme }) => theme.palette.action.hover};
|
|
132
|
+
color: ${({ theme }) => theme.palette.text.secondary};
|
|
133
|
+
|
|
134
|
+
&:hover {
|
|
135
|
+
background-color: ${({ theme }) => theme.palette.action.hover};
|
|
136
|
+
color: ${({ theme }) => theme.palette.text.primary};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
62
141
|
table {
|
|
142
|
+
position: relative;
|
|
63
143
|
border-collapse: collapse;
|
|
64
144
|
width: 100%;
|
|
145
|
+
table-layout: fixed;
|
|
146
|
+
|
|
147
|
+
tr.is-empty::before {
|
|
148
|
+
display: none;
|
|
149
|
+
}
|
|
65
150
|
|
|
66
151
|
th,
|
|
67
152
|
td {
|
|
68
153
|
border: 1px solid ${({ theme }) => theme.palette.divider};
|
|
69
|
-
padding:
|
|
154
|
+
padding: 5px;
|
|
70
155
|
min-width: 100px;
|
|
156
|
+
white-space: normal;
|
|
157
|
+
word-break: break-word;
|
|
158
|
+
overflow-wrap: anywhere;
|
|
159
|
+
vertical-align: baseline;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
th.is-empty p::before {
|
|
163
|
+
display: none;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
td.is-empty p::before {
|
|
167
|
+
display: none;
|
|
71
168
|
}
|
|
72
169
|
|
|
73
170
|
// for table header
|
|
74
171
|
th {
|
|
172
|
+
background-color: ${({ theme }) => theme.palette.background.alt};
|
|
75
173
|
border: 1px solid ${({ theme }) => theme.palette.divider};
|
|
76
|
-
padding:
|
|
174
|
+
padding: 5px;
|
|
77
175
|
min-width: 100px;
|
|
78
|
-
background-color: ${({ theme }) => theme.palette.action.hover};
|
|
79
176
|
font-weight: 500;
|
|
80
177
|
}
|
|
81
178
|
}
|
|
@@ -139,6 +236,7 @@ const StyledContent = styled.div `
|
|
|
139
236
|
color: #888;
|
|
140
237
|
pointer-events: none;
|
|
141
238
|
height: 0;
|
|
239
|
+
white-space: nowrap;
|
|
142
240
|
}
|
|
143
241
|
.ProseMirror .is-empty::before {
|
|
144
242
|
content: attr(data-placeholder);
|
|
@@ -146,6 +244,7 @@ const StyledContent = styled.div `
|
|
|
146
244
|
color: #888;
|
|
147
245
|
pointer-events: none;
|
|
148
246
|
height: 0;
|
|
247
|
+
white-space: nowrap;
|
|
149
248
|
}
|
|
150
249
|
|
|
151
250
|
.ProseMirror .monolith-image.uploading {
|
|
@@ -18,7 +18,7 @@ export type ToolbarOptions = {
|
|
|
18
18
|
};
|
|
19
19
|
export type ToolbarProps = {
|
|
20
20
|
className?: string;
|
|
21
|
-
editor: Editor
|
|
21
|
+
editor: Editor;
|
|
22
22
|
toolbarOptions?: ToolbarOptions;
|
|
23
23
|
};
|
|
24
|
-
export declare const Toolbar:
|
|
24
|
+
export declare const Toolbar: React.FC<ToolbarProps>;
|
|
@@ -10,14 +10,27 @@ import RichTextEditorContext from "../Contexts/RichTextEditorContext";
|
|
|
10
10
|
import { Button } from "../../Button";
|
|
11
11
|
import TextColors from "../Enums/TextColors";
|
|
12
12
|
import { SquircleIcon } from "lucide-react";
|
|
13
|
-
|
|
13
|
+
import { useToolbarState } from "./useToolbarState";
|
|
14
|
+
const ToolbarContainer = styled.div `
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-direction: row;
|
|
17
|
+
flex-wrap: wrap;
|
|
18
|
+
justify-content: center;
|
|
19
|
+
align-items: center;
|
|
20
|
+
gap: 5px;
|
|
21
|
+
margin-bottom: 10px;
|
|
22
|
+
border-radius: 5px 5px 0 0;
|
|
23
|
+
border: 1px solid transparent;
|
|
24
|
+
`;
|
|
25
|
+
export const Toolbar = ({ className, editor, toolbarOptions, }) => {
|
|
14
26
|
var _a;
|
|
15
27
|
const theme = useTheme();
|
|
16
28
|
const { controls } = toolbarOptions || {};
|
|
17
29
|
const customItems = controls === null || controls === void 0 ? void 0 : controls.filter((control) => typeof control !== "string" &&
|
|
18
30
|
(control.type === "menu" || control.type === "button"));
|
|
19
31
|
const { font, setFont } = useContext(RichTextEditorContext);
|
|
20
|
-
|
|
32
|
+
const { isInsideTable } = useToolbarState(editor);
|
|
33
|
+
return (_jsxs(ToolbarContainer, { 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
34
|
var _a, _b;
|
|
22
35
|
if (item.type === "button") {
|
|
23
36
|
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));
|
|
@@ -60,14 +73,80 @@ export const Toolbar = styled(({ className, editor, toolbarOptions }) => {
|
|
|
60
73
|
borderRadius: "3px",
|
|
61
74
|
} }), item.label] })), size: "xxs", variant: "outlined", arrow: true, buttonProps: {
|
|
62
75
|
title: "Select Color",
|
|
63
|
-
}, children: "Color" })),
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
76
|
+
}, children: "Color" })), (controls === null || controls === void 0 ? void 0 : controls.includes(Controls.TABLE)) && (_jsx(DropDownMenu, { data: [
|
|
77
|
+
{
|
|
78
|
+
label: "Insert Table",
|
|
79
|
+
value: "insert-table",
|
|
80
|
+
onClick: () => {
|
|
81
|
+
editor === null || editor === void 0 ? void 0 : editor.chain().focus().insertTable().run();
|
|
82
|
+
},
|
|
83
|
+
disabled: isInsideTable,
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
label: "Insert Column Before",
|
|
87
|
+
value: "insert-column-before",
|
|
88
|
+
onClick: () => {
|
|
89
|
+
editor === null || editor === void 0 ? void 0 : editor.chain().focus().addColumnBefore().run();
|
|
90
|
+
},
|
|
91
|
+
disabled: !isInsideTable,
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
label: "Insert Column After",
|
|
95
|
+
value: "insert-column-after",
|
|
96
|
+
onClick: () => {
|
|
97
|
+
editor === null || editor === void 0 ? void 0 : editor.chain().focus().addColumnAfter().run();
|
|
98
|
+
},
|
|
99
|
+
disabled: !isInsideTable,
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
label: "Delete Column",
|
|
103
|
+
value: "delete-column",
|
|
104
|
+
onClick: () => {
|
|
105
|
+
editor === null || editor === void 0 ? void 0 : editor.chain().focus().deleteColumn().run();
|
|
106
|
+
},
|
|
107
|
+
disabled: !isInsideTable,
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
label: "Insert Row Before",
|
|
111
|
+
value: "insert-row-before",
|
|
112
|
+
onClick: () => {
|
|
113
|
+
editor === null || editor === void 0 ? void 0 : editor.chain().focus().addRowBefore().run();
|
|
114
|
+
},
|
|
115
|
+
disabled: !isInsideTable,
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
label: "Insert Row After",
|
|
119
|
+
value: "insert-row-after",
|
|
120
|
+
onClick: () => {
|
|
121
|
+
editor === null || editor === void 0 ? void 0 : editor.chain().focus().addRowAfter().run();
|
|
122
|
+
},
|
|
123
|
+
disabled: !isInsideTable,
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
label: "Delete Row",
|
|
127
|
+
value: "delete-row",
|
|
128
|
+
onClick: () => {
|
|
129
|
+
editor === null || editor === void 0 ? void 0 : editor.chain().focus().deleteRow().run();
|
|
130
|
+
},
|
|
131
|
+
disabled: !isInsideTable,
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
label: "Toggle Header Row",
|
|
135
|
+
value: "toggle-header-row",
|
|
136
|
+
onClick: () => {
|
|
137
|
+
editor === null || editor === void 0 ? void 0 : editor.chain().focus().toggleHeaderRow().run();
|
|
138
|
+
},
|
|
139
|
+
disabled: !isInsideTable,
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
label: "Delete Table",
|
|
143
|
+
value: "delete-table",
|
|
144
|
+
onClick: () => {
|
|
145
|
+
editor === null || editor === void 0 ? void 0 : editor.chain().focus().deleteTable().run();
|
|
146
|
+
},
|
|
147
|
+
disabled: !isInsideTable,
|
|
148
|
+
},
|
|
149
|
+
], size: "xxs", variant: "outlined", arrow: true, buttonProps: {
|
|
150
|
+
title: "Select Color",
|
|
151
|
+
}, children: "Table" })), _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 }))] })] }));
|
|
152
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Editor } from "@tiptap/react";
|
|
2
|
+
export declare const useToolbarState: (editor: Editor) => {
|
|
3
|
+
isBold: boolean;
|
|
4
|
+
canBold: boolean;
|
|
5
|
+
isItalic: boolean;
|
|
6
|
+
canItalic: boolean;
|
|
7
|
+
isStrike: boolean;
|
|
8
|
+
canStrike: boolean;
|
|
9
|
+
isCode: boolean;
|
|
10
|
+
canCode: boolean;
|
|
11
|
+
canClearMarks: boolean;
|
|
12
|
+
isParagraph: boolean;
|
|
13
|
+
isHeading1: boolean;
|
|
14
|
+
isHeading2: boolean;
|
|
15
|
+
isHeading3: boolean;
|
|
16
|
+
isHeading4: boolean;
|
|
17
|
+
isHeading5: boolean;
|
|
18
|
+
isHeading6: boolean;
|
|
19
|
+
isBulletList: boolean;
|
|
20
|
+
isOrderedList: boolean;
|
|
21
|
+
isCodeBlock: boolean;
|
|
22
|
+
isBlockquote: boolean;
|
|
23
|
+
canUndo: boolean;
|
|
24
|
+
canRedo: boolean;
|
|
25
|
+
isTable: boolean;
|
|
26
|
+
isTableRow: boolean;
|
|
27
|
+
isTableCell: boolean;
|
|
28
|
+
isTableHeader: boolean;
|
|
29
|
+
isInsideTable: boolean;
|
|
30
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { useEditorState } from "@tiptap/react";
|
|
2
|
+
export const useToolbarState = (editor) => {
|
|
3
|
+
const editorState = useEditorState({
|
|
4
|
+
editor,
|
|
5
|
+
selector: (ctx) => {
|
|
6
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1;
|
|
7
|
+
const isTable = (_a = ctx.editor.isActive("table")) !== null && _a !== void 0 ? _a : false;
|
|
8
|
+
const isTableRow = (_b = ctx.editor.isActive("tableRow")) !== null && _b !== void 0 ? _b : false;
|
|
9
|
+
const isTableCell = (_c = ctx.editor.isActive("tableCell")) !== null && _c !== void 0 ? _c : false;
|
|
10
|
+
const isTableHeader = (_d = ctx.editor.isActive("tableHeader")) !== null && _d !== void 0 ? _d : false;
|
|
11
|
+
const isInsideTable = isTable || isTableRow || isTableCell || isTableHeader;
|
|
12
|
+
return {
|
|
13
|
+
isBold: (_e = ctx.editor.isActive("bold")) !== null && _e !== void 0 ? _e : false,
|
|
14
|
+
canBold: (_f = ctx.editor.can().chain().toggleBold().run()) !== null && _f !== void 0 ? _f : false,
|
|
15
|
+
isItalic: (_g = ctx.editor.isActive("italic")) !== null && _g !== void 0 ? _g : false,
|
|
16
|
+
canItalic: (_h = ctx.editor.can().chain().toggleItalic().run()) !== null && _h !== void 0 ? _h : false,
|
|
17
|
+
isStrike: (_j = ctx.editor.isActive("strike")) !== null && _j !== void 0 ? _j : false,
|
|
18
|
+
canStrike: (_k = ctx.editor.can().chain().toggleStrike().run()) !== null && _k !== void 0 ? _k : false,
|
|
19
|
+
isCode: (_l = ctx.editor.isActive("code")) !== null && _l !== void 0 ? _l : false,
|
|
20
|
+
canCode: (_m = ctx.editor.can().chain().toggleCode().run()) !== null && _m !== void 0 ? _m : false,
|
|
21
|
+
canClearMarks: (_o = ctx.editor.can().chain().unsetAllMarks().run()) !== null && _o !== void 0 ? _o : false,
|
|
22
|
+
isParagraph: (_p = ctx.editor.isActive("paragraph")) !== null && _p !== void 0 ? _p : false,
|
|
23
|
+
isHeading1: (_q = ctx.editor.isActive("heading", { level: 1 })) !== null && _q !== void 0 ? _q : false,
|
|
24
|
+
isHeading2: (_r = ctx.editor.isActive("heading", { level: 2 })) !== null && _r !== void 0 ? _r : false,
|
|
25
|
+
isHeading3: (_s = ctx.editor.isActive("heading", { level: 3 })) !== null && _s !== void 0 ? _s : false,
|
|
26
|
+
isHeading4: (_t = ctx.editor.isActive("heading", { level: 4 })) !== null && _t !== void 0 ? _t : false,
|
|
27
|
+
isHeading5: (_u = ctx.editor.isActive("heading", { level: 5 })) !== null && _u !== void 0 ? _u : false,
|
|
28
|
+
isHeading6: (_v = ctx.editor.isActive("heading", { level: 6 })) !== null && _v !== void 0 ? _v : false,
|
|
29
|
+
isBulletList: (_w = ctx.editor.isActive("bulletList")) !== null && _w !== void 0 ? _w : false,
|
|
30
|
+
isOrderedList: (_x = ctx.editor.isActive("orderedList")) !== null && _x !== void 0 ? _x : false,
|
|
31
|
+
isCodeBlock: (_y = ctx.editor.isActive("codeBlock")) !== null && _y !== void 0 ? _y : false,
|
|
32
|
+
isBlockquote: (_z = ctx.editor.isActive("blockquote")) !== null && _z !== void 0 ? _z : false,
|
|
33
|
+
canUndo: (_0 = ctx.editor.can().chain().undo().run()) !== null && _0 !== void 0 ? _0 : false,
|
|
34
|
+
canRedo: (_1 = ctx.editor.can().chain().redo().run()) !== null && _1 !== void 0 ? _1 : false,
|
|
35
|
+
isTable,
|
|
36
|
+
isTableRow,
|
|
37
|
+
isTableCell,
|
|
38
|
+
isTableHeader,
|
|
39
|
+
isInsideTable,
|
|
40
|
+
};
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
return editorState;
|
|
44
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@monolith-forensics/monolith-ui",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.3",
|
|
4
4
|
"main": "./dist/index.js",
|
|
5
5
|
"types": "./dist/index.d.ts",
|
|
6
6
|
"author": "Matt Danner (Monolith Forensics LLC)",
|
|
@@ -33,22 +33,23 @@
|
|
|
33
33
|
"@radix-ui/react-switch": "^1.0.7",
|
|
34
34
|
"@radix-ui/react-tooltip": "^1.0.7",
|
|
35
35
|
"@tabler/icons-react": "^3.11.0",
|
|
36
|
-
"@tiptap/extension-color": "^
|
|
37
|
-
"@tiptap/extension-focus": "^
|
|
38
|
-
"@tiptap/extension-horizontal-rule": "^
|
|
39
|
-
"@tiptap/extension-image": "^
|
|
40
|
-
"@tiptap/extension-placeholder": "^
|
|
41
|
-
"@tiptap/extension-table": "^
|
|
42
|
-
"@tiptap/extension-table-cell": "^
|
|
43
|
-
"@tiptap/extension-table-header": "^
|
|
44
|
-
"@tiptap/extension-table-row": "^
|
|
45
|
-
"@tiptap/extension-text-align": "^
|
|
46
|
-
"@tiptap/extension-text-style": "^
|
|
47
|
-
"@tiptap/extension-underline": "^
|
|
48
|
-
"@tiptap/
|
|
49
|
-
"@tiptap/
|
|
50
|
-
"@tiptap/
|
|
51
|
-
"@tiptap/
|
|
36
|
+
"@tiptap/extension-color": "^3.0.9",
|
|
37
|
+
"@tiptap/extension-focus": "^3.0.9",
|
|
38
|
+
"@tiptap/extension-horizontal-rule": "^3.0.9",
|
|
39
|
+
"@tiptap/extension-image": "^3.0.9",
|
|
40
|
+
"@tiptap/extension-placeholder": "^3.0.9",
|
|
41
|
+
"@tiptap/extension-table": "^3.0.9",
|
|
42
|
+
"@tiptap/extension-table-cell": "^3.0.9",
|
|
43
|
+
"@tiptap/extension-table-header": "^3.0.9",
|
|
44
|
+
"@tiptap/extension-table-row": "^3.0.9",
|
|
45
|
+
"@tiptap/extension-text-align": "^3.0.9",
|
|
46
|
+
"@tiptap/extension-text-style": "^3.0.9",
|
|
47
|
+
"@tiptap/extension-underline": "^3.0.9",
|
|
48
|
+
"@tiptap/extensions": "^3.0.9",
|
|
49
|
+
"@tiptap/pm": "^3.0.9",
|
|
50
|
+
"@tiptap/react": "^3.0.9",
|
|
51
|
+
"@tiptap/starter-kit": "^3.0.9",
|
|
52
|
+
"@tiptap/suggestion": "^3.0.9",
|
|
52
53
|
"@uiw/codemirror-theme-vscode": "^4.23.6",
|
|
53
54
|
"@uiw/react-codemirror": "^4.23.6",
|
|
54
55
|
"deepmerge": "^4.3.1",
|