From f18bf3ff124923f4f6147a17dd923e50ae1196b6 Mon Sep 17 00:00:00 2001
From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com>
Date: Mon, 28 Aug 2023 14:42:36 +0530
Subject: [PATCH 1/8] added basic table support
---
.../components/tiptap/extensions/index.tsx | 12 ++
.../tiptap/extensions/table/table-cell.ts | 39 ++++++
.../tiptap/extensions/table/table-header.ts | 7 +
.../tiptap/extensions/table/table-row.ts | 0
.../tiptap/extensions/table/table.ts | 9 ++
.../tiptap/extensions/updated-image.tsx | 2 +-
apps/app/components/tiptap/index.tsx | 2 +
.../tiptap/plugins/delete-image.tsx | 2 +-
.../tiptap/plugins/table-menu-component.tsx | 129 ++++++++++++++++++
.../components/tiptap/plugins/table-menu.tsx | 123 +++++++++++++++++
.../components/tiptap/slash-command/index.tsx | 11 ++
.../components/tiptap/table-menu/index.tsx | 94 +++++++++++++
apps/app/package.json | 5 +
apps/app/styles/editor.css | 90 ++++++++++++
14 files changed, 523 insertions(+), 2 deletions(-)
create mode 100644 apps/app/components/tiptap/extensions/table/table-cell.ts
create mode 100644 apps/app/components/tiptap/extensions/table/table-header.ts
create mode 100644 apps/app/components/tiptap/extensions/table/table-row.ts
create mode 100644 apps/app/components/tiptap/extensions/table/table.ts
create mode 100644 apps/app/components/tiptap/plugins/table-menu-component.tsx
create mode 100644 apps/app/components/tiptap/plugins/table-menu.tsx
create mode 100644 apps/app/components/tiptap/table-menu/index.tsx
diff --git a/apps/app/components/tiptap/extensions/index.tsx b/apps/app/components/tiptap/extensions/index.tsx
index 2c5ffd10a43..e34ea0348b8 100644
--- a/apps/app/components/tiptap/extensions/index.tsx
+++ b/apps/app/components/tiptap/extensions/index.tsx
@@ -20,6 +20,10 @@ import "highlight.js/styles/github-dark.css";
import UniqueID from "@tiptap-pro/extension-unique-id";
import UpdatedImage from "./updated-image";
import isValidHttpUrl from "../bubble-menu/utils/link-validator";
+import { CustomTableCell } from "./table/table-cell";
+import { Table } from "./table/table";
+import { TableHeader } from "./table/table-header";
+import { TableRow } from "@tiptap/extension-table-row";
lowlight.registerLanguage("ts", ts);
@@ -101,9 +105,13 @@ export const TiptapExtensions = (workspaceSlug: string, setIsSubmitting?: (isSub
}),
Placeholder.configure({
placeholder: ({ node }) => {
+ console.log(node.type.name)
if (node.type.name === "heading") {
return `Heading ${node.attrs.level}`;
}
+ if (node.type.name === "image" || node.type.name === "table") {
+ return ""
+ }
return "Press '/' for commands...";
},
@@ -134,4 +142,8 @@ export const TiptapExtensions = (workspaceSlug: string, setIsSubmitting?: (isSub
html: true,
transformCopiedText: true,
}),
+ Table,
+ TableHeader,
+ CustomTableCell,
+ TableRow
];
diff --git a/apps/app/components/tiptap/extensions/table/table-cell.ts b/apps/app/components/tiptap/extensions/table/table-cell.ts
new file mode 100644
index 00000000000..f0d5cce42d8
--- /dev/null
+++ b/apps/app/components/tiptap/extensions/table/table-cell.ts
@@ -0,0 +1,39 @@
+import { TableCell } from "@tiptap/extension-table-cell";
+import { Star } from "lucide-react";
+
+export const CustomTableCell = TableCell.extend({
+ addAttributes() {
+ return {
+ ...this.parent?.(),
+ isHeader: {
+ default: false,
+ parseHTML: (element) => {
+ console.log("ran inside", element.tagName);
+ return { isHeader: element.tagName === "TD" };
+ },
+ renderHTML: (attributes) => {
+ return { tag: attributes.isHeader ? "th" : "td" };
+ },
+ },
+ };
+ },
+ renderHTML({ HTMLAttributes }) {
+ console.log("ran", HTMLAttributes);
+ if (HTMLAttributes.isHeader) {
+ return [
+ "th",
+ {
+ ...HTMLAttributes,
+ class: `relative ${HTMLAttributes.class}`,
+ },
+ [
+ "span",
+ { class: "absolute top-0 right-0" },
+ Star
+ ],
+ 0,
+ ];
+ }
+ return ["td", HTMLAttributes, 0];
+ },
+});
diff --git a/apps/app/components/tiptap/extensions/table/table-header.ts b/apps/app/components/tiptap/extensions/table/table-header.ts
new file mode 100644
index 00000000000..d04fe85d3fb
--- /dev/null
+++ b/apps/app/components/tiptap/extensions/table/table-header.ts
@@ -0,0 +1,7 @@
+import { TableHeader as BaseTableHeader } from "@tiptap/extension-table-header";
+
+const TableHeader = BaseTableHeader.extend({
+ content: "paragraph"
+});
+
+export { TableHeader };
diff --git a/apps/app/components/tiptap/extensions/table/table-row.ts b/apps/app/components/tiptap/extensions/table/table-row.ts
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/apps/app/components/tiptap/extensions/table/table.ts b/apps/app/components/tiptap/extensions/table/table.ts
new file mode 100644
index 00000000000..b05dedb3b51
--- /dev/null
+++ b/apps/app/components/tiptap/extensions/table/table.ts
@@ -0,0 +1,9 @@
+import { Table as BaseTable } from "@tiptap/extension-table";
+
+const Table = BaseTable.configure({
+ resizable: true,
+ cellMinWidth: 100,
+ allowTableNodeSelection: true
+});
+
+export { Table };
diff --git a/apps/app/components/tiptap/extensions/updated-image.tsx b/apps/app/components/tiptap/extensions/updated-image.tsx
index 01648dcd701..2f27ffab306 100644
--- a/apps/app/components/tiptap/extensions/updated-image.tsx
+++ b/apps/app/components/tiptap/extensions/updated-image.tsx
@@ -4,7 +4,7 @@ import UploadImagesPlugin from "../plugins/upload-image";
const UpdatedImage = Image.extend({
addProseMirrorPlugins() {
- return [UploadImagesPlugin(), TrackImageDeletionPlugin()];
+ return [UploadImagesPlugin()];
},
addAttributes() {
return {
diff --git a/apps/app/components/tiptap/index.tsx b/apps/app/components/tiptap/index.tsx
index 418449c0890..7d04fb09347 100644
--- a/apps/app/components/tiptap/index.tsx
+++ b/apps/app/components/tiptap/index.tsx
@@ -5,6 +5,7 @@ import { TiptapExtensions } from "./extensions";
import { TiptapEditorProps } from "./props";
import { useImperativeHandle, useRef } from "react";
import { ImageResizer } from "./extensions/image-resize";
+import { TableMenu } from "./table-menu";
export interface ITiptapRichTextEditor {
value: string;
@@ -91,6 +92,7 @@ const Tiptap = (props: ITiptapRichTextEditor) => {
{editor && }
+ {editor?.isActive("table") &&
}
{editor?.isActive("image") &&
}
diff --git a/apps/app/components/tiptap/plugins/delete-image.tsx b/apps/app/components/tiptap/plugins/delete-image.tsx
index 57ab65c6379..2761d7f9f74 100644
--- a/apps/app/components/tiptap/plugins/delete-image.tsx
+++ b/apps/app/components/tiptap/plugins/delete-image.tsx
@@ -16,7 +16,7 @@ const TrackImageDeletionPlugin = () =>
oldState.doc.descendants((oldNode, oldPos) => {
if (oldNode.type.name !== 'image') return;
- if (!newState.doc.resolve(oldPos).parent) return;
+ // if (!newState.doc.resolve(oldPos).parent) return;
const newNode = newState.doc.nodeAt(oldPos);
// Check if the node has been deleted or replaced
diff --git a/apps/app/components/tiptap/plugins/table-menu-component.tsx b/apps/app/components/tiptap/plugins/table-menu-component.tsx
new file mode 100644
index 00000000000..b5d1379fc92
--- /dev/null
+++ b/apps/app/components/tiptap/plugins/table-menu-component.tsx
@@ -0,0 +1,129 @@
+import {
+ mdiKeyboardCloseOutline,
+ mdiTableColumnPlusAfter,
+ mdiTableColumnPlusBefore,
+ mdiTableHeadersEye,
+ mdiTableHeadersEyeOff,
+ mdiTableRemove,
+ mdiTableRowPlusAfter,
+ mdiTableRowPlusBefore
+} from "@mdi/js";
+import { ChainedCommands } from "@tiptap/core";
+import clsx from "clsx";
+import { FC, useMemo } from "react";
+
+interface TableMenuProps {
+ state: {
+ container: HTMLElement | null;
+ };
+}
+
+const TableMenu: FC = (props) => {
+ const hasHeader = useMemo(() => props.state.container?.querySelector("tr:first-child > th") !== null, [props.state.container]);
+ const runCommand = (fn: (chain: ChainedCommands) => void): void => {
+ const chain = props.state.editor.chain();
+
+ if (hasHeader()) {
+ chain.toggleHeaderRow();
+ }
+
+ fn(chain);
+
+ if (hasHeader()) {
+ chain.toggleHeaderRow();
+ }
+
+ chain.fixTables().focus().run();
+ };
+
+ return (
+
+
+ chain.addRowBefore());
+ }
+ },
+ {
+ icon: mdiTableRowPlusAfter,
+ label: "Insert row below",
+ onClick() {
+ runCommand((chain) => chain.addRowAfter());
+ }
+ },
+ {
+ icon: mdiTableColumnPlusBefore,
+ label: "Insert column left",
+ onClick() {
+ runCommand((chain) => chain.addColumnBefore());
+ }
+ },
+ {
+ icon: mdiTableColumnPlusAfter,
+ label: "Insert column right",
+ onClick() {
+ runCommand((chain) => chain.addColumnAfter());
+ }
+ },
+ {
+ label() {
+ return hasHeader() ? "Remove header row" : "Add header row";
+ },
+ icon() {
+ return hasHeader() ? mdiTableHeadersEyeOff : mdiTableHeadersEye;
+ },
+ onClick() {
+ props.state.editor.chain().focus().toggleHeaderRow().run();
+ }
+ },
+ {
+ icon: mdiTableRemove,
+ label: "Delete table",
+ onClick() {
+ props.state.editor.chain().deleteTable().focus().run();
+ }
+ },
+ ...((!breakpoints.md() && [
+ {
+ icon: mdiKeyboardCloseOutline,
+ label: "Close keyboard",
+ async onClick() {
+ props.state.editor.commands.blur();
+ }
+ }
+ ]) ||
+ [])
+ ]}
+ >
+ {(menuItem) => {
+ return (
+
+
+
+ );
+ }}
+
+
+
+ );
+};
+
+export { TableMenu };
diff --git a/apps/app/components/tiptap/plugins/table-menu.tsx b/apps/app/components/tiptap/plugins/table-menu.tsx
new file mode 100644
index 00000000000..722a0e724bb
--- /dev/null
+++ b/apps/app/components/tiptap/plugins/table-menu.tsx
@@ -0,0 +1,123 @@
+import { TableMenu } from "./component";
+import { Extension } from "@tiptap/core";
+import { TextSelection } from "@tiptap/pm/state";
+import { CellSelection } from "@tiptap/pm/tables";
+import { Editor } from "@tiptap/react";
+
+const generalMenuContainer = document.createElement("div");
+
+const getTableParent = (node: Node): HTMLElement | null => {
+ let currentNode: HTMLElement | null =
+ node.nodeType === 1 ? (node as HTMLElement) : node.parentElement;
+
+ while (currentNode) {
+ if (currentNode.tagName === "TABLE") {
+ return currentNode;
+ }
+
+ currentNode = currentNode.parentElement;
+ }
+
+ return null;
+};
+const handleUpdate = (editor: Editor): void => {
+ const { selection } = editor.state;
+ const isTextSelection = selection instanceof TextSelection;
+ const isCellSelection = selection instanceof CellSelection;
+ const selectedNode = selection.$from.node(1) || selection.$from.nodeAfter;
+
+ if (
+ !selectedNode ||
+ !editor.isActive("table") ||
+ isCellSelection ||
+ !(isTextSelection && selection.empty)
+ ) {
+ generalMenuContainer.style.display = "none";
+
+ return;
+ }
+
+ const { view } = editor;
+ const node =
+ view.nodeDOM(selection.$from.pos) ||
+ view.nodeDOM(selection.$from.pos - selection.$from.parentOffset) ||
+ view.domAtPos(selection.$from.pos)?.node;
+
+ if (!node) return;
+
+ const blockParent = getTableParent(node);
+ const parentPos = document.getElementById("pm-container")?.getBoundingClientRect();
+ const childPos = blockParent?.getBoundingClientRect();
+ const tablePos = blockParent?.querySelector("tbody")?.getBoundingClientRect();
+
+ if (!parentPos || !childPos) return;
+
+ const relativePos = {
+ top: childPos.top - parentPos.top,
+ right: childPos.right - parentPos.right,
+ bottom: childPos.bottom - parentPos.bottom,
+ left: childPos.left - parentPos.left
+ };
+
+ generalMenuContainer.style.top = `${relativePos.top + (tablePos?.height || 0)}px`;
+ generalMenuContainer.style.transform = `translate(${(tablePos?.width || 0) > 250 ? "-50%" : "0"
+ },0.75rem)`;
+
+ if ((tablePos?.width || 0) > 250) {
+ generalMenuContainer.style.left = `${relativePos.left + Math.min(tablePos?.width || parentPos.width, parentPos.width) / 2
+ }px`;
+ } else {
+ generalMenuContainer.style.left = "-0.25rem";
+ }
+
+ generalMenuContainer.style.display = "block";
+ generalMenu?.setState({
+ node: selectedNode,
+ container: blockParent,
+ editor
+ });
+};
+const TableMenuPlugin = Extension.create({
+ name: "tableMenu",
+ onCreate() {
+ generalMenu = new SolidRenderer(TableMenu, {
+ editor: this.editor as SolidEditor,
+ state: {
+ container: null as HTMLElement | null,
+ editor: this.editor as SolidEditor
+ }
+ });
+ generalMenuContainer.style.position = "absolute";
+ generalMenuContainer.style.top = "-100vh";
+ generalMenuContainer.style.left = "-100vw";
+ generalMenuContainer.appendChild(generalMenu.element);
+ document.getElementById("pm-container")?.appendChild(generalMenuContainer);
+ },
+ onBlur() {
+ const dropdownOpened = document.documentElement.classList.contains("dropdown-opened");
+
+ if (
+ (document.activeElement?.contains(generalMenuContainer) || dropdownOpened) &&
+ breakpoints.md()
+ ) {
+ return;
+ }
+
+ generalMenuContainer.style.display = "none";
+ },
+ onFocus() {
+ const isCellSelection = this.editor.state.selection instanceof CellSelection;
+
+ if (this.editor.isActive("table") && !isCellSelection) {
+ generalMenuContainer.style.display = "block";
+ }
+ },
+ onUpdate() {
+ handleUpdate(this.editor as SolidEditor);
+ },
+ onSelectionUpdate() {
+ handleUpdate(this.editor as SolidEditor);
+ }
+});
+
+export { TableMenuPlugin };
diff --git a/apps/app/components/tiptap/slash-command/index.tsx b/apps/app/components/tiptap/slash-command/index.tsx
index 38f5c9c0ad9..13c6e3bc0d6 100644
--- a/apps/app/components/tiptap/slash-command/index.tsx
+++ b/apps/app/components/tiptap/slash-command/index.tsx
@@ -15,6 +15,7 @@ import {
MinusSquare,
CheckSquare,
ImageIcon,
+ Table,
} from "lucide-react";
import { startImageUpload } from "../plugins/upload-image";
import { cn } from "../utils";
@@ -60,6 +61,7 @@ const getSuggestionItems = (workspaceSlug: string, setIsSubmitting?: (isSubmitti
searchTerms: ["p", "paragraph"],
icon: ,
command: ({ editor, range }: CommandProps) => {
+ console.log("focused")
editor.chain().focus().deleteRange(range).toggleNode("paragraph", "paragraph").run();
},
},
@@ -117,6 +119,15 @@ const getSuggestionItems = (workspaceSlug: string, setIsSubmitting?: (isSubmitti
editor.chain().focus().deleteRange(range).setHorizontalRule().run();
},
},
+ {
+ title: "Table",
+ description: "Create a Table",
+ searchTerms: ["table", "cell", "db", "data", "tabular"],
+ icon: ,
+ command: ({ editor, range }: CommandProps) => {
+ editor.chain().focus().deleteRange(range).insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run();
+ },
+ },
{
title: "Numbered List",
description: "Create a list with numbering.",
diff --git a/apps/app/components/tiptap/table-menu/index.tsx b/apps/app/components/tiptap/table-menu/index.tsx
new file mode 100644
index 00000000000..5b2aa714012
--- /dev/null
+++ b/apps/app/components/tiptap/table-menu/index.tsx
@@ -0,0 +1,94 @@
+import { BubbleMenu, BubbleMenuProps } from "@tiptap/react";
+import { FC, useState, useEffect } from "react";
+import { Rows, Columns, BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, CodeIcon } from "lucide-react";
+
+import { cn } from "../utils";
+import { ToggleOn } from "@mui/icons-material";
+
+export interface TableMenuItem {
+ name: string;
+ isActive?: () => boolean;
+ command: () => void;
+ icon: typeof Rows;
+}
+
+type EditorTableMenuProps = Omit;
+
+export const TableMenu: FC = (props: any) => {
+ const items: TableMenuItem[] = [
+ {
+ name: "Add Column to Right",
+ command: () => props.editor?.chain().focus().addColumnAfter().run(),
+ icon: Columns,
+ },
+ {
+ name: "Toggle table header",
+ command: () => props.editor?.chain().focus().toggleHeaderRow().run(),
+ icon: ToggleOn,
+ },
+ {
+ name: "Add Column to Left",
+ command: () => props.editor?.chain().focus().addColumnBefore().run(),
+ icon: Columns,
+ },
+ {
+ name: "Add Row to Top",
+ command: () => props.editor?.chain().focus().addRowBefore().run(),
+ icon: Rows,
+ },
+ {
+ name: "Add Row Below",
+ command: () => props.editor?.chain().focus().addRowAfter().run(),
+ icon: Rows,
+ },
+ {
+ name: "Delete Column",
+ command: () => props.editor?.chain().focus().deleteColumn().run(),
+ icon: Columns,
+ },
+ {
+ name: "Delete Rows",
+ command: () => props.editor?.chain().focus().deleteRow().run(),
+ icon: Rows,
+ }
+ ];
+
+ const tableMenuProps: EditorTableMenuProps = {
+ ...props,
+ shouldShow: ({ editor }) => {
+ if (!editor.isEditable) {
+ return false;
+ }
+ if (editor?.isActive("table")) {
+ return true;
+ }
+ },
+ tippyOptions: {
+ moveTransition: "transform 0.15s ease-out",
+ },
+ };
+
+ return (
+
+
+ {items.map((item, index) => (
+
+ ))}
+
+
+ );
+};
diff --git a/apps/app/package.json b/apps/app/package.json
index 578a95716f5..045c02b4399 100644
--- a/apps/app/package.json
+++ b/apps/app/package.json
@@ -16,6 +16,7 @@
"@headlessui/react": "^1.7.3",
"@heroicons/react": "^2.0.12",
"@jitsu/nextjs": "^3.1.5",
+ "@mdi/js": "^7.2.96",
"@mui/icons-material": "^5.14.1",
"@mui/material": "^5.14.1",
"@nivo/bar": "0.80.0",
@@ -35,6 +36,10 @@
"@tiptap/extension-image": "^2.0.4",
"@tiptap/extension-link": "^2.0.4",
"@tiptap/extension-placeholder": "^2.0.4",
+ "@tiptap/extension-table": "^2.1.6",
+ "@tiptap/extension-table-cell": "^2.1.6",
+ "@tiptap/extension-table-header": "^2.1.6",
+ "@tiptap/extension-table-row": "^2.1.6",
"@tiptap/extension-task-item": "^2.0.4",
"@tiptap/extension-task-list": "^2.0.4",
"@tiptap/extension-text-style": "^2.0.4",
diff --git a/apps/app/styles/editor.css b/apps/app/styles/editor.css
index 57c23c911b5..96e3ff84dd2 100644
--- a/apps/app/styles/editor.css
+++ b/apps/app/styles/editor.css
@@ -150,3 +150,93 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
transform: rotate(360deg);
}
}
+
+#tiptap-container {
+ table {
+ border-collapse: collapse;
+ table-layout: fixed;
+ border: 2px solid rgb(var(--color-border-100));
+ border-radius: 10px;
+ width: 100%;
+ margin: 0;
+ box-shadow: 0 0 10px rgba(0,0,0,0.1);
+
+ td,
+ th {
+ min-width: 1em;
+ border: 2px solid rgb(var(--color-border-400));
+ padding: 10px 15px;
+ vertical-align: top;
+ box-sizing: border-box;
+ position: relative;
+ transition: background-color 0.3s ease;
+
+ > * {
+ margin-bottom: 0;
+ }
+ }
+
+ th {
+ font-weight: bold;
+ text-align: left;
+ background-color: rgb(var(--color-primary-300));
+ }
+
+ tr:first-child th:first-child {
+ border-top-left-radius: 10px;
+ }
+
+ tr:first-child th:last-child {
+ border-top-right-radius: 10px;
+ }
+
+ tr:last-child td:first-child {
+ border-bottom-left-radius: 10px;
+ }
+
+ tr:last-child td:last-child {
+ border-bottom-right-radius: 10px;
+ }
+
+ td:hover {
+ background-color: rgba(var(--color-primary-300), 0.1);
+ }
+
+ .selectedCell:after {
+ z-index: 2;
+ position: absolute;
+ content: "";
+ left: 0; right: 0; top: 0; bottom: 0;
+ background-color: rgba(var(--color-primary-300), 0.1);
+ pointer-events: none;
+ }
+
+ .column-resize-handle {
+ position: absolute;
+ right: -2px;
+ top: 0;
+ bottom: -2px;
+ width: 2px;
+ background-color: rgb(var(--color-primary-400));
+ pointer-events: none;
+ }
+ }
+}
+
+.tableWrapper {
+ overflow-x: auto;
+}
+
+.resize-cursor {
+ cursor: ew-resize;
+ cursor: col-resize;
+}
+
+.ProseMirror table * p {
+ padding: 0px 1px;
+ margin: 6px 2px;
+}
+
+.ProseMirror table * .is-empty::before {
+ opacity: 0;
+}
From 3a34458245d7c0e098036db7f74efefdffcbcb2e Mon Sep 17 00:00:00 2001
From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com>
Date: Tue, 29 Aug 2023 14:06:56 +0530
Subject: [PATCH 2/8] fixed table position at bottom
---
.../tiptap/extensions/updated-image.tsx | 2 +-
.../tiptap/plugins/delete-image.tsx | 2 +-
.../tiptap/plugins/table-menu-component.tsx | 129 ------------------
.../components/tiptap/plugins/table-menu.tsx | 123 -----------------
.../components/tiptap/table-menu/index.tsx | 116 +++++++---------
apps/app/package.json | 1 -
apps/app/styles/editor.css | 3 +-
yarn.lock | 29 +++-
8 files changed, 84 insertions(+), 321 deletions(-)
diff --git a/apps/app/components/tiptap/extensions/updated-image.tsx b/apps/app/components/tiptap/extensions/updated-image.tsx
index 2f27ffab306..01648dcd701 100644
--- a/apps/app/components/tiptap/extensions/updated-image.tsx
+++ b/apps/app/components/tiptap/extensions/updated-image.tsx
@@ -4,7 +4,7 @@ import UploadImagesPlugin from "../plugins/upload-image";
const UpdatedImage = Image.extend({
addProseMirrorPlugins() {
- return [UploadImagesPlugin()];
+ return [UploadImagesPlugin(), TrackImageDeletionPlugin()];
},
addAttributes() {
return {
diff --git a/apps/app/components/tiptap/plugins/delete-image.tsx b/apps/app/components/tiptap/plugins/delete-image.tsx
index 2761d7f9f74..57ab65c6379 100644
--- a/apps/app/components/tiptap/plugins/delete-image.tsx
+++ b/apps/app/components/tiptap/plugins/delete-image.tsx
@@ -16,7 +16,7 @@ const TrackImageDeletionPlugin = () =>
oldState.doc.descendants((oldNode, oldPos) => {
if (oldNode.type.name !== 'image') return;
- // if (!newState.doc.resolve(oldPos).parent) return;
+ if (!newState.doc.resolve(oldPos).parent) return;
const newNode = newState.doc.nodeAt(oldPos);
// Check if the node has been deleted or replaced
diff --git a/apps/app/components/tiptap/plugins/table-menu-component.tsx b/apps/app/components/tiptap/plugins/table-menu-component.tsx
index b5d1379fc92..e69de29bb2d 100644
--- a/apps/app/components/tiptap/plugins/table-menu-component.tsx
+++ b/apps/app/components/tiptap/plugins/table-menu-component.tsx
@@ -1,129 +0,0 @@
-import {
- mdiKeyboardCloseOutline,
- mdiTableColumnPlusAfter,
- mdiTableColumnPlusBefore,
- mdiTableHeadersEye,
- mdiTableHeadersEyeOff,
- mdiTableRemove,
- mdiTableRowPlusAfter,
- mdiTableRowPlusBefore
-} from "@mdi/js";
-import { ChainedCommands } from "@tiptap/core";
-import clsx from "clsx";
-import { FC, useMemo } from "react";
-
-interface TableMenuProps {
- state: {
- container: HTMLElement | null;
- };
-}
-
-const TableMenu: FC = (props) => {
- const hasHeader = useMemo(() => props.state.container?.querySelector("tr:first-child > th") !== null, [props.state.container]);
- const runCommand = (fn: (chain: ChainedCommands) => void): void => {
- const chain = props.state.editor.chain();
-
- if (hasHeader()) {
- chain.toggleHeaderRow();
- }
-
- fn(chain);
-
- if (hasHeader()) {
- chain.toggleHeaderRow();
- }
-
- chain.fixTables().focus().run();
- };
-
- return (
-
-
- chain.addRowBefore());
- }
- },
- {
- icon: mdiTableRowPlusAfter,
- label: "Insert row below",
- onClick() {
- runCommand((chain) => chain.addRowAfter());
- }
- },
- {
- icon: mdiTableColumnPlusBefore,
- label: "Insert column left",
- onClick() {
- runCommand((chain) => chain.addColumnBefore());
- }
- },
- {
- icon: mdiTableColumnPlusAfter,
- label: "Insert column right",
- onClick() {
- runCommand((chain) => chain.addColumnAfter());
- }
- },
- {
- label() {
- return hasHeader() ? "Remove header row" : "Add header row";
- },
- icon() {
- return hasHeader() ? mdiTableHeadersEyeOff : mdiTableHeadersEye;
- },
- onClick() {
- props.state.editor.chain().focus().toggleHeaderRow().run();
- }
- },
- {
- icon: mdiTableRemove,
- label: "Delete table",
- onClick() {
- props.state.editor.chain().deleteTable().focus().run();
- }
- },
- ...((!breakpoints.md() && [
- {
- icon: mdiKeyboardCloseOutline,
- label: "Close keyboard",
- async onClick() {
- props.state.editor.commands.blur();
- }
- }
- ]) ||
- [])
- ]}
- >
- {(menuItem) => {
- return (
-
-
-
- );
- }}
-
-
-
- );
-};
-
-export { TableMenu };
diff --git a/apps/app/components/tiptap/plugins/table-menu.tsx b/apps/app/components/tiptap/plugins/table-menu.tsx
index 722a0e724bb..e69de29bb2d 100644
--- a/apps/app/components/tiptap/plugins/table-menu.tsx
+++ b/apps/app/components/tiptap/plugins/table-menu.tsx
@@ -1,123 +0,0 @@
-import { TableMenu } from "./component";
-import { Extension } from "@tiptap/core";
-import { TextSelection } from "@tiptap/pm/state";
-import { CellSelection } from "@tiptap/pm/tables";
-import { Editor } from "@tiptap/react";
-
-const generalMenuContainer = document.createElement("div");
-
-const getTableParent = (node: Node): HTMLElement | null => {
- let currentNode: HTMLElement | null =
- node.nodeType === 1 ? (node as HTMLElement) : node.parentElement;
-
- while (currentNode) {
- if (currentNode.tagName === "TABLE") {
- return currentNode;
- }
-
- currentNode = currentNode.parentElement;
- }
-
- return null;
-};
-const handleUpdate = (editor: Editor): void => {
- const { selection } = editor.state;
- const isTextSelection = selection instanceof TextSelection;
- const isCellSelection = selection instanceof CellSelection;
- const selectedNode = selection.$from.node(1) || selection.$from.nodeAfter;
-
- if (
- !selectedNode ||
- !editor.isActive("table") ||
- isCellSelection ||
- !(isTextSelection && selection.empty)
- ) {
- generalMenuContainer.style.display = "none";
-
- return;
- }
-
- const { view } = editor;
- const node =
- view.nodeDOM(selection.$from.pos) ||
- view.nodeDOM(selection.$from.pos - selection.$from.parentOffset) ||
- view.domAtPos(selection.$from.pos)?.node;
-
- if (!node) return;
-
- const blockParent = getTableParent(node);
- const parentPos = document.getElementById("pm-container")?.getBoundingClientRect();
- const childPos = blockParent?.getBoundingClientRect();
- const tablePos = blockParent?.querySelector("tbody")?.getBoundingClientRect();
-
- if (!parentPos || !childPos) return;
-
- const relativePos = {
- top: childPos.top - parentPos.top,
- right: childPos.right - parentPos.right,
- bottom: childPos.bottom - parentPos.bottom,
- left: childPos.left - parentPos.left
- };
-
- generalMenuContainer.style.top = `${relativePos.top + (tablePos?.height || 0)}px`;
- generalMenuContainer.style.transform = `translate(${(tablePos?.width || 0) > 250 ? "-50%" : "0"
- },0.75rem)`;
-
- if ((tablePos?.width || 0) > 250) {
- generalMenuContainer.style.left = `${relativePos.left + Math.min(tablePos?.width || parentPos.width, parentPos.width) / 2
- }px`;
- } else {
- generalMenuContainer.style.left = "-0.25rem";
- }
-
- generalMenuContainer.style.display = "block";
- generalMenu?.setState({
- node: selectedNode,
- container: blockParent,
- editor
- });
-};
-const TableMenuPlugin = Extension.create({
- name: "tableMenu",
- onCreate() {
- generalMenu = new SolidRenderer(TableMenu, {
- editor: this.editor as SolidEditor,
- state: {
- container: null as HTMLElement | null,
- editor: this.editor as SolidEditor
- }
- });
- generalMenuContainer.style.position = "absolute";
- generalMenuContainer.style.top = "-100vh";
- generalMenuContainer.style.left = "-100vw";
- generalMenuContainer.appendChild(generalMenu.element);
- document.getElementById("pm-container")?.appendChild(generalMenuContainer);
- },
- onBlur() {
- const dropdownOpened = document.documentElement.classList.contains("dropdown-opened");
-
- if (
- (document.activeElement?.contains(generalMenuContainer) || dropdownOpened) &&
- breakpoints.md()
- ) {
- return;
- }
-
- generalMenuContainer.style.display = "none";
- },
- onFocus() {
- const isCellSelection = this.editor.state.selection instanceof CellSelection;
-
- if (this.editor.isActive("table") && !isCellSelection) {
- generalMenuContainer.style.display = "block";
- }
- },
- onUpdate() {
- handleUpdate(this.editor as SolidEditor);
- },
- onSelectionUpdate() {
- handleUpdate(this.editor as SolidEditor);
- }
-});
-
-export { TableMenuPlugin };
diff --git a/apps/app/components/tiptap/table-menu/index.tsx b/apps/app/components/tiptap/table-menu/index.tsx
index 5b2aa714012..cf39d3a6b6d 100644
--- a/apps/app/components/tiptap/table-menu/index.tsx
+++ b/apps/app/components/tiptap/table-menu/index.tsx
@@ -1,94 +1,82 @@
-import { BubbleMenu, BubbleMenuProps } from "@tiptap/react";
-import { FC, useState, useEffect } from "react";
-import { Rows, Columns, BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, CodeIcon } from "lucide-react";
-
+import { useState, useEffect } from "react";
+import { Rows, Columns } from "lucide-react";
import { cn } from "../utils";
-import { ToggleOn } from "@mui/icons-material";
-export interface TableMenuItem {
+interface TableMenuItem {
name: string;
- isActive?: () => boolean;
command: () => void;
- icon: typeof Rows;
+ icon: any;
}
-type EditorTableMenuProps = Omit;
+const findTableAncestor = (node: Node | null): HTMLTableElement | null => {
+ while (node !== null && node.nodeName !== "TABLE") {
+ node = node.parentNode;
+ }
+ return node as HTMLTableElement;
+};
-export const TableMenu: FC = (props: any) => {
+export const TableMenu = ({ editor }: { editor: any }) => {
+ const [tableLocation, setTableLocation] = useState(0);
const items: TableMenuItem[] = [
{
- name: "Add Column to Right",
- command: () => props.editor?.chain().focus().addColumnAfter().run(),
- icon: Columns,
- },
- {
- name: "Toggle table header",
- command: () => props.editor?.chain().focus().toggleHeaderRow().run(),
- icon: ToggleOn,
- },
- {
- name: "Add Column to Left",
- command: () => props.editor?.chain().focus().addColumnBefore().run(),
+ name: "Insert column right",
+ command: () => editor.chain().focus().addColumnBefore().run(),
icon: Columns,
},
{
- name: "Add Row to Top",
- command: () => props.editor?.chain().focus().addRowBefore().run(),
- icon: Rows,
- },
- {
- name: "Add Row Below",
- command: () => props.editor?.chain().focus().addRowAfter().run(),
+ name: "Insert row below",
+ command: () => editor.chain().focus().addRowAfter().run(),
icon: Rows,
},
{
name: "Delete Column",
- command: () => props.editor?.chain().focus().deleteColumn().run(),
+ command: () => editor.chain().focus().deleteColumn().run(),
icon: Columns,
},
{
name: "Delete Rows",
- command: () => props.editor?.chain().focus().deleteRow().run(),
+ command: () => editor.chain().focus().deleteRow().run(),
icon: Rows,
}
];
- const tableMenuProps: EditorTableMenuProps = {
- ...props,
- shouldShow: ({ editor }) => {
- if (!editor.isEditable) {
- return false;
+ useEffect(() => {
+ const handleWindowClick = () => {
+ const selection: any = window.getSelection();
+ const range = selection.getRangeAt(0);
+ const tableNode = findTableAncestor(range.startContainer);
+ if (tableNode) {
+ const tableBottom = tableNode.getBoundingClientRect().bottom;
+ tableLocation !== tableBottom && setTableLocation(tableBottom);
}
- if (editor?.isActive("table")) {
- return true;
- }
- },
- tippyOptions: {
- moveTransition: "transform 0.15s ease-out",
- },
- };
+ };
+
+ window.addEventListener("click", handleWindowClick);
+
+ return () => {
+ window.removeEventListener("click", handleWindowClick);
+ };
+ }, [tableLocation]);
return (
-
-
- {items.map((item, index) => (
-
- ))}
-
-
+ {items.map((item, index) => (
+
+ ))}
+
);
};
diff --git a/apps/app/package.json b/apps/app/package.json
index 045c02b4399..b5cb26f6f2b 100644
--- a/apps/app/package.json
+++ b/apps/app/package.json
@@ -16,7 +16,6 @@
"@headlessui/react": "^1.7.3",
"@heroicons/react": "^2.0.12",
"@jitsu/nextjs": "^3.1.5",
- "@mdi/js": "^7.2.96",
"@mui/icons-material": "^5.14.1",
"@mui/material": "^5.14.1",
"@nivo/bar": "0.80.0",
diff --git a/apps/app/styles/editor.css b/apps/app/styles/editor.css
index 96e3ff84dd2..3a721bacf25 100644
--- a/apps/app/styles/editor.css
+++ b/apps/app/styles/editor.css
@@ -155,10 +155,11 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
table {
border-collapse: collapse;
table-layout: fixed;
+ margin: 0;
+ margin-bottom: 2rem;
border: 2px solid rgb(var(--color-border-100));
border-radius: 10px;
width: 100%;
- margin: 0;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
td,
diff --git a/yarn.lock b/yarn.lock
index 8bc1fec304d..36041e2d0ac 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2349,6 +2349,26 @@
resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.0.4.tgz#13286dcf8780c55610ed65b24238b8395a5be824"
integrity sha512-Men7LK6N/Dh3/G4/z2Z9WkDHM2Gxx1XyxYix2ZMf5CnqY37SeDNUnGDqit65pdIN3Y/TQnOZTkKSBilSAtXfJA==
+"@tiptap/extension-table-cell@^2.1.6":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-table-cell/-/extension-table-cell-2.1.7.tgz#87841144b8368c9611ad46f2134b637e2c33c8bc"
+ integrity sha512-p3e4FNdbKVIjOLHDcXrRtlP6FYPoN6hBUFjq6QZbf5g4+ao2Uq4bQCL+eKbYMxUVERl8g/Qu9X+jG99fVsBDjA==
+
+"@tiptap/extension-table-header@^2.1.6":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-table-header/-/extension-table-header-2.1.7.tgz#4757834655e2c4edffa65bc6f6807eb59401e0d8"
+ integrity sha512-rolSUQxFJf/CEj2XBJpeMsLiLHASKrVIzZ2A/AZ9pT6WpFqmECi8r9xyutpJpx21n2Hrk46Y+uGFOKhyvbZ5ug==
+
+"@tiptap/extension-table-row@^2.1.6":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-table-row/-/extension-table-row-2.1.7.tgz#f736a61035b271423ef18f65a25f8d1e240263a1"
+ integrity sha512-DBCaEMEuCCoOmr4fdDfp2jnmyWPt672rmCZ5WUuenJ47Cy4Ox2dV+qk5vBZ/yDQcq12WvzLMhdSnAo9pMMMa6Q==
+
+"@tiptap/extension-table@^2.1.6":
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/@tiptap/extension-table/-/extension-table-2.1.7.tgz#c8a83744f60c76ae1e41438b04d5ac9e984afa66"
+ integrity sha512-nlKs35vTQOFW9lfw76S7kJvqVJAfHUlz1muQgWT0gNUlKJYINMXjUIg4Wcx8LTaITCCkp0lMGrLETGRNI+RyxA==
+
"@tiptap/extension-task-item@^2.0.4":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-2.0.4.tgz#71f46d35ac629ca10c5c23d4ad170007338a436e"
@@ -6558,13 +6578,20 @@ prosemirror-menu@^1.2.1:
prosemirror-history "^1.0.0"
prosemirror-state "^1.0.0"
-prosemirror-model@1.18.1, prosemirror-model@^1.0.0, prosemirror-model@^1.16.0, prosemirror-model@^1.18.1, prosemirror-model@^1.19.0, prosemirror-model@^1.8.1:
+prosemirror-model@^1.0.0, prosemirror-model@^1.16.0, prosemirror-model@^1.18.1, prosemirror-model@^1.8.1:
version "1.18.1"
resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.18.1.tgz#1d5d6b6de7b983ee67a479dc607165fdef3935bd"
integrity sha512-IxSVBKAEMjD7s3n8cgtwMlxAXZrC7Mlag7zYsAKDndAqnDScvSmp/UdnRTV/B33lTCVU3CCm7dyAn/rVVD0mcw==
dependencies:
orderedmap "^2.0.0"
+prosemirror-model@^1.19.0:
+ version "1.19.3"
+ resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.19.3.tgz#f0d55285487fefd962d0ac695f716f4ec6705006"
+ integrity sha512-tgSnwN7BS7/UM0sSARcW+IQryx2vODKX4MI7xpqY2X+iaepJdKBPc7I4aACIsDV/LTaTjt12Z56MhDr9LsyuZQ==
+ dependencies:
+ orderedmap "^2.0.0"
+
prosemirror-schema-basic@^1.2.0:
version "1.2.2"
resolved "https://registry.yarnpkg.com/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.2.tgz#6695f5175e4628aab179bf62e5568628b9cfe6c7"
From a2a78529ab82c654335b024677d8addf54875567 Mon Sep 17 00:00:00 2001
From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com>
Date: Tue, 29 Aug 2023 14:36:53 +0530
Subject: [PATCH 3/8] fixed image node deletion logic's regression issue
---
apps/app/components/tiptap/extensions/index.tsx | 1 -
.../tiptap/extensions/table/table-cell.ts | 12 ++----------
.../tiptap/extensions/table/table-row.ts | 0
.../components/tiptap/plugins/delete-image.tsx | 2 +-
.../tiptap/plugins/table-menu-component.tsx | 0
.../components/tiptap/plugins/table-menu.tsx | 0
apps/app/components/tiptap/table-menu/index.tsx | 12 +++++++++---
apps/app/styles/editor.css | 17 -----------------
8 files changed, 12 insertions(+), 32 deletions(-)
delete mode 100644 apps/app/components/tiptap/extensions/table/table-row.ts
delete mode 100644 apps/app/components/tiptap/plugins/table-menu-component.tsx
delete mode 100644 apps/app/components/tiptap/plugins/table-menu.tsx
diff --git a/apps/app/components/tiptap/extensions/index.tsx b/apps/app/components/tiptap/extensions/index.tsx
index e34ea0348b8..900258d44c8 100644
--- a/apps/app/components/tiptap/extensions/index.tsx
+++ b/apps/app/components/tiptap/extensions/index.tsx
@@ -105,7 +105,6 @@ export const TiptapExtensions = (workspaceSlug: string, setIsSubmitting?: (isSub
}),
Placeholder.configure({
placeholder: ({ node }) => {
- console.log(node.type.name)
if (node.type.name === "heading") {
return `Heading ${node.attrs.level}`;
}
diff --git a/apps/app/components/tiptap/extensions/table/table-cell.ts b/apps/app/components/tiptap/extensions/table/table-cell.ts
index f0d5cce42d8..94c5aced2d6 100644
--- a/apps/app/components/tiptap/extensions/table/table-cell.ts
+++ b/apps/app/components/tiptap/extensions/table/table-cell.ts
@@ -1,5 +1,4 @@
import { TableCell } from "@tiptap/extension-table-cell";
-import { Star } from "lucide-react";
export const CustomTableCell = TableCell.extend({
addAttributes() {
@@ -7,18 +6,12 @@ export const CustomTableCell = TableCell.extend({
...this.parent?.(),
isHeader: {
default: false,
- parseHTML: (element) => {
- console.log("ran inside", element.tagName);
- return { isHeader: element.tagName === "TD" };
- },
- renderHTML: (attributes) => {
- return { tag: attributes.isHeader ? "th" : "td" };
- },
+ parseHTML: (element) => { isHeader: element.tagName === "TD" },
+ renderHTML: (attributes) => { tag: attributes.isHeader ? "th" : "td" }
},
};
},
renderHTML({ HTMLAttributes }) {
- console.log("ran", HTMLAttributes);
if (HTMLAttributes.isHeader) {
return [
"th",
@@ -29,7 +22,6 @@ export const CustomTableCell = TableCell.extend({
[
"span",
{ class: "absolute top-0 right-0" },
- Star
],
0,
];
diff --git a/apps/app/components/tiptap/extensions/table/table-row.ts b/apps/app/components/tiptap/extensions/table/table-row.ts
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/apps/app/components/tiptap/plugins/delete-image.tsx b/apps/app/components/tiptap/plugins/delete-image.tsx
index 57ab65c6379..262a3f59145 100644
--- a/apps/app/components/tiptap/plugins/delete-image.tsx
+++ b/apps/app/components/tiptap/plugins/delete-image.tsx
@@ -16,6 +16,7 @@ const TrackImageDeletionPlugin = () =>
oldState.doc.descendants((oldNode, oldPos) => {
if (oldNode.type.name !== 'image') return;
+ if (oldPos < 0 || oldPos > newState.doc.content.size) return;
if (!newState.doc.resolve(oldPos).parent) return;
const newNode = newState.doc.nodeAt(oldPos);
@@ -28,7 +29,6 @@ const TrackImageDeletionPlugin = () =>
nodeExists = true;
}
});
-
if (!nodeExists) {
removedImages.push(oldNode as ProseMirrorNode);
}
diff --git a/apps/app/components/tiptap/plugins/table-menu-component.tsx b/apps/app/components/tiptap/plugins/table-menu-component.tsx
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/apps/app/components/tiptap/plugins/table-menu.tsx b/apps/app/components/tiptap/plugins/table-menu.tsx
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/apps/app/components/tiptap/table-menu/index.tsx b/apps/app/components/tiptap/table-menu/index.tsx
index cf39d3a6b6d..75b301aa4d4 100644
--- a/apps/app/components/tiptap/table-menu/index.tsx
+++ b/apps/app/components/tiptap/table-menu/index.tsx
@@ -1,5 +1,5 @@
import { useState, useEffect } from "react";
-import { Rows, Columns } from "lucide-react";
+import { Rows, Columns, ToggleRight } from "lucide-react";
import { cn } from "../utils";
interface TableMenuItem {
@@ -19,12 +19,12 @@ export const TableMenu = ({ editor }: { editor: any }) => {
const [tableLocation, setTableLocation] = useState(0);
const items: TableMenuItem[] = [
{
- name: "Insert column right",
+ name: "Insert Column right",
command: () => editor.chain().focus().addColumnBefore().run(),
icon: Columns,
},
{
- name: "Insert row below",
+ name: "Insert Row below",
command: () => editor.chain().focus().addRowAfter().run(),
icon: Rows,
},
@@ -37,7 +37,13 @@ export const TableMenu = ({ editor }: { editor: any }) => {
name: "Delete Rows",
command: () => editor.chain().focus().deleteRow().run(),
icon: Rows,
+ },
+ {
+ name: "Toggle Header Row",
+ command: () => editor.chain().focus().toggleHeaderRow().run(),
+ icon: ToggleRight,
}
+
];
useEffect(() => {
diff --git a/apps/app/styles/editor.css b/apps/app/styles/editor.css
index 3a721bacf25..8808fb2c4aa 100644
--- a/apps/app/styles/editor.css
+++ b/apps/app/styles/editor.css
@@ -158,7 +158,6 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
margin: 0;
margin-bottom: 2rem;
border: 2px solid rgb(var(--color-border-100));
- border-radius: 10px;
width: 100%;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
@@ -183,22 +182,6 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
background-color: rgb(var(--color-primary-300));
}
- tr:first-child th:first-child {
- border-top-left-radius: 10px;
- }
-
- tr:first-child th:last-child {
- border-top-right-radius: 10px;
- }
-
- tr:last-child td:first-child {
- border-bottom-left-radius: 10px;
- }
-
- tr:last-child td:last-child {
- border-bottom-right-radius: 10px;
- }
-
td:hover {
background-color: rgba(var(--color-primary-300), 0.1);
}
From 55d2f4b2aa64ca76392e22cdc7582ca5561f09d6 Mon Sep 17 00:00:00 2001
From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com>
Date: Tue, 29 Aug 2023 20:01:48 +0530
Subject: [PATCH 4/8] added compatible styles
---
.../components/tiptap/bubble-menu/index.tsx | 20 +++++++++---
.../tiptap/bubble-menu/link-selector.tsx | 7 +++--
.../components/tiptap/slash-command/index.tsx | 31 ++++++++++++++-----
.../components/tiptap/table-menu/index.tsx | 8 ++---
apps/app/styles/editor.css | 2 +-
5 files changed, 50 insertions(+), 18 deletions(-)
diff --git a/apps/app/components/tiptap/bubble-menu/index.tsx b/apps/app/components/tiptap/bubble-menu/index.tsx
index e689007829b..d14c7033c88 100644
--- a/apps/app/components/tiptap/bubble-menu/index.tsx
+++ b/apps/app/components/tiptap/bubble-menu/index.tsx
@@ -5,6 +5,7 @@ import { BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, CodeIcon } from
import { NodeSelector } from "./node-selector";
import { LinkSelector } from "./link-selector";
import { cn } from "../utils";
+import { findTableAncestor } from "../table-menu";
export interface BubbleMenuItem {
name: string;
@@ -16,6 +17,7 @@ export interface BubbleMenuItem {
type EditorBubbleMenuProps = Omit;
export const EditorBubbleMenu: FC = (props: any) => {
+ const [isTableSelected, setisTableSelected] = useState(false)
const items: BubbleMenuItem[] = [
{
name: "bold",
@@ -58,6 +60,15 @@ export const EditorBubbleMenu: FC = (props: any) => {
if (editor.isActive("image")) {
return false;
}
+ const selection: any = window?.getSelection();
+ if (selection.rangeCount !== 0) {
+ const range = selection.getRangeAt(0);
+ if (findTableAncestor(range.startContainer)) {
+ setisTableSelected(true)
+ } else {
+ setisTableSelected(false)
+ }
+ }
return editor.view.state.selection.content().size > 0;
},
tippyOptions: {
@@ -77,22 +88,23 @@ export const EditorBubbleMenu: FC = (props: any) => {
{...bubbleMenuProps}
className="flex w-fit divide-x divide-custom-border-300 rounded border border-custom-border-300 bg-custom-background-100 shadow-xl"
>
- {
setIsNodeSelectorOpen(!isNodeSelectorOpen);
setIsLinkSelectorOpen(false);
}}
- />
- }
+ {!isTableSelected && {
setIsLinkSelectorOpen(!isLinkSelectorOpen);
setIsNodeSelectorOpen(false);
}}
- />
+ />}
{items.map((item, index) => (