From d639a0126d49c37269d8d98b59ae54b1308465ac Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Wed, 27 Sep 2023 19:49:15 +0530 Subject: [PATCH] new structure of editor components --- package.json | 1 + packages/editor/{ => core}/package.json | 0 packages/editor/{ => core}/postcss.config.js | 0 packages/editor/core/src/index.ts | 6 + packages/editor/core/src/lib/utils.ts | 15 + .../editor/{ => core}/src/styles/editor.css | 0 .../editor/{ => core}/src/styles/tailwind.css | 0 .../{ => core}/src/types/delete-image.ts | 0 .../{ => core}/src/types/upload-image.ts | 0 .../src/ui}/extensions/image/image-resize.tsx | 0 .../ui}/extensions/image/updated-image.tsx | 4 +- .../src/ui}/extensions/index.tsx | 12 +- .../src/ui}/extensions/slash-command.tsx | 2 +- .../src/ui}/extensions/table/table-cell.ts | 0 .../src/ui}/extensions/table/table-header.ts | 0 .../src/ui}/extensions/table/table.ts | 0 .../{src/ui/editor => core/src/ui}/index.tsx | 24 +- .../src/ui}/menus/bubble-menu/index.tsx | 0 .../ui}/menus/bubble-menu/link-selector.tsx | 2 +- .../ui}/menus/bubble-menu/node-selector.tsx | 0 .../src/ui}/menus/bubble-menu/utils/index.tsx | 0 .../core/src/ui/menus/fixed-menu/icon.tsx | 13 + .../src/ui}/menus/fixed-menu/index.tsx | 42 +- .../table-menu/InsertBottomTableIcon.tsx | 0 .../menus/table-menu/InsertLeftTableIcon.tsx | 0 .../menus/table-menu/InsertRightTableIcon.tsx | 0 .../menus/table-menu/InsertTopTableIcon.tsx | 0 .../src/ui}/menus/table-menu/index.tsx | 9 +- .../src/ui}/menus/table-menu/tooltip.tsx | 0 .../src/ui}/plugins/delete-image.tsx | 0 .../src/ui}/plugins/upload-image.tsx | 0 .../ui/light-editor => core/src/ui}/props.tsx | 4 +- packages/editor/core/src/useEditor.tsx | 35 ++ packages/editor/{ => core}/tailwind.config.js | 0 packages/editor/{ => core}/tsconfig.json | 0 packages/editor/{ => core}/tsup.config.ts | 0 packages/editor/lite-text-editor/package.json | 86 +++++ .../editor/lite-text-editor/postcss.config.js | 9 + .../lite-text-editor/tailwind.config.js | 6 + .../editor/lite-text-editor/tsconfig.json | 20 + .../editor/lite-text-editor/tsup.config.ts | 11 + packages/editor/rich-text-editor/package.json | 86 +++++ .../editor/rich-text-editor/postcss.config.js | 9 + .../rich-text-editor/tailwind.config.js | 6 + .../editor/rich-text-editor/tsconfig.json | 20 + .../editor/rich-text-editor/tsup.config.ts | 11 + packages/editor/src/index.ts | 4 - packages/editor/src/lib/utils.ts | 6 - .../editor/extensions/image/updated-image.tsx | 23 -- .../editor/src/ui/editor/extensions/index.tsx | 155 -------- .../src/ui/editor/menus/table-menu/index.tsx | 143 ------- packages/editor/src/ui/editor/props.tsx | 71 ---- .../extensions/image/image-resize.tsx | 44 --- .../light-editor/extensions/slash-command.tsx | 365 ------------------ .../extensions/table/table-cell.ts | 32 -- .../extensions/table/table-header.ts | 7 - .../ui/light-editor/extensions/table/table.ts | 9 - packages/editor/src/ui/light-editor/index.tsx | 0 .../light-editor/menus/bubble-menu/index.tsx | 121 ------ .../menus/bubble-menu/link-selector.tsx | 93 ----- .../menus/bubble-menu/node-selector.tsx | 130 ------- .../menus/bubble-menu/utils/index.tsx | 11 - .../table-menu/InsertBottomTableIcon.tsx | 16 - .../menus/table-menu/InsertLeftTableIcon.tsx | 15 - .../menus/table-menu/InsertRightTableIcon.tsx | 16 - .../menus/table-menu/InsertTopTableIcon.tsx | 15 - .../light-editor/menus/table-menu/tooltip.tsx | 77 ---- .../ui/light-editor/plugins/delete-image.tsx | 68 ---- .../ui/light-editor/plugins/upload-image.tsx | 138 ------- web/components/issues/comment/add-comment.tsx | 68 ++-- yarn.lock | 20 +- 71 files changed, 430 insertions(+), 1650 deletions(-) rename packages/editor/{ => core}/package.json (100%) rename packages/editor/{ => core}/postcss.config.js (100%) create mode 100644 packages/editor/core/src/index.ts create mode 100644 packages/editor/core/src/lib/utils.ts rename packages/editor/{ => core}/src/styles/editor.css (100%) rename packages/editor/{ => core}/src/styles/tailwind.css (100%) rename packages/editor/{ => core}/src/types/delete-image.ts (100%) rename packages/editor/{ => core}/src/types/upload-image.ts (100%) rename packages/editor/{src/ui/editor => core/src/ui}/extensions/image/image-resize.tsx (100%) rename packages/editor/{src/ui/light-editor => core/src/ui}/extensions/image/updated-image.tsx (77%) rename packages/editor/{src/ui/light-editor => core/src/ui}/extensions/index.tsx (91%) rename packages/editor/{src/ui/editor => core/src/ui}/extensions/slash-command.tsx (99%) rename packages/editor/{src/ui/editor => core/src/ui}/extensions/table/table-cell.ts (100%) rename packages/editor/{src/ui/editor => core/src/ui}/extensions/table/table-header.ts (100%) rename packages/editor/{src/ui/editor => core/src/ui}/extensions/table/table.ts (100%) rename packages/editor/{src/ui/editor => core/src/ui}/index.tsx (85%) rename packages/editor/{src/ui/editor => core/src/ui}/menus/bubble-menu/index.tsx (100%) rename packages/editor/{src/ui/editor => core/src/ui}/menus/bubble-menu/link-selector.tsx (97%) rename packages/editor/{src/ui/editor => core/src/ui}/menus/bubble-menu/node-selector.tsx (100%) rename packages/editor/{src/ui/editor => core/src/ui}/menus/bubble-menu/utils/index.tsx (100%) create mode 100644 packages/editor/core/src/ui/menus/fixed-menu/icon.tsx rename packages/editor/{src/ui/editor => core/src/ui}/menus/fixed-menu/index.tsx (59%) rename packages/editor/{src/ui/editor => core/src/ui}/menus/table-menu/InsertBottomTableIcon.tsx (100%) rename packages/editor/{src/ui/editor => core/src/ui}/menus/table-menu/InsertLeftTableIcon.tsx (100%) rename packages/editor/{src/ui/editor => core/src/ui}/menus/table-menu/InsertRightTableIcon.tsx (100%) rename packages/editor/{src/ui/editor => core/src/ui}/menus/table-menu/InsertTopTableIcon.tsx (100%) rename packages/editor/{src/ui/light-editor => core/src/ui}/menus/table-menu/index.tsx (94%) rename packages/editor/{src/ui/editor => core/src/ui}/menus/table-menu/tooltip.tsx (100%) rename packages/editor/{src/ui/editor => core/src/ui}/plugins/delete-image.tsx (100%) rename packages/editor/{src/ui/editor => core/src/ui}/plugins/upload-image.tsx (100%) rename packages/editor/{src/ui/light-editor => core/src/ui}/props.tsx (94%) create mode 100644 packages/editor/core/src/useEditor.tsx rename packages/editor/{ => core}/tailwind.config.js (100%) rename packages/editor/{ => core}/tsconfig.json (100%) rename packages/editor/{ => core}/tsup.config.ts (100%) create mode 100644 packages/editor/lite-text-editor/package.json create mode 100644 packages/editor/lite-text-editor/postcss.config.js create mode 100644 packages/editor/lite-text-editor/tailwind.config.js create mode 100644 packages/editor/lite-text-editor/tsconfig.json create mode 100644 packages/editor/lite-text-editor/tsup.config.ts create mode 100644 packages/editor/rich-text-editor/package.json create mode 100644 packages/editor/rich-text-editor/postcss.config.js create mode 100644 packages/editor/rich-text-editor/tailwind.config.js create mode 100644 packages/editor/rich-text-editor/tsconfig.json create mode 100644 packages/editor/rich-text-editor/tsup.config.ts delete mode 100644 packages/editor/src/index.ts delete mode 100644 packages/editor/src/lib/utils.ts delete mode 100644 packages/editor/src/ui/editor/extensions/image/updated-image.tsx delete mode 100644 packages/editor/src/ui/editor/extensions/index.tsx delete mode 100644 packages/editor/src/ui/editor/menus/table-menu/index.tsx delete mode 100644 packages/editor/src/ui/editor/props.tsx delete mode 100644 packages/editor/src/ui/light-editor/extensions/image/image-resize.tsx delete mode 100644 packages/editor/src/ui/light-editor/extensions/slash-command.tsx delete mode 100644 packages/editor/src/ui/light-editor/extensions/table/table-cell.ts delete mode 100644 packages/editor/src/ui/light-editor/extensions/table/table-header.ts delete mode 100644 packages/editor/src/ui/light-editor/extensions/table/table.ts delete mode 100644 packages/editor/src/ui/light-editor/index.tsx delete mode 100644 packages/editor/src/ui/light-editor/menus/bubble-menu/index.tsx delete mode 100644 packages/editor/src/ui/light-editor/menus/bubble-menu/link-selector.tsx delete mode 100644 packages/editor/src/ui/light-editor/menus/bubble-menu/node-selector.tsx delete mode 100644 packages/editor/src/ui/light-editor/menus/bubble-menu/utils/index.tsx delete mode 100644 packages/editor/src/ui/light-editor/menus/table-menu/InsertBottomTableIcon.tsx delete mode 100644 packages/editor/src/ui/light-editor/menus/table-menu/InsertLeftTableIcon.tsx delete mode 100644 packages/editor/src/ui/light-editor/menus/table-menu/InsertRightTableIcon.tsx delete mode 100644 packages/editor/src/ui/light-editor/menus/table-menu/InsertTopTableIcon.tsx delete mode 100644 packages/editor/src/ui/light-editor/menus/table-menu/tooltip.tsx delete mode 100644 packages/editor/src/ui/light-editor/plugins/delete-image.tsx delete mode 100644 packages/editor/src/ui/light-editor/plugins/upload-image.tsx diff --git a/package.json b/package.json index 3c729a234..23ec38b79 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "workspaces": [ "web", "space", + "packages/editor/*", "packages/*" ], "scripts": { diff --git a/packages/editor/package.json b/packages/editor/core/package.json similarity index 100% rename from packages/editor/package.json rename to packages/editor/core/package.json diff --git a/packages/editor/postcss.config.js b/packages/editor/core/postcss.config.js similarity index 100% rename from packages/editor/postcss.config.js rename to packages/editor/core/postcss.config.js diff --git a/packages/editor/core/src/index.ts b/packages/editor/core/src/index.ts new file mode 100644 index 000000000..7e137d3c6 --- /dev/null +++ b/packages/editor/core/src/index.ts @@ -0,0 +1,6 @@ +import "@/styles/tailwind.css"; +import "@/styles/editor.css"; + +export { TiptapEditor, TiptapEditorWithRef } from "@/ui"; + +export { useEditor } from "@/useEditor"; diff --git a/packages/editor/core/src/lib/utils.ts b/packages/editor/core/src/lib/utils.ts new file mode 100644 index 000000000..1c985922b --- /dev/null +++ b/packages/editor/core/src/lib/utils.ts @@ -0,0 +1,15 @@ +import { clsx, type ClassValue } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} + +export const findTableAncestor = ( + node: Node | null +): HTMLTableElement | null => { + while (node !== null && node.nodeName !== "TABLE") { + node = node.parentNode; + } + return node as HTMLTableElement; +}; \ No newline at end of file diff --git a/packages/editor/src/styles/editor.css b/packages/editor/core/src/styles/editor.css similarity index 100% rename from packages/editor/src/styles/editor.css rename to packages/editor/core/src/styles/editor.css diff --git a/packages/editor/src/styles/tailwind.css b/packages/editor/core/src/styles/tailwind.css similarity index 100% rename from packages/editor/src/styles/tailwind.css rename to packages/editor/core/src/styles/tailwind.css diff --git a/packages/editor/src/types/delete-image.ts b/packages/editor/core/src/types/delete-image.ts similarity index 100% rename from packages/editor/src/types/delete-image.ts rename to packages/editor/core/src/types/delete-image.ts diff --git a/packages/editor/src/types/upload-image.ts b/packages/editor/core/src/types/upload-image.ts similarity index 100% rename from packages/editor/src/types/upload-image.ts rename to packages/editor/core/src/types/upload-image.ts diff --git a/packages/editor/src/ui/editor/extensions/image/image-resize.tsx b/packages/editor/core/src/ui/extensions/image/image-resize.tsx similarity index 100% rename from packages/editor/src/ui/editor/extensions/image/image-resize.tsx rename to packages/editor/core/src/ui/extensions/image/image-resize.tsx diff --git a/packages/editor/src/ui/light-editor/extensions/image/updated-image.tsx b/packages/editor/core/src/ui/extensions/image/updated-image.tsx similarity index 77% rename from packages/editor/src/ui/light-editor/extensions/image/updated-image.tsx rename to packages/editor/core/src/ui/extensions/image/updated-image.tsx index 2ba977f57..9157e8905 100644 --- a/packages/editor/src/ui/light-editor/extensions/image/updated-image.tsx +++ b/packages/editor/core/src/ui/extensions/image/updated-image.tsx @@ -1,6 +1,6 @@ import Image from "@tiptap/extension-image"; -import TrackImageDeletionPlugin from "@/ui/editor/plugins/delete-image"; -import UploadImagesPlugin from "@/ui/editor/plugins/upload-image"; +import TrackImageDeletionPlugin from "@/ui/plugins/delete-image"; +import UploadImagesPlugin from "@/ui/plugins/upload-image"; import { DeleteImage } from "@/types/delete-image"; const UpdatedImage = (deleteImage: DeleteImage) => Image.extend({ diff --git a/packages/editor/src/ui/light-editor/extensions/index.tsx b/packages/editor/core/src/ui/extensions/index.tsx similarity index 91% rename from packages/editor/src/ui/light-editor/extensions/index.tsx rename to packages/editor/core/src/ui/extensions/index.tsx index 5fd7f9ad1..f018fab49 100644 --- a/packages/editor/src/ui/light-editor/extensions/index.tsx +++ b/packages/editor/core/src/ui/extensions/index.tsx @@ -12,18 +12,18 @@ import Highlight from "@tiptap/extension-highlight"; import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight"; import { InputRule } from "@tiptap/core"; import Gapcursor from "@tiptap/extension-gapcursor"; -import { Table } from "@/ui/editor/extensions/table/table"; -import { TableHeader } from "@/ui/editor/extensions/table/table-header"; +import { Table } from "@/ui/extensions/table/table"; +import { TableHeader } from "@/ui/extensions/table/table-header"; import { TableRow } from "@tiptap/extension-table-row"; -import { CustomTableCell } from "@/ui/editor/extensions/table/table-cell"; +import { CustomTableCell } from "@/ui/extensions/table/table-cell"; -import UpdatedImage from "@/ui/editor/extensions/image/updated-image"; -import SlashCommand from "@/ui/editor/extensions/slash-command"; +import UpdatedImage from "@/ui/extensions/image/updated-image"; +import SlashCommand from "@/ui/extensions/slash-command"; import { DeleteImage } from "@/types/delete-image"; import { UploadImage } from "@/types/upload-image"; -import isValidHttpUrl from "@/ui/editor/menus/bubble-menu/utils" +import isValidHttpUrl from "@/ui/menus/bubble-menu/utils" import ts from "highlight.js/lib/languages/typescript"; import { lowlight } from "lowlight/lib/core"; diff --git a/packages/editor/src/ui/editor/extensions/slash-command.tsx b/packages/editor/core/src/ui/extensions/slash-command.tsx similarity index 99% rename from packages/editor/src/ui/editor/extensions/slash-command.tsx rename to packages/editor/core/src/ui/extensions/slash-command.tsx index 4fba7af5f..3813c1def 100644 --- a/packages/editor/src/ui/editor/extensions/slash-command.tsx +++ b/packages/editor/core/src/ui/extensions/slash-command.tsx @@ -17,7 +17,7 @@ import { ImageIcon, Table, } from "lucide-react"; -import { startImageUpload } from "@/ui/editor/plugins/upload-image"; +import { startImageUpload } from "@/ui/plugins/upload-image"; import { cn } from "@/lib/utils"; import { UploadImage } from "@/types/upload-image"; diff --git a/packages/editor/src/ui/editor/extensions/table/table-cell.ts b/packages/editor/core/src/ui/extensions/table/table-cell.ts similarity index 100% rename from packages/editor/src/ui/editor/extensions/table/table-cell.ts rename to packages/editor/core/src/ui/extensions/table/table-cell.ts diff --git a/packages/editor/src/ui/editor/extensions/table/table-header.ts b/packages/editor/core/src/ui/extensions/table/table-header.ts similarity index 100% rename from packages/editor/src/ui/editor/extensions/table/table-header.ts rename to packages/editor/core/src/ui/extensions/table/table-header.ts diff --git a/packages/editor/src/ui/editor/extensions/table/table.ts b/packages/editor/core/src/ui/extensions/table/table.ts similarity index 100% rename from packages/editor/src/ui/editor/extensions/table/table.ts rename to packages/editor/core/src/ui/extensions/table/table.ts diff --git a/packages/editor/src/ui/editor/index.tsx b/packages/editor/core/src/ui/index.tsx similarity index 85% rename from packages/editor/src/ui/editor/index.tsx rename to packages/editor/core/src/ui/index.tsx index 286768f51..7eb332a43 100644 --- a/packages/editor/src/ui/editor/index.tsx +++ b/packages/editor/core/src/ui/index.tsx @@ -3,11 +3,11 @@ import * as React from 'react'; import { useImperativeHandle, useRef, forwardRef } from "react"; import { useEditor, EditorContent, Editor } from "@tiptap/react"; import { useDebouncedCallback } from "use-debounce"; -import { TableMenu } from '@/ui/editor/menus/table-menu'; -import { TiptapExtensions } from '@/ui/editor/extensions'; -import { EditorBubbleMenu } from '@/ui/editor/menus/bubble-menu'; -import { ImageResizer } from '@/ui/editor/extensions/image/image-resize'; -import { TiptapEditorProps } from '@/ui/editor/props'; +import { TableMenu } from '@/ui/menus/table-menu'; +import { TiptapExtensions } from '@/ui/extensions'; +import { EditorBubbleMenu } from '@/ui/menus/bubble-menu'; +import { ImageResizer } from '@/ui/extensions/image/image-resize'; +import { TiptapEditorProps } from '@/ui/props'; import { UploadImage } from '@/types/upload-image'; import { DeleteImage } from '@/types/delete-image'; import { cn } from '@/lib/utils'; @@ -28,6 +28,13 @@ interface ITiptapEditor { editable?: boolean; forwardedRef?: any; debouncedUpdatesEnabled?: boolean; + accessValue: string; + onAccessChange: (accessKey: string) => void; + commentAccess: { + icon: string; + key: string; + label: "Private" | "Public"; + }[]; } interface TiptapProps extends ITiptapEditor { @@ -56,6 +63,9 @@ const TiptapEditor = ({ borderOnFocus, customClassName, forwardedRef, + accessValue, + onAccessChange, + commentAccess, }: TiptapProps) => { const editor = useEditor({ editable: editable ?? true, @@ -117,8 +127,8 @@ const TiptapEditor = ({ {editor?.isActive("image") && } {editor && editable !== false && - (
- + (
+
) }
diff --git a/packages/editor/src/ui/editor/menus/bubble-menu/index.tsx b/packages/editor/core/src/ui/menus/bubble-menu/index.tsx similarity index 100% rename from packages/editor/src/ui/editor/menus/bubble-menu/index.tsx rename to packages/editor/core/src/ui/menus/bubble-menu/index.tsx diff --git a/packages/editor/src/ui/editor/menus/bubble-menu/link-selector.tsx b/packages/editor/core/src/ui/menus/bubble-menu/link-selector.tsx similarity index 97% rename from packages/editor/src/ui/editor/menus/bubble-menu/link-selector.tsx rename to packages/editor/core/src/ui/menus/bubble-menu/link-selector.tsx index 4f8284506..f3730c4dc 100644 --- a/packages/editor/src/ui/editor/menus/bubble-menu/link-selector.tsx +++ b/packages/editor/core/src/ui/menus/bubble-menu/link-selector.tsx @@ -2,7 +2,7 @@ import { cn } from "@/lib/utils"; import { Editor } from "@tiptap/core"; import { Check, Trash } from "lucide-react"; import { Dispatch, FC, SetStateAction, useCallback, useEffect, useRef } from "react"; -import isValidHttpUrl from "@/ui/editor/menus/bubble-menu/utils"; +import isValidHttpUrl from "@/ui/menus/bubble-menu/utils"; interface LinkSelectorProps { editor: Editor; diff --git a/packages/editor/src/ui/editor/menus/bubble-menu/node-selector.tsx b/packages/editor/core/src/ui/menus/bubble-menu/node-selector.tsx similarity index 100% rename from packages/editor/src/ui/editor/menus/bubble-menu/node-selector.tsx rename to packages/editor/core/src/ui/menus/bubble-menu/node-selector.tsx diff --git a/packages/editor/src/ui/editor/menus/bubble-menu/utils/index.tsx b/packages/editor/core/src/ui/menus/bubble-menu/utils/index.tsx similarity index 100% rename from packages/editor/src/ui/editor/menus/bubble-menu/utils/index.tsx rename to packages/editor/core/src/ui/menus/bubble-menu/utils/index.tsx diff --git a/packages/editor/core/src/ui/menus/fixed-menu/icon.tsx b/packages/editor/core/src/ui/menus/fixed-menu/icon.tsx new file mode 100644 index 000000000..c0006b3f2 --- /dev/null +++ b/packages/editor/core/src/ui/menus/fixed-menu/icon.tsx @@ -0,0 +1,13 @@ +import React from "react"; + +type Props = { + iconName: string; + className?: string; +}; + +export const Icon: React.FC = ({ iconName, className = "" }) => ( + + {iconName} + +); + diff --git a/packages/editor/src/ui/editor/menus/fixed-menu/index.tsx b/packages/editor/core/src/ui/menus/fixed-menu/index.tsx similarity index 59% rename from packages/editor/src/ui/editor/menus/fixed-menu/index.tsx rename to packages/editor/core/src/ui/menus/fixed-menu/index.tsx index 31a7ad90d..7d00b65e6 100644 --- a/packages/editor/src/ui/editor/menus/fixed-menu/index.tsx +++ b/packages/editor/core/src/ui/menus/fixed-menu/index.tsx @@ -1,8 +1,9 @@ -import { BubbleMenu, BubbleMenuProps } from "@tiptap/react"; -import { FC, useState } from "react"; +import { Editor } from "@tiptap/react"; import { BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, CodeIcon } from "lucide-react"; import { cn } from "@/lib/utils"; +import { Tooltip } from "../table-menu/tooltip"; +import { Icon } from "./icon"; export interface BubbleMenuItem { name: string; @@ -11,9 +12,18 @@ export interface BubbleMenuItem { icon: typeof BoldIcon; } -type EditorBubbleMenuProps = Omit; +type EditorBubbleMenuProps = { + editor: Editor; + accessValue: string; + onAccessChange: (accessKey: string) => void; + commentAccess: { + icon: string; + key: string; + label: "Private" | "Public"; + }[] | undefined; +} -export const FixedMenu: FC = (props: any) => { +export const FixedMenu = (props: EditorBubbleMenuProps) => { const items: BubbleMenuItem[] = [ { name: "bold", @@ -47,12 +57,36 @@ export const FixedMenu: FC = (props: any) => { }, ]; + const handleAccessChange = (accessKey: string) => { + props.onAccessChange(accessKey); + }; + return (
+
+ {props?.commentAccess?.map((access) => ( + + + + ))} +
{items.map((item, index) => ( - - ))} - - ); -}; diff --git a/packages/editor/src/ui/editor/props.tsx b/packages/editor/src/ui/editor/props.tsx deleted file mode 100644 index ff5b2f11b..000000000 --- a/packages/editor/src/ui/editor/props.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { EditorProps } from "@tiptap/pm/view"; -import { findTableAncestor } from "@/ui/editor/menus/table-menu"; -import { startImageUpload } from "@/ui/editor/plugins/upload-image"; -import { UploadImage } from "@/types/upload-image"; - -export function TiptapEditorProps( - workspaceSlug: string, - uploadFile: UploadImage, - setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void -): EditorProps { - return { - attributes: { - class: `prose prose-brand max-w-full prose-headings:font-display font-default focus:outline-none`, - }, - handleDOMEvents: { - keydown: (_view, event) => { - // prevent default event listeners from firing when slash command is active - if (["ArrowUp", "ArrowDown", "Enter"].includes(event.key)) { - const slashCommand = document.querySelector("#slash-command"); - if (slashCommand) { - return true; - } - } - }, - }, - handlePaste: (view, event) => { - if (typeof window !== "undefined") { - const selection: any = window?.getSelection(); - if (selection.rangeCount !== 0) { - const range = selection.getRangeAt(0); - if (findTableAncestor(range.startContainer)) { - return; - } - } - } - if (event.clipboardData && event.clipboardData.files && event.clipboardData.files[0]) { - event.preventDefault(); - const file = event.clipboardData.files[0]; - const pos = view.state.selection.from; - startImageUpload(file, view, pos, workspaceSlug, uploadFile, setIsSubmitting); - return true; - } - return false; - }, - handleDrop: (view, event, _slice, moved) => { - if (typeof window !== "undefined") { - const selection: any = window?.getSelection(); - if (selection.rangeCount !== 0) { - const range = selection.getRangeAt(0); - if (findTableAncestor(range.startContainer)) { - return; - } - } - } - if (!moved && event.dataTransfer && event.dataTransfer.files && event.dataTransfer.files[0]) { - event.preventDefault(); - const file = event.dataTransfer.files[0]; - const coordinates = view.posAtCoords({ - left: event.clientX, - top: event.clientY, - }); - // here we deduct 1 from the pos or else the image will create an extra node - if (coordinates) { - startImageUpload(file, view, coordinates.pos - 1, workspaceSlug, uploadFile, setIsSubmitting); - } - return true; - } - return false; - }, - }; -} diff --git a/packages/editor/src/ui/light-editor/extensions/image/image-resize.tsx b/packages/editor/src/ui/light-editor/extensions/image/image-resize.tsx deleted file mode 100644 index 448b8811c..000000000 --- a/packages/editor/src/ui/light-editor/extensions/image/image-resize.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { Editor } from "@tiptap/react"; -import Moveable from "react-moveable"; - -export const ImageResizer = ({ editor }: { editor: Editor }) => { - const updateMediaSize = () => { - const imageInfo = document.querySelector(".ProseMirror-selectednode") as HTMLImageElement; - if (imageInfo) { - const selection = editor.state.selection; - editor.commands.setImage({ - src: imageInfo.src, - width: Number(imageInfo.style.width.replace("px", "")), - height: Number(imageInfo.style.height.replace("px", "")), - } as any); - editor.commands.setNodeSelection(selection.from); - } - }; - - return ( - <> - { - delta[0] && (target!.style.width = `${width}px`); - delta[1] && (target!.style.height = `${height}px`); - }} - onResizeEnd={() => { - updateMediaSize(); - }} - scalable={true} - renderDirections={["w", "e"]} - onScale={({ target, transform }: any) => { - target!.style.transform = transform; - }} - /> - - ); -}; diff --git a/packages/editor/src/ui/light-editor/extensions/slash-command.tsx b/packages/editor/src/ui/light-editor/extensions/slash-command.tsx deleted file mode 100644 index 4fba7af5f..000000000 --- a/packages/editor/src/ui/light-editor/extensions/slash-command.tsx +++ /dev/null @@ -1,365 +0,0 @@ -import { useState, useEffect, useCallback, ReactNode, useRef, useLayoutEffect } from "react"; -import { Editor, Range, Extension } from "@tiptap/core"; -import Suggestion from "@tiptap/suggestion"; -import { ReactRenderer } from "@tiptap/react"; -import tippy from "tippy.js"; -import { - Heading1, - Heading2, - Heading3, - List, - ListOrdered, - Text, - TextQuote, - Code, - MinusSquare, - CheckSquare, - ImageIcon, - Table, -} from "lucide-react"; -import { startImageUpload } from "@/ui/editor/plugins/upload-image"; -import { cn } from "@/lib/utils"; -import { UploadImage } from "@/types/upload-image"; - -interface CommandItemProps { - title: string; - description: string; - icon: ReactNode; -} - -interface CommandProps { - editor: Editor; - range: Range; -} - -const Command = Extension.create({ - name: "slash-command", - addOptions() { - return { - suggestion: { - char: "/", - command: ({ editor, range, props }: { editor: Editor; range: Range; props: any }) => { - props.command({ editor, range }); - }, - }, - }; - }, - addProseMirrorPlugins() { - return [ - Suggestion({ - editor: this.editor, - allow({ editor }) { - return !editor.isActive("table"); - }, - ...this.options.suggestion, - }), - ]; - }, -}); - -const getSuggestionItems = - ( - workspaceSlug: string, - uploadFile: UploadImage, - setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void - ) => - ({ query }: { query: string }) => - [ - { - title: "Text", - description: "Just start typing with plain text.", - searchTerms: ["p", "paragraph"], - icon: , - command: ({ editor, range }: CommandProps) => { - editor.chain().focus().deleteRange(range).toggleNode("paragraph", "paragraph").run(); - }, - }, - { - title: "Heading 1", - description: "Big section heading.", - searchTerms: ["title", "big", "large"], - icon: , - command: ({ editor, range }: CommandProps) => { - editor.chain().focus().deleteRange(range).setNode("heading", { level: 1 }).run(); - }, - }, - { - title: "Heading 2", - description: "Medium section heading.", - searchTerms: ["subtitle", "medium"], - icon: , - command: ({ editor, range }: CommandProps) => { - editor.chain().focus().deleteRange(range).setNode("heading", { level: 2 }).run(); - }, - }, - { - title: "Heading 3", - description: "Small section heading.", - searchTerms: ["subtitle", "small"], - icon: , - command: ({ editor, range }: CommandProps) => { - editor.chain().focus().deleteRange(range).setNode("heading", { level: 3 }).run(); - }, - }, - { - title: "To-do List", - description: "Track tasks with a to-do list.", - searchTerms: ["todo", "task", "list", "check", "checkbox"], - icon: , - command: ({ editor, range }: CommandProps) => { - editor.chain().focus().deleteRange(range).toggleTaskList().run(); - }, - }, - { - title: "Bullet List", - description: "Create a simple bullet list.", - searchTerms: ["unordered", "point"], - icon: , - command: ({ editor, range }: CommandProps) => { - // @ts-ignore - editor.chain().focus().deleteRange(range).toggleBulletList().run(); - }, - }, - { - title: "Divider", - description: "Visually divide blocks", - searchTerms: ["line", "divider", "horizontal", "rule", "separate"], - icon: , - command: ({ editor, range }: CommandProps) => { - 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.", - searchTerms: ["ordered"], - icon: , - command: ({ editor, range }: CommandProps) => { - // @ts-ignore - editor.chain().focus().deleteRange(range).toggleOrderedList().run(); - }, - }, - { - title: "Quote", - description: "Capture a quote.", - searchTerms: ["blockquote"], - icon: , - command: ({ editor, range }: CommandProps) => - // @ts-ignore - editor.chain().focus().deleteRange(range).toggleNode("paragraph", "paragraph").toggleBlockquote().run(), - }, - { - title: "Code", - description: "Capture a code snippet.", - searchTerms: ["codeblock"], - icon: , - command: ({ editor, range }: CommandProps) => - editor.chain().focus().deleteRange(range).toggleCodeBlock().run(), - }, - { - title: "Image", - description: "Upload an image from your computer.", - searchTerms: ["photo", "picture", "media"], - icon: , - command: ({ editor, range }: CommandProps) => { - editor.chain().focus().deleteRange(range).run(); - // upload image - const input = document.createElement("input"); - input.type = "file"; - input.accept = "image/*"; - input.onchange = async () => { - if (input.files?.length) { - const file = input.files[0]; - const pos = editor.view.state.selection.from; - startImageUpload(file, editor.view, pos, workspaceSlug, uploadFile, setIsSubmitting); - } - }; - input.click(); - }, - }, - ].filter((item) => { - if (typeof query === "string" && query.length > 0) { - const search = query.toLowerCase(); - return ( - item.title.toLowerCase().includes(search) || - item.description.toLowerCase().includes(search) || - (item.searchTerms && item.searchTerms.some((term: string) => term.includes(search))) - ); - } - return true; - }); - -export const updateScrollView = (container: HTMLElement, item: HTMLElement) => { - const containerHeight = container.offsetHeight; - const itemHeight = item ? item.offsetHeight : 0; - - const top = item.offsetTop; - const bottom = top + itemHeight; - - if (top < container.scrollTop) { - container.scrollTop -= container.scrollTop - top + 5; - } else if (bottom > containerHeight + container.scrollTop) { - container.scrollTop += bottom - containerHeight - container.scrollTop + 5; - } -}; - -const CommandList = ({ - items, - command, -}: { - items: CommandItemProps[]; - command: any; - editor: any; - range: any; -}) => { - const [selectedIndex, setSelectedIndex] = useState(0); - - const selectItem = useCallback( - (index: number) => { - const item = items[index]; - if (item) { - command(item); - } - }, - [command, items] - ); - - useEffect(() => { - const navigationKeys = ["ArrowUp", "ArrowDown", "Enter"]; - const onKeyDown = (e: KeyboardEvent) => { - if (navigationKeys.includes(e.key)) { - e.preventDefault(); - if (e.key === "ArrowUp") { - setSelectedIndex((selectedIndex + items.length - 1) % items.length); - return true; - } - if (e.key === "ArrowDown") { - setSelectedIndex((selectedIndex + 1) % items.length); - return true; - } - if (e.key === "Enter") { - selectItem(selectedIndex); - return true; - } - return false; - } - }; - document.addEventListener("keydown", onKeyDown); - return () => { - document.removeEventListener("keydown", onKeyDown); - }; - }, [items, selectedIndex, setSelectedIndex, selectItem]); - - useEffect(() => { - setSelectedIndex(0); - }, [items]); - - const commandListContainer = useRef(null); - - useLayoutEffect(() => { - const container = commandListContainer?.current; - - const item = container?.children[selectedIndex] as HTMLElement; - - if (item && container) updateScrollView(container, item); - }, [selectedIndex]); - - return items.length > 0 ? ( -
- {items.map((item: CommandItemProps, index: number) => ( - - ))} -
- ) : null; -}; - -const renderItems = () => { - let component: ReactRenderer | null = null; - let popup: any | null = null; - - return { - onStart: (props: { editor: Editor; clientRect: DOMRect }) => { - component = new ReactRenderer(CommandList, { - props, - editor: props.editor, - }); - - // @ts-ignore - popup = tippy("body", { - getReferenceClientRect: props.clientRect, - appendTo: () => document.querySelector("#tiptap-container"), - content: component.element, - showOnCreate: true, - interactive: true, - trigger: "manual", - placement: "bottom-start", - }); - }, - onUpdate: (props: { editor: Editor; clientRect: DOMRect }) => { - component?.updateProps(props); - - popup && - popup[0].setProps({ - getReferenceClientRect: props.clientRect, - }); - }, - onKeyDown: (props: { event: KeyboardEvent }) => { - if (props.event.key === "Escape") { - popup?.[0].hide(); - - return true; - } - - // @ts-ignore - return component?.ref?.onKeyDown(props); - }, - onExit: () => { - popup?.[0].destroy(); - component?.destroy(); - }, - }; -}; - -export const SlashCommand = ( - workspaceSlug: string, - uploadFile: UploadImage, - setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void -) => - Command.configure({ - suggestion: { - items: getSuggestionItems(workspaceSlug, uploadFile, setIsSubmitting), - render: renderItems, - }, - }); - -export default SlashCommand; diff --git a/packages/editor/src/ui/light-editor/extensions/table/table-cell.ts b/packages/editor/src/ui/light-editor/extensions/table/table-cell.ts deleted file mode 100644 index 643cb8c64..000000000 --- a/packages/editor/src/ui/light-editor/extensions/table/table-cell.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { TableCell } from "@tiptap/extension-table-cell"; - -export const CustomTableCell = TableCell.extend({ - addAttributes() { - return { - ...this.parent?.(), - isHeader: { - default: false, - parseHTML: (element) => { - isHeader: element.tagName === "TD"; - }, - renderHTML: (attributes) => { - tag: attributes.isHeader ? "th" : "td"; - }, - }, - }; - }, - renderHTML({ HTMLAttributes }) { - if (HTMLAttributes.isHeader) { - return [ - "th", - { - ...HTMLAttributes, - class: `relative ${HTMLAttributes.class}`, - }, - ["span", { class: "absolute top-0 right-0" }], - 0, - ]; - } - return ["td", HTMLAttributes, 0]; - }, -}); diff --git a/packages/editor/src/ui/light-editor/extensions/table/table-header.ts b/packages/editor/src/ui/light-editor/extensions/table/table-header.ts deleted file mode 100644 index f23aa93ef..000000000 --- a/packages/editor/src/ui/light-editor/extensions/table/table-header.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { TableHeader as BaseTableHeader } from "@tiptap/extension-table-header"; - -const TableHeader = BaseTableHeader.extend({ - content: "paragraph", -}); - -export { TableHeader }; diff --git a/packages/editor/src/ui/light-editor/extensions/table/table.ts b/packages/editor/src/ui/light-editor/extensions/table/table.ts deleted file mode 100644 index 9b727bb51..000000000 --- a/packages/editor/src/ui/light-editor/extensions/table/table.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Table as BaseTable } from "@tiptap/extension-table"; - -const Table = BaseTable.configure({ - resizable: true, - cellMinWidth: 100, - allowTableNodeSelection: true, -}); - -export { Table }; diff --git a/packages/editor/src/ui/light-editor/index.tsx b/packages/editor/src/ui/light-editor/index.tsx deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/editor/src/ui/light-editor/menus/bubble-menu/index.tsx b/packages/editor/src/ui/light-editor/menus/bubble-menu/index.tsx deleted file mode 100644 index 9592cf617..000000000 --- a/packages/editor/src/ui/light-editor/menus/bubble-menu/index.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import { BubbleMenu, BubbleMenuProps } from "@tiptap/react"; -import { FC, useState } from "react"; -import { BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, CodeIcon } from "lucide-react"; - -import { NodeSelector } from "./node-selector"; -import { LinkSelector } from "./link-selector"; -import { cn } from "@/lib/utils"; - -export interface BubbleMenuItem { - name: string; - isActive: () => boolean; - command: () => void; - icon: typeof BoldIcon; -} - -type EditorBubbleMenuProps = Omit; - -export const EditorBubbleMenu: FC = (props: any) => { - const items: BubbleMenuItem[] = [ - { - name: "bold", - isActive: () => props.editor?.isActive("bold"), - command: () => props.editor?.chain().focus().toggleBold().run(), - icon: BoldIcon, - }, - { - name: "italic", - isActive: () => props.editor?.isActive("italic"), - command: () => props.editor?.chain().focus().toggleItalic().run(), - icon: ItalicIcon, - }, - { - name: "underline", - isActive: () => props.editor?.isActive("underline"), - command: () => props.editor?.chain().focus().toggleUnderline().run(), - icon: UnderlineIcon, - }, - { - name: "strike", - isActive: () => props.editor?.isActive("strike"), - command: () => props.editor?.chain().focus().toggleStrike().run(), - icon: StrikethroughIcon, - }, - { - name: "code", - isActive: () => props.editor?.isActive("code"), - command: () => props.editor?.chain().focus().toggleCode().run(), - icon: CodeIcon, - }, - ]; - - const bubbleMenuProps: EditorBubbleMenuProps = { - ...props, - shouldShow: ({ editor }) => { - if (!editor.isEditable) { - return false; - } - if (editor.isActive("image")) { - return false; - } - return editor.view.state.selection.content().size > 0; - }, - tippyOptions: { - moveTransition: "transform 0.15s ease-out", - onHidden: () => { - setIsNodeSelectorOpen(false); - setIsLinkSelectorOpen(false); - }, - }, - }; - - const [isNodeSelectorOpen, setIsNodeSelectorOpen] = useState(false); - const [isLinkSelectorOpen, setIsLinkSelectorOpen] = useState(false); - - return ( - - {!props.editor.isActive("table") && ( - { - setIsNodeSelectorOpen(!isNodeSelectorOpen); - setIsLinkSelectorOpen(false); - }} - /> - )} - { - setIsLinkSelectorOpen(!isLinkSelectorOpen); - setIsNodeSelectorOpen(false); - }} - /> -
- {items.map((item, index) => ( - - ))} -
-
- ); -}; diff --git a/packages/editor/src/ui/light-editor/menus/bubble-menu/link-selector.tsx b/packages/editor/src/ui/light-editor/menus/bubble-menu/link-selector.tsx deleted file mode 100644 index 4f8284506..000000000 --- a/packages/editor/src/ui/light-editor/menus/bubble-menu/link-selector.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import { cn } from "@/lib/utils"; -import { Editor } from "@tiptap/core"; -import { Check, Trash } from "lucide-react"; -import { Dispatch, FC, SetStateAction, useCallback, useEffect, useRef } from "react"; -import isValidHttpUrl from "@/ui/editor/menus/bubble-menu/utils"; - -interface LinkSelectorProps { - editor: Editor; - isOpen: boolean; - setIsOpen: Dispatch>; -} - -export const LinkSelector: FC = ({ editor, isOpen, setIsOpen }) => { - const inputRef = useRef(null); - - const onLinkSubmit = useCallback(() => { - const input = inputRef.current; - const url = input?.value; - if (url && isValidHttpUrl(url)) { - editor.chain().focus().setLink({ href: url }).run(); - setIsOpen(false); - } - }, [editor, inputRef, setIsOpen]); - - useEffect(() => { - inputRef.current && inputRef.current?.focus(); - }); - - return ( -
- - {isOpen && ( -
{ - if (e.key === "Enter") { - e.preventDefault(); - onLinkSubmit(); - } - }} - > - - {editor.getAttributes("link").href ? ( - - ) : ( - - )} -
- )} -
- ); -}; diff --git a/packages/editor/src/ui/light-editor/menus/bubble-menu/node-selector.tsx b/packages/editor/src/ui/light-editor/menus/bubble-menu/node-selector.tsx deleted file mode 100644 index 999184506..000000000 --- a/packages/editor/src/ui/light-editor/menus/bubble-menu/node-selector.tsx +++ /dev/null @@ -1,130 +0,0 @@ -import { cn } from "@/lib/utils"; -import { Editor } from "@tiptap/core"; -import { - Check, - ChevronDown, - Heading1, - Heading2, - Heading3, - TextQuote, - ListOrdered, - TextIcon, - Code, - CheckSquare, -} from "lucide-react"; -import { Dispatch, FC, SetStateAction } from "react"; - -import { BubbleMenuItem } from "."; - -interface NodeSelectorProps { - editor: Editor; - isOpen: boolean; - setIsOpen: Dispatch>; -} - -export const NodeSelector: FC = ({ editor, isOpen, setIsOpen }) => { - const items: BubbleMenuItem[] = [ - { - name: "Text", - icon: TextIcon, - command: () => editor.chain().focus().toggleNode("paragraph", "paragraph").run(), - isActive: () => - editor.isActive("paragraph") && - !editor.isActive("bulletList") && - !editor.isActive("orderedList"), - }, - { - name: "H1", - icon: Heading1, - command: () => editor.chain().focus().toggleHeading({ level: 1 }).run(), - isActive: () => editor.isActive("heading", { level: 1 }), - }, - { - name: "H2", - icon: Heading2, - command: () => editor.chain().focus().toggleHeading({ level: 2 }).run(), - isActive: () => editor.isActive("heading", { level: 2 }), - }, - { - name: "H3", - icon: Heading3, - command: () => editor.chain().focus().toggleHeading({ level: 3 }).run(), - isActive: () => editor.isActive("heading", { level: 3 }), - }, - { - name: "To-do List", - icon: CheckSquare, - command: () => editor.chain().focus().toggleTaskList().run(), - isActive: () => editor.isActive("taskItem"), - }, - { - name: "Bullet List", - icon: ListOrdered, - command: () => editor.chain().focus().toggleBulletList().run(), - isActive: () => editor.isActive("bulletList"), - }, - { - name: "Numbered List", - icon: ListOrdered, - command: () => editor.chain().focus().toggleOrderedList().run(), - isActive: () => editor.isActive("orderedList"), - }, - { - name: "Quote", - icon: TextQuote, - command: () => - editor.chain().focus().toggleNode("paragraph", "paragraph").toggleBlockquote().run(), - isActive: () => editor.isActive("blockquote"), - }, - { - name: "Code", - icon: Code, - command: () => editor.chain().focus().toggleCodeBlock().run(), - isActive: () => editor.isActive("codeBlock"), - }, - ]; - - const activeItem = items.filter((item) => item.isActive()).pop() ?? { - name: "Multiple", - }; - - return ( -
- - - {isOpen && ( -
- {items.map((item, index) => ( - - ))} -
- )} -
- ); -}; diff --git a/packages/editor/src/ui/light-editor/menus/bubble-menu/utils/index.tsx b/packages/editor/src/ui/light-editor/menus/bubble-menu/utils/index.tsx deleted file mode 100644 index b5add3f54..000000000 --- a/packages/editor/src/ui/light-editor/menus/bubble-menu/utils/index.tsx +++ /dev/null @@ -1,11 +0,0 @@ -export default function isValidHttpUrl(string: string): boolean { - let url: URL; - - try { - url = new URL(string); - } catch (_) { - return false; - } - - return url.protocol === "http:" || url.protocol === "https:"; -} diff --git a/packages/editor/src/ui/light-editor/menus/table-menu/InsertBottomTableIcon.tsx b/packages/editor/src/ui/light-editor/menus/table-menu/InsertBottomTableIcon.tsx deleted file mode 100644 index 0e42ba648..000000000 --- a/packages/editor/src/ui/light-editor/menus/table-menu/InsertBottomTableIcon.tsx +++ /dev/null @@ -1,16 +0,0 @@ -const InsertBottomTableIcon = (props: any) => ( - - - -); - -export default InsertBottomTableIcon; diff --git a/packages/editor/src/ui/light-editor/menus/table-menu/InsertLeftTableIcon.tsx b/packages/editor/src/ui/light-editor/menus/table-menu/InsertLeftTableIcon.tsx deleted file mode 100644 index 1fd75fe87..000000000 --- a/packages/editor/src/ui/light-editor/menus/table-menu/InsertLeftTableIcon.tsx +++ /dev/null @@ -1,15 +0,0 @@ -const InsertLeftTableIcon = (props: any) => ( - - - -); -export default InsertLeftTableIcon; diff --git a/packages/editor/src/ui/light-editor/menus/table-menu/InsertRightTableIcon.tsx b/packages/editor/src/ui/light-editor/menus/table-menu/InsertRightTableIcon.tsx deleted file mode 100644 index 1a6570969..000000000 --- a/packages/editor/src/ui/light-editor/menus/table-menu/InsertRightTableIcon.tsx +++ /dev/null @@ -1,16 +0,0 @@ -const InsertRightTableIcon = (props: any) => ( - - - -); - -export default InsertRightTableIcon; diff --git a/packages/editor/src/ui/light-editor/menus/table-menu/InsertTopTableIcon.tsx b/packages/editor/src/ui/light-editor/menus/table-menu/InsertTopTableIcon.tsx deleted file mode 100644 index 8f04f4f61..000000000 --- a/packages/editor/src/ui/light-editor/menus/table-menu/InsertTopTableIcon.tsx +++ /dev/null @@ -1,15 +0,0 @@ -const InsertTopTableIcon = (props: any) => ( - - - -); -export default InsertTopTableIcon; diff --git a/packages/editor/src/ui/light-editor/menus/table-menu/tooltip.tsx b/packages/editor/src/ui/light-editor/menus/table-menu/tooltip.tsx deleted file mode 100644 index f29d8a491..000000000 --- a/packages/editor/src/ui/light-editor/menus/table-menu/tooltip.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import * as React from 'react'; - -// next-themes -import { useTheme } from "next-themes"; -// tooltip2 -import { Tooltip2 } from "@blueprintjs/popover2"; - -type Props = { - tooltipHeading?: string; - tooltipContent: string | React.ReactNode; - position?: - | "top" - | "right" - | "bottom" - | "left" - | "auto" - | "auto-end" - | "auto-start" - | "bottom-left" - | "bottom-right" - | "left-bottom" - | "left-top" - | "right-bottom" - | "right-top" - | "top-left" - | "top-right"; - children: JSX.Element; - disabled?: boolean; - className?: string; - openDelay?: number; - closeDelay?: number; -}; - -export const Tooltip: React.FC = ({ - tooltipHeading, - tooltipContent, - position = "top", - children, - disabled = false, - className = "", - openDelay = 200, - closeDelay, -}) => { - const { theme } = useTheme(); - - return ( - - {tooltipHeading && ( -
- {tooltipHeading} -
- )} - {tooltipContent} - - } - position={position} - renderTarget={({ isOpen: isTooltipOpen, ref: eleReference, ...tooltipProps }) => - React.cloneElement(children, { ref: eleReference, ...tooltipProps, ...children.props }) - } - /> - ); -}; diff --git a/packages/editor/src/ui/light-editor/plugins/delete-image.tsx b/packages/editor/src/ui/light-editor/plugins/delete-image.tsx deleted file mode 100644 index 9204481a8..000000000 --- a/packages/editor/src/ui/light-editor/plugins/delete-image.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { EditorState, Plugin, PluginKey, Transaction } from "@tiptap/pm/state"; -import { Node as ProseMirrorNode } from "@tiptap/pm/model"; -import { DeleteImage } from "@/types/delete-image"; - -const deleteKey = new PluginKey("delete-image"); -const IMAGE_NODE_TYPE = "image"; - -interface ImageNode extends ProseMirrorNode { - attrs: { - src: string; - id: string; - }; -} - -const TrackImageDeletionPlugin = (deleteImage: DeleteImage): Plugin => - new Plugin({ - key: deleteKey, - appendTransaction: (transactions: readonly Transaction[], oldState: EditorState, newState: EditorState) => { - const newImageSources = new Set(); - newState.doc.descendants((node) => { - if (node.type.name === IMAGE_NODE_TYPE) { - newImageSources.add(node.attrs.src); - } - }); - - transactions.forEach((transaction) => { - if (!transaction.docChanged) return; - - const removedImages: ImageNode[] = []; - - oldState.doc.descendants((oldNode, oldPos) => { - if (oldNode.type.name !== IMAGE_NODE_TYPE) return; - if (oldPos < 0 || oldPos > newState.doc.content.size) return; - if (!newState.doc.resolve(oldPos).parent) return; - - const newNode = newState.doc.nodeAt(oldPos); - - // Check if the node has been deleted or replaced - if (!newNode || newNode.type.name !== IMAGE_NODE_TYPE) { - if (!newImageSources.has(oldNode.attrs.src)) { - removedImages.push(oldNode as ImageNode); - } - } - }); - - removedImages.forEach(async (node) => { - const src = node.attrs.src; - await onNodeDeleted(src, deleteImage); - }); - }); - - return null; - }, - }); - -export default TrackImageDeletionPlugin; - -async function onNodeDeleted(src: string, deleteImage: DeleteImage): Promise { - try { - const assetUrlWithWorkspaceId = new URL(src).pathname.substring(1); - const resStatus = await deleteImage(assetUrlWithWorkspaceId); - if (resStatus === 204) { - console.log("Image deleted successfully"); - } - } catch (error) { - console.error("Error deleting image: ", error); - } -} diff --git a/packages/editor/src/ui/light-editor/plugins/upload-image.tsx b/packages/editor/src/ui/light-editor/plugins/upload-image.tsx deleted file mode 100644 index 4c3bbf9a8..000000000 --- a/packages/editor/src/ui/light-editor/plugins/upload-image.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import { UploadImage } from "@/types/upload-image"; -import { EditorState, Plugin, PluginKey } from "@tiptap/pm/state"; -import { Decoration, DecorationSet, EditorView } from "@tiptap/pm/view"; - -const uploadKey = new PluginKey("upload-image"); - -const UploadImagesPlugin = () => - new Plugin({ - key: uploadKey, - state: { - init() { - return DecorationSet.empty; - }, - apply(tr, set) { - set = set.map(tr.mapping, tr.doc); - // See if the transaction adds or removes any placeholders - const action = tr.getMeta(uploadKey); - if (action && action.add) { - const { id, pos, src } = action.add; - - const placeholder = document.createElement("div"); - placeholder.setAttribute("class", "img-placeholder"); - const image = document.createElement("img"); - image.setAttribute("class", "opacity-10 rounded-lg border border-custom-border-300"); - image.src = src; - placeholder.appendChild(image); - const deco = Decoration.widget(pos + 1, placeholder, { - id, - }); - set = set.add(tr.doc, [deco]); - } else if (action && action.remove) { - set = set.remove(set.find(undefined, undefined, (spec) => spec.id == action.remove.id)); - } - return set; - }, - }, - props: { - decorations(state) { - return this.getState(state); - }, - }, - }); - -export default UploadImagesPlugin; - -function findPlaceholder(state: EditorState, id: {}) { - const decos = uploadKey.getState(state); - const found = decos.find( - undefined, - undefined, - (spec: { id: number | undefined }) => spec.id == id - ); - return found.length ? found[0].from : null; -} - -export async function startImageUpload( - file: File, - view: EditorView, - pos: number, - workspaceSlug: string, - uploadFile: UploadImage, - setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void -) { - if (!file.type.includes("image/")) { - return; - } - - const id = {}; - - const tr = view.state.tr; - if (!tr.selection.empty) tr.deleteSelection(); - - const reader = new FileReader(); - reader.readAsDataURL(file); - reader.onload = () => { - tr.setMeta(uploadKey, { - add: { - id, - pos, - src: reader.result, - }, - }); - view.dispatch(tr); - }; - - if (!workspaceSlug) { - return; - } - setIsSubmitting?.("submitting"); - const src = await UploadImageHandler(file, workspaceSlug, uploadFile); - const { schema } = view.state; - pos = findPlaceholder(view.state, id); - - if (pos == null) return; - const imageSrc = typeof src === "object" ? reader.result : src; - - const node = schema.nodes.image.create({ src: imageSrc }); - const transaction = view.state.tr - .replaceWith(pos, pos, node) - .setMeta(uploadKey, { remove: { id } }); - view.dispatch(transaction); -} - -const UploadImageHandler = (file: File, workspaceSlug: string, - uploadFile: UploadImage -): Promise => { - if (!workspaceSlug) { - return Promise.reject("Workspace slug is missing"); - } - try { - const formData = new FormData(); - formData.append("asset", file); - formData.append("attributes", JSON.stringify({})); - - return new Promise(async (resolve, reject) => { - try { - const imageUrl = await uploadFile(workspaceSlug, formData) - .then((response: { asset: string }) => response.asset); - - const image = new Image(); - image.src = imageUrl; - image.onload = () => { - resolve(imageUrl); - }; - } catch (error) { - if (error instanceof Error) { - console.log(error.message); - } - reject(error); - } - }); - } catch (error) { - if (error instanceof Error) { - console.log(error.message); - } - return Promise.reject(error); - } -}; diff --git a/web/components/issues/comment/add-comment.tsx b/web/components/issues/comment/add-comment.tsx index 78b38e1d3..76a45faa4 100644 --- a/web/components/issues/comment/add-comment.tsx +++ b/web/components/issues/comment/add-comment.tsx @@ -22,7 +22,12 @@ type Props = { showAccessSpecifier?: boolean; }; -const commentAccess = [ +type commentAccessType = { + icon: string; + key: string; + label: "Private" | "Public"; +} +const commentAccess: commentAccessType[] = [ { icon: "lock", key: "INTERNAL", @@ -67,51 +72,30 @@ export const AddComment: React.FC = ({
( -

" : value} - customClassName="p-3 min-h-[100px] shadow-sm" - debouncedUpdatesEnabled={false} - onChange={(comment_json: Object, comment_html: string) => onChange(comment_html)} + render={({ field: { onChange, value } }) => ( + ( +

" : commentValue} + customClassName="p-3 min-h-[100px] shadow-sm" + debouncedUpdatesEnabled={false} + onChange={(comment_json: Object, comment_html: string) => onCommentChange(comment_html)} + accessValue={value} + onAccessChange={onChange} + commentAccess={commentAccess} + /> + )} /> )} /> - {showAccessSpecifier && ( -
- ( -
- {commentAccess.map((access) => ( - - - - ))} -
- )} - /> -
- )}
diff --git a/yarn.lock b/yarn.lock index 9ec69da91..d92d076bf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2808,7 +2808,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^18.0.17": +"@types/react@*", "@types/react@18.0.15", "@types/react@18.0.28", "@types/react@18.2.0", "@types/react@^18.0.17": version "18.2.0" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.0.tgz#15cda145354accfc09a18d2f2305f9fc099ada21" integrity sha512-0FLj93y5USLHdnhIhABk83rm8XEGA7kH3cr+YUlvxoUGp1xNt/DINUMvqPxLyOQMzLmZe8i4RTHbvb8MC7NmrA== @@ -2817,24 +2817,6 @@ "@types/scheduler" "*" csstype "^3.0.2" -"@types/react@18.0.15": - version "18.0.15" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.15.tgz#d355644c26832dc27f3e6cbf0c4f4603fc4ab7fe" - integrity sha512-iz3BtLuIYH1uWdsv6wXYdhozhqj20oD4/Hk2DNXIn1kFsmp9x8d9QB6FnPhfkbhd2PgEONt9Q1x/ebkwjfFLow== - dependencies: - "@types/prop-types" "*" - "@types/scheduler" "*" - csstype "^3.0.2" - -"@types/react@18.0.28": - version "18.0.28" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.28.tgz#accaeb8b86f4908057ad629a26635fe641480065" - integrity sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew== - dependencies: - "@types/prop-types" "*" - "@types/scheduler" "*" - csstype "^3.0.2" - "@types/reactcss@*": version "1.2.6" resolved "https://registry.yarnpkg.com/@types/reactcss/-/reactcss-1.2.6.tgz#133c1e7e896f2726370d1d5a26bf06a30a038bcc"