From 0887b69149bcc15e143726455e84f42729458895 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Fri, 8 Sep 2023 18:41:40 +0530 Subject: [PATCH 01/57] initialized tiptap component with common tailwind config --- packages/editor/package.json | 85 ++++ packages/editor/postcss.config.js | 9 + packages/editor/src/README.md | 139 +++++++ packages/editor/src/index.tsx | 106 +++++ packages/editor/src/lib/utils.ts | 6 + packages/editor/src/style/editor.css | 231 +++++++++++ .../editor/extensions/image/image-resize.tsx | 44 +++ .../editor/extensions/image/updated-image.tsx | 22 ++ .../editor/src/ui/editor/extensions/index.tsx | 150 +++++++ .../ui/editor/extensions/slash-command.tsx | 365 ++++++++++++++++++ .../ui/editor/extensions/table/table-cell.ts | 32 ++ .../editor/extensions/table/table-header.ts | 7 + .../src/ui/editor/extensions/table/table.ts | 9 + .../src/ui/editor/menus/bubble-menu/index.tsx | 121 ++++++ .../menus/bubble-menu/link-selector.tsx | 92 +++++ .../menus/bubble-menu/node-selector.tsx | 130 +++++++ .../bubble-menu/utils/link-validator.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 + .../src/ui/editor/menus/table-menu/index.tsx | 143 +++++++ .../ui/editor/menus/table-menu/tooltip.tsx | 77 ++++ .../src/ui/editor/plugins/delete-image.tsx | 68 ++++ .../src/ui/editor/plugins/upload-image.tsx | 127 ++++++ packages/editor/src/ui/editor/props.tsx | 69 ++++ packages/editor/src/utils.ts | 6 + packages/editor/tailwind.config.js | 6 + packages/editor/tsconfig.json | 12 + packages/editor/tsup.config.ts | 14 + packages/tailwind-config/package.json | 15 + packages/tailwind-config/tailwind.config.js | 206 ++++++++++ 32 files changed, 2364 insertions(+) create mode 100644 packages/editor/package.json create mode 100644 packages/editor/postcss.config.js create mode 100644 packages/editor/src/README.md create mode 100644 packages/editor/src/index.tsx create mode 100644 packages/editor/src/lib/utils.ts create mode 100644 packages/editor/src/style/editor.css create mode 100644 packages/editor/src/ui/editor/extensions/image/image-resize.tsx create mode 100644 packages/editor/src/ui/editor/extensions/image/updated-image.tsx create mode 100644 packages/editor/src/ui/editor/extensions/index.tsx create mode 100644 packages/editor/src/ui/editor/extensions/slash-command.tsx create mode 100644 packages/editor/src/ui/editor/extensions/table/table-cell.ts create mode 100644 packages/editor/src/ui/editor/extensions/table/table-header.ts create mode 100644 packages/editor/src/ui/editor/extensions/table/table.ts create mode 100644 packages/editor/src/ui/editor/menus/bubble-menu/index.tsx create mode 100644 packages/editor/src/ui/editor/menus/bubble-menu/link-selector.tsx create mode 100644 packages/editor/src/ui/editor/menus/bubble-menu/node-selector.tsx create mode 100644 packages/editor/src/ui/editor/menus/bubble-menu/utils/link-validator.tsx create mode 100644 packages/editor/src/ui/editor/menus/table-menu/InsertBottomTableIcon.tsx create mode 100644 packages/editor/src/ui/editor/menus/table-menu/InsertLeftTableIcon.tsx create mode 100644 packages/editor/src/ui/editor/menus/table-menu/InsertRightTableIcon.tsx create mode 100644 packages/editor/src/ui/editor/menus/table-menu/InsertTopTableIcon.tsx create mode 100644 packages/editor/src/ui/editor/menus/table-menu/index.tsx create mode 100644 packages/editor/src/ui/editor/menus/table-menu/tooltip.tsx create mode 100644 packages/editor/src/ui/editor/plugins/delete-image.tsx create mode 100644 packages/editor/src/ui/editor/plugins/upload-image.tsx create mode 100644 packages/editor/src/ui/editor/props.tsx create mode 100644 packages/editor/src/utils.ts create mode 100644 packages/editor/tailwind.config.js create mode 100644 packages/editor/tsconfig.json create mode 100644 packages/editor/tsup.config.ts create mode 100644 packages/tailwind-config/package.json create mode 100644 packages/tailwind-config/tailwind.config.js diff --git a/packages/editor/package.json b/packages/editor/package.json new file mode 100644 index 00000000000..21861559145 --- /dev/null +++ b/packages/editor/package.json @@ -0,0 +1,85 @@ +{ + "name": "plane-editor", + "version": "0.0.1", + "description": "Rich Text Editor that powers Plane", + "main": "./dist/index.js", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "files": [ + "dist/**/*" + ], + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.mjs", + "module": "./dist/index.mjs", + "require": "./dist/index.js" + } + }, + "scripts": { + "build": "tsup", + "dev": "tsup --watch", + "check-types": "tsc --noEmit" + }, + "peerDependencies": { + "react": "^18.2.0" + }, + "dependencies": { + "@blueprintjs/popover2": "^2.0.10", + "@tiptap/core": "^2.1.7", + "@tiptap/extension-code-block-lowlight": "^2.0.4", + "@tiptap/extension-highlight": "^2.1.7", + "@tiptap/extension-horizontal-rule": "^2.1.7", + "@tiptap/extension-image": "^2.1.7", + "@tiptap/extension-link": "^2.1.7", + "@tiptap/extension-placeholder": "2.0.3", + "@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.1.7", + "@tiptap/extension-task-list": "^2.1.7", + "@tiptap/extension-text-style": "^2.1.7", + "@tiptap/extension-underline": "^2.1.7", + "@tiptap/pm": "^2.1.7", + "@tiptap/react": "^2.1.7", + "@tiptap/starter-kit": "^2.1.7", + "@tiptap/suggestion": "^2.1.7", + "@types/node": "18.15.3", + "@types/react": "18.0.28", + "@types/react-dom": "18.0.11", + "clsx": "^1.2.1", + "eslint": "8.36.0", + "eslint-config-next": "13.2.4", + "eventsource-parser": "^0.1.0", + "lowlight": "^2.9.0", + "lucide-react": "^0.244.0", + "next": "12.3.2", + "next-themes": "^0.2.1", + "react": "18.2.0", + "react-dom": "18.2.0", + "react-markdown": "^8.0.7", + "sonner": "^0.7.0", + "tailwind-merge": "^1.14.0", + "tippy.js": "^6.3.7", + "tiptap-markdown": "^0.8.2", + "use-debounce": "^9.0.4" + }, + "devDependencies": { + "@types/react": "^18.2.5", + "eslint": "^7.32.0", + "postcss": "^8.4.29", + "react": "^18.2.0", + "tailwind-config": "*", + "tsconfig": "*", + "tsup": "^7.2.0", + "typescript": "4.9.5" + }, + "keywords": [ + "editor", + "rich-text", + "markdown", + "nextjs", + "react" + ] +} diff --git a/packages/editor/postcss.config.js b/packages/editor/postcss.config.js new file mode 100644 index 00000000000..07aa434b2bf --- /dev/null +++ b/packages/editor/postcss.config.js @@ -0,0 +1,9 @@ +// If you want to use other PostCSS plugins, see the following: +// https://tailwindcss.com/docs/using-with-preprocessors + +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/packages/editor/src/README.md b/packages/editor/src/README.md new file mode 100644 index 00000000000..aa673e39f7d --- /dev/null +++ b/packages/editor/src/README.md @@ -0,0 +1,139 @@ + + This is the core engine that supports Rich Text Editing at Plane +

Plane's Editor

+
+ +

+ An open-source Notion-style WYSIWYG editor with AI-powered autocompletions. +

+ +

+ Hacker News + + License + + Novel.sh's GitHub repo +

+ +

+ Introduction · + Installation · + Deploy Your Own · + Setting Up Locally · + Tech Stack · + Contributing · + License +

+
+ +## Introduction + +[Novel](https://novel.sh/) is a Notion-style WYSIWYG editor with AI-powered autocompletions. + +https://github.com/steven-tey/novel/assets/28986134/2099877f-4f2b-4b1c-8782-5d803d63be5c + +
+ +## Installation + +To use Novel in a project, you can run the following command to install the `novel` [NPM package](https://www.npmjs.com/package/novel): + +``` +npm i novel +``` + +Then, you can use it in your code like this: + +```jsx +import { Editor } from "novel"; + +export default function App() { + return ; +} +``` + +The `Editor` is a React component that takes in the following props: + +| Prop | Type | Description | Default | +| ------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | +| `completionApi` | `string` | The API route to use for the OpenAI completion API. | `/api/generate` | +| `className` | `string` | Editor container classname. | `"relative min-h-[500px] w-full max-w-screen-lg border-stone-200 bg-white sm:mb-[calc(20vh)] sm:rounded-lg sm:border sm:shadow-lg"` | +| `defaultValue` | `JSONContent` or `string` | The default value to use for the editor. | [`defaultEditorContent`](https://github.com/steven-tey/novel/blob/main/packages/core/src/ui/editor/default-content.tsx) | +| `extensions` | `Extension[]` | A list of extensions to use for the editor, in addition to the [default Novel extensions](https://github.com/steven-tey/novel/blob/main/packages/core/src/ui/editor/extensions/index.tsx). | `[]` | +| `editorProps` | `EditorProps` | Props to pass to the underlying Tiptap editor, in addition to the [default Novel editor props](https://github.com/steven-tey/novel/blob/main/packages/core/src/ui/editor/props.ts). | `{}` | +| `onUpdate` | `(editor?: Editor) => void` | A callback function that is called whenever the editor is updated. | `() => {}` | +| `onDebouncedUpdate` | `(editor?: Editor) => void` | A callback function that is called whenever the editor is updated, but only after the defined debounce duration. | `() => {}` | +| `debounceDuration` | `number` | The duration (in milliseconds) to debounce the `onDebouncedUpdate` callback. | `750` | +| `storageKey` | `string` | The key to use for storing the editor's value in local storage. | `novel__content` | + +> **Note**: Make sure to define an API endpoint that matches the `completionApi` prop (default is `/api/generate`). This is needed for the AI autocompletions to work. Here's an example: https://github.com/steven-tey/novel/blob/main/apps/web/app/api/generate/route.ts + +Here's an example application: https://github.com/steven-tey/novella + +## Deploy Your Own + +You can deploy your own version of Novel to Vercel with one click: + +[![Deploy with Vercel](https://vercel.com/button)](https://stey.me/novel-deploy) + +## Setting Up Locally + +To set up Novel locally, you'll need to clone the repository and set up the following environment variables: + +- `OPENAI_API_KEY` – your OpenAI API key (you can get one [here](https://platform.openai.com/account/api-keys)) +- `BLOB_READ_WRITE_TOKEN` – your Vercel Blob read/write token (currently [still in beta](https://vercel.com/docs/storage/vercel-blob/quickstart#quickstart), but feel free to [sign up on this form](https://vercel.fyi/blob-beta) for access) + +If you've deployed this to Vercel, you can also use [`vc env pull`](https://vercel.com/docs/cli/env#exporting-development-environment-variables) to pull the environment variables from your Vercel project. + +To run the app locally, you can run the following commands: + +``` +pnpm i +pnpm build +pnpm dev +``` + +## Cross-framework support + +While Novel is built for React, we also have a few community-maintained packages for non-React frameworks: + +- Svelte: https://novel.sh/svelte +- Vue: https://novel.sh/vue + +## VSCode Extension + +Thanks to @bennykok, Novel also has a VSCode Extension: https://novel.sh/vscode + +https://github.com/steven-tey/novel/assets/28986134/58ebf7e3-cdb3-43df-878b-119e304f7373 + +## Tech Stack + +Novel is built on the following stack: + +- [Next.js](https://nextjs.org/) – framework +- [Tiptap](https://tiptap.dev/) – text editor +- [OpenAI](https://openai.com/) - AI completions +- [Vercel AI SDK](https://sdk.vercel.ai/docs) – AI library +- [Vercel](https://vercel.com) – deployments +- [TailwindCSS](https://tailwindcss.com/) – styles +- [Cal Sans](https://github.com/calcom/font) – font + +## Contributing + +Here's how you can contribute: + +- [Open an issue](https://github.com/steven-tey/novel/issues) if you believe you've encountered a bug. +- Make a [pull request](https://github.com/steven-tey/novel/pull) to add new features/make quality-of-life improvements/fix bugs. + + + + + +## Repo Activity + +![Novel.sh repo activity – generated by Axiom](https://repobeats.axiom.co/api/embed/2ebdaa143b0ad6e7c2ee23151da7b37f67da0b36.svg) + +## License + +Licensed under the [Apache-2.0 license](https://github.com/steven-tey/novel/blob/main/LICENSE.md). + diff --git a/packages/editor/src/index.tsx b/packages/editor/src/index.tsx new file mode 100644 index 00000000000..1a692d8d0bc --- /dev/null +++ b/packages/editor/src/index.tsx @@ -0,0 +1,106 @@ +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'; + +export interface ITipTapRichTextEditor { + value: string; + noBorder?: boolean; + borderOnFocus?: boolean; + customClassName?: string; + editorContentCustomClassNames?: string; + onChange?: (json: any, html: string) => void; + setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void; + setShouldShowAlert?: (showAlert: boolean) => void; + workspaceSlug: string; + editable?: boolean; + forwardedRef?: any; + debouncedUpdatesEnabled?: boolean; +} + +const Tiptap = (props: ITipTapRichTextEditor) => { + const { + onChange, + debouncedUpdatesEnabled, + forwardedRef, + editable, + setIsSubmitting, + setShouldShowAlert, + editorContentCustomClassNames, + value, + noBorder, + workspaceSlug, + borderOnFocus, + customClassName, + } = props; + + const editor = useEditor({ + editable: editable ?? true, + editorProps: TiptapEditorProps(workspaceSlug, setIsSubmitting), + extensions: TiptapExtensions(workspaceSlug, setIsSubmitting), + content: value, + onUpdate: async ({ editor }) => { + // for instant feedback loop + setIsSubmitting?.("submitting"); + setShouldShowAlert?.(true); + if (debouncedUpdatesEnabled) { + debouncedUpdates({ onChange, editor }); + } else { + onChange?.(editor.getJSON(), editor.getHTML()); + } + }, + }); + + const editorRef: React.MutableRefObject = useRef(null); + + useImperativeHandle(forwardedRef, () => ({ + clearEditor: () => { + editorRef.current?.commands.clearContent(); + }, + setEditorValue: (content: string) => { + editorRef.current?.commands.setContent(content); + }, + })); + + const debouncedUpdates = useDebouncedCallback(async ({ onChange, editor }) => { + setTimeout(async () => { + if (onChange) { + onChange(editor.getJSON(), editor.getHTML()); + } + }, 500); + }, 1000); + + const editorClassNames = `relative w-full max-w-full sm:rounded-lg mt-2 p-3 relative focus:outline-none rounded-md + ${noBorder ? "" : "border border-custom-border-200"} ${borderOnFocus ? "focus:border border-custom-border-300" : "focus:border-0" + } ${customClassName}`; + + if (!editor) return null; + editorRef.current = editor; + + return ( +
{ + editor?.chain().focus().run(); + }} + className={`tiptap-editor-container cursor-text ${editorClassNames}`} + > + {editor && } +
+ + + {editor?.isActive("image") && } +
+
+ ); +}; + +const TipTapEditor = forwardRef((props, ref) => ( + +)); + +TipTapEditor.displayName = "TipTapEditor"; + +export { TipTapEditor }; diff --git a/packages/editor/src/lib/utils.ts b/packages/editor/src/lib/utils.ts new file mode 100644 index 00000000000..a5ef193506d --- /dev/null +++ b/packages/editor/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/packages/editor/src/style/editor.css b/packages/editor/src/style/editor.css new file mode 100644 index 00000000000..9da250dd108 --- /dev/null +++ b/packages/editor/src/style/editor.css @@ -0,0 +1,231 @@ +.ProseMirror p.is-editor-empty:first-child::before { + content: attr(data-placeholder); + float: left; + color: rgb(var(--color-text-400)); + pointer-events: none; + height: 0; +} + +.ProseMirror .is-empty::before { + content: attr(data-placeholder); + float: left; + color: rgb(var(--color-text-400)); + pointer-events: none; + height: 0; +} + +/* Custom image styles */ + +.ProseMirror img { + transition: filter 0.1s ease-in-out; + + &:hover { + cursor: pointer; + filter: brightness(90%); + } + + &.ProseMirror-selectednode { + outline: 3px solid #5abbf7; + filter: brightness(90%); + } +} + +.ProseMirror-gapcursor:after { + border-top: 1px solid rgb(var(--color-text-100)) !important; +} + +/* Custom TODO list checkboxes – shoutout to this awesome tutorial: https://moderncss.dev/pure-css-custom-checkbox-style/ */ + +ul[data-type="taskList"] li > label { + margin-right: 0.2rem; + user-select: none; +} + +@media screen and (max-width: 768px) { + ul[data-type="taskList"] li > label { + margin-right: 0.5rem; + } +} + +ul[data-type="taskList"] li > label input[type="checkbox"] { + -webkit-appearance: none; + appearance: none; + background-color: rgb(var(--color-background-100)); + margin: 0; + cursor: pointer; + width: 1.2rem; + height: 1.2rem; + position: relative; + border: 2px solid rgb(var(--color-text-100)); + margin-right: 0.3rem; + display: grid; + place-content: center; + + &:hover { + background-color: rgb(var(--color-background-80)); + } + + &:active { + background-color: rgb(var(--color-background-90)); + } + + &::before { + content: ""; + width: 0.65em; + height: 0.65em; + transform: scale(0); + transition: 120ms transform ease-in-out; + box-shadow: inset 1em 1em; + transform-origin: center; + clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%); + } + + &:checked::before { + transform: scale(1); + } +} + +ul[data-type="taskList"] li[data-checked="true"] > div > p { + color: rgb(var(--color-text-200)); + text-decoration: line-through; + text-decoration-thickness: 2px; +} + +/* Overwrite tippy-box original max-width */ + +.tippy-box { + max-width: 400px !important; +} + +.ProseMirror { + position: relative; + word-wrap: break-word; + white-space: pre-wrap; + -moz-tab-size: 4; + tab-size: 4; + -webkit-user-select: text; + -moz-user-select: text; + -ms-user-select: text; + user-select: text; + outline: none; + cursor: text; + line-height: 1.2; + font-family: inherit; + font-size: 14px; + color: inherit; + -moz-box-sizing: border-box; + box-sizing: border-box; + appearance: textfield; + -webkit-appearance: textfield; + -moz-appearance: textfield; +} + +.fadeIn { + opacity: 1; + transition: opacity 0.3s ease-in; +} + +.fadeOut { + opacity: 0; + transition: opacity 0.2s ease-out; +} + +.img-placeholder { + position: relative; + width: 35%; + + &:before { + content: ""; + box-sizing: border-box; + position: absolute; + top: 50%; + left: 45%; + width: 20px; + height: 20px; + border-radius: 50%; + border: 3px solid rgba(var(--color-text-200)); + border-top-color: rgba(var(--color-text-800)); + animation: spinning 0.6s linear infinite; + } +} + +@keyframes spinning { + to { + transform: rotate(360deg); + } +} + +#tiptap-container { + table { + border-collapse: collapse; + table-layout: fixed; + margin: 0; + border: 1px solid rgb(var(--color-border-200)); + width: 100%; + + td, + th { + min-width: 1em; + border: 1px solid rgb(var(--color-border-200)); + 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-100)); + } + + 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; +} diff --git a/packages/editor/src/ui/editor/extensions/image/image-resize.tsx b/packages/editor/src/ui/editor/extensions/image/image-resize.tsx new file mode 100644 index 00000000000..448b8811cc1 --- /dev/null +++ b/packages/editor/src/ui/editor/extensions/image/image-resize.tsx @@ -0,0 +1,44 @@ +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/editor/extensions/image/updated-image.tsx b/packages/editor/src/ui/editor/extensions/image/updated-image.tsx new file mode 100644 index 00000000000..b620509535e --- /dev/null +++ b/packages/editor/src/ui/editor/extensions/image/updated-image.tsx @@ -0,0 +1,22 @@ +import Image from "@tiptap/extension-image"; +import TrackImageDeletionPlugin from "../plugins/delete-image"; +import UploadImagesPlugin from "../plugins/upload-image"; + +const UpdatedImage = Image.extend({ + addProseMirrorPlugins() { + return [UploadImagesPlugin(), TrackImageDeletionPlugin()]; + }, + addAttributes() { + return { + ...this.parent?.(), + width: { + default: "35%", + }, + height: { + default: null, + }, + }; + }, +}); + +export default UpdatedImage; diff --git a/packages/editor/src/ui/editor/extensions/index.tsx b/packages/editor/src/ui/editor/extensions/index.tsx new file mode 100644 index 00000000000..e13d83a09f3 --- /dev/null +++ b/packages/editor/src/ui/editor/extensions/index.tsx @@ -0,0 +1,150 @@ +import StarterKit from "@tiptap/starter-kit"; +import HorizontalRule from "@tiptap/extension-horizontal-rule"; +import TiptapLink from "@tiptap/extension-link"; +import Placeholder from "@tiptap/extension-placeholder"; +import TiptapUnderline from "@tiptap/extension-underline"; +import TextStyle from "@tiptap/extension-text-style"; +import { Color } from "@tiptap/extension-color"; +import TaskItem from "@tiptap/extension-task-item"; +import TaskList from "@tiptap/extension-task-list"; +import { Markdown } from "tiptap-markdown"; +import Highlight from "@tiptap/extension-highlight"; +import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight"; +import { lowlight } from "lowlight/lib/core"; +import { InputRule } from "@tiptap/core"; +import Gapcursor from "@tiptap/extension-gapcursor"; + +import ts from "highlight.js/lib/languages/typescript"; + +import "highlight.js/styles/github-dark.css"; +import UniqueID from "@tiptap-pro/extension-unique-id"; +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); + +export const TiptapExtensions = ( + workspaceSlug: string, + setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void +) => [ + StarterKit.configure({ + bulletList: { + HTMLAttributes: { + class: "list-disc list-outside leading-3 -mt-2", + }, + }, + orderedList: { + HTMLAttributes: { + class: "list-decimal list-outside leading-3 -mt-2", + }, + }, + listItem: { + HTMLAttributes: { + class: "leading-normal -mb-2", + }, + }, + blockquote: { + HTMLAttributes: { + class: "border-l-4 border-custom-border-300", + }, + }, + code: { + HTMLAttributes: { + class: + "rounded-md bg-custom-primary-30 mx-1 px-1 py-1 font-mono font-medium text-custom-text-1000", + spellcheck: "false", + }, + }, + codeBlock: false, + horizontalRule: false, + dropcursor: { + color: "rgba(var(--color-text-100))", + width: 2, + }, + gapcursor: false, + }), + CodeBlockLowlight.configure({ + lowlight, + }), + HorizontalRule.extend({ + addInputRules() { + return [ + new InputRule({ + find: /^(?:---|—-|___\s|\*\*\*\s)$/, + handler: ({ state, range, commands }) => { + commands.splitBlock(); + + const attributes = {}; + const { tr } = state; + const start = range.from; + const end = range.to; + // @ts-ignore + tr.replaceWith(start - 1, end, this.type.create(attributes)); + }, + }), + ]; + }, + }).configure({ + HTMLAttributes: { + class: "mb-6 border-t border-custom-border-300", + }, + }), + Gapcursor, + TiptapLink.configure({ + protocols: ["http", "https"], + validate: (url) => isValidHttpUrl(url), + HTMLAttributes: { + class: + "text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer", + }, + }), + UpdatedImage.configure({ + HTMLAttributes: { + class: "rounded-lg border border-custom-border-300", + }, + }), + Placeholder.configure({ + placeholder: ({ node }) => { + if (node.type.name === "heading") { + return `Heading ${node.attrs.level}`; + } + if (node.type.name === "image" || node.type.name === "table") { + return ""; + } + + return "Press '/' for commands..."; + }, + includeChildren: true, + }), + UniqueID.configure({ + types: ["image"], + }), + SlashCommand(workspaceSlug, setIsSubmitting), + TiptapUnderline, + TextStyle, + Color, + Highlight.configure({ + multicolor: true, + }), + TaskList.configure({ + HTMLAttributes: { + class: "not-prose pl-2", + }, + }), + TaskItem.configure({ + HTMLAttributes: { + class: "flex items-start my-4", + }, + nested: true, + }), + Markdown.configure({ + html: true, + transformCopiedText: true, + }), + Table, + TableHeader, + CustomTableCell, + TableRow, + ]; diff --git a/packages/editor/src/ui/editor/extensions/slash-command.tsx b/packages/editor/src/ui/editor/extensions/slash-command.tsx new file mode 100644 index 00000000000..9dd4d8f9366 --- /dev/null +++ b/packages/editor/src/ui/editor/extensions/slash-command.tsx @@ -0,0 +1,365 @@ +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 "../plugins/upload-image"; +import { cn } from "../utils"; + +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, + 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) => { + 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) => { + editor.chain().focus().deleteRange(range).toggleOrderedList().run(); + }, + }, + { + title: "Quote", + description: "Capture a quote.", + searchTerms: ["blockquote"], + icon: , + command: ({ editor, range }: CommandProps) => + 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, 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, + setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void +) => + Command.configure({ + suggestion: { + items: getSuggestionItems(workspaceSlug, setIsSubmitting), + render: renderItems, + }, + }); + +export default SlashCommand; diff --git a/packages/editor/src/ui/editor/extensions/table/table-cell.ts b/packages/editor/src/ui/editor/extensions/table/table-cell.ts new file mode 100644 index 00000000000..643cb8c64a7 --- /dev/null +++ b/packages/editor/src/ui/editor/extensions/table/table-cell.ts @@ -0,0 +1,32 @@ +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/editor/extensions/table/table-header.ts b/packages/editor/src/ui/editor/extensions/table/table-header.ts new file mode 100644 index 00000000000..f23aa93ef55 --- /dev/null +++ b/packages/editor/src/ui/editor/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/packages/editor/src/ui/editor/extensions/table/table.ts b/packages/editor/src/ui/editor/extensions/table/table.ts new file mode 100644 index 00000000000..9b727bb51bd --- /dev/null +++ b/packages/editor/src/ui/editor/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/packages/editor/src/ui/editor/menus/bubble-menu/index.tsx b/packages/editor/src/ui/editor/menus/bubble-menu/index.tsx new file mode 100644 index 00000000000..217317ea105 --- /dev/null +++ b/packages/editor/src/ui/editor/menus/bubble-menu/index.tsx @@ -0,0 +1,121 @@ +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 "../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/editor/menus/bubble-menu/link-selector.tsx b/packages/editor/src/ui/editor/menus/bubble-menu/link-selector.tsx new file mode 100644 index 00000000000..559521db66f --- /dev/null +++ b/packages/editor/src/ui/editor/menus/bubble-menu/link-selector.tsx @@ -0,0 +1,92 @@ +import { Editor } from "@tiptap/core"; +import { Check, Trash } from "lucide-react"; +import { Dispatch, FC, SetStateAction, useCallback, useEffect, useRef } from "react"; +import { cn } from "../utils"; +import isValidHttpUrl from "./utils/link-validator"; +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/editor/menus/bubble-menu/node-selector.tsx b/packages/editor/src/ui/editor/menus/bubble-menu/node-selector.tsx new file mode 100644 index 00000000000..34d40ec06d5 --- /dev/null +++ b/packages/editor/src/ui/editor/menus/bubble-menu/node-selector.tsx @@ -0,0 +1,130 @@ +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 "."; +import { cn } from "../utils"; + +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/editor/menus/bubble-menu/utils/link-validator.tsx b/packages/editor/src/ui/editor/menus/bubble-menu/utils/link-validator.tsx new file mode 100644 index 00000000000..9af366c0266 --- /dev/null +++ b/packages/editor/src/ui/editor/menus/bubble-menu/utils/link-validator.tsx @@ -0,0 +1,11 @@ +export default function isValidHttpUrl(string: string): boolean { + let url; + + try { + url = new URL(string); + } catch (_) { + return false; + } + + return url.protocol === "http:" || url.protocol === "https:"; +} diff --git a/packages/editor/src/ui/editor/menus/table-menu/InsertBottomTableIcon.tsx b/packages/editor/src/ui/editor/menus/table-menu/InsertBottomTableIcon.tsx new file mode 100644 index 00000000000..0e42ba64824 --- /dev/null +++ b/packages/editor/src/ui/editor/menus/table-menu/InsertBottomTableIcon.tsx @@ -0,0 +1,16 @@ +const InsertBottomTableIcon = (props: any) => ( + + + +); + +export default InsertBottomTableIcon; diff --git a/packages/editor/src/ui/editor/menus/table-menu/InsertLeftTableIcon.tsx b/packages/editor/src/ui/editor/menus/table-menu/InsertLeftTableIcon.tsx new file mode 100644 index 00000000000..1fd75fe8754 --- /dev/null +++ b/packages/editor/src/ui/editor/menus/table-menu/InsertLeftTableIcon.tsx @@ -0,0 +1,15 @@ +const InsertLeftTableIcon = (props: any) => ( + + + +); +export default InsertLeftTableIcon; diff --git a/packages/editor/src/ui/editor/menus/table-menu/InsertRightTableIcon.tsx b/packages/editor/src/ui/editor/menus/table-menu/InsertRightTableIcon.tsx new file mode 100644 index 00000000000..1a65709694b --- /dev/null +++ b/packages/editor/src/ui/editor/menus/table-menu/InsertRightTableIcon.tsx @@ -0,0 +1,16 @@ +const InsertRightTableIcon = (props: any) => ( + + + +); + +export default InsertRightTableIcon; diff --git a/packages/editor/src/ui/editor/menus/table-menu/InsertTopTableIcon.tsx b/packages/editor/src/ui/editor/menus/table-menu/InsertTopTableIcon.tsx new file mode 100644 index 00000000000..8f04f4f6126 --- /dev/null +++ b/packages/editor/src/ui/editor/menus/table-menu/InsertTopTableIcon.tsx @@ -0,0 +1,15 @@ +const InsertTopTableIcon = (props: any) => ( + + + +); +export default InsertTopTableIcon; diff --git a/packages/editor/src/ui/editor/menus/table-menu/index.tsx b/packages/editor/src/ui/editor/menus/table-menu/index.tsx new file mode 100644 index 00000000000..94f9c0f8d87 --- /dev/null +++ b/packages/editor/src/ui/editor/menus/table-menu/index.tsx @@ -0,0 +1,143 @@ +import { useState, useEffect } from "react"; +import { Rows, Columns, ToggleRight } from "lucide-react"; +import { cn } from "../utils"; +import { Tooltip } from "components/ui"; +import InsertLeftTableIcon from "./InsertLeftTableIcon"; +import InsertRightTableIcon from "./InsertRightTableIcon"; +import InsertTopTableIcon from "./InsertTopTableIcon"; +import InsertBottomTableIcon from "./InsertBottomTableIcon"; + +interface TableMenuItem { + command: () => void; + icon: any; + key: string; + name: string; +} + +export const findTableAncestor = (node: Node | null): HTMLTableElement | null => { + while (node !== null && node.nodeName !== "TABLE") { + node = node.parentNode; + } + return node as HTMLTableElement; +}; + +export const TableMenu = ({ editor }: { editor: any }) => { + const [tableLocation, setTableLocation] = useState({ bottom: 0, left: 0 }); + const isOpen = editor?.isActive("table"); + + const items: TableMenuItem[] = [ + { + command: () => editor.chain().focus().addColumnBefore().run(), + icon: InsertLeftTableIcon, + key: "insert-column-left", + name: "Insert 1 column left", + }, + { + command: () => editor.chain().focus().addColumnAfter().run(), + icon: InsertRightTableIcon, + key: "insert-column-right", + name: "Insert 1 column right", + }, + { + command: () => editor.chain().focus().addRowBefore().run(), + icon: InsertTopTableIcon, + key: "insert-row-above", + name: "Insert 1 row above", + }, + { + command: () => editor.chain().focus().addRowAfter().run(), + icon: InsertBottomTableIcon, + key: "insert-row-below", + name: "Insert 1 row below", + }, + { + command: () => editor.chain().focus().deleteColumn().run(), + icon: Columns, + key: "delete-column", + name: "Delete column", + }, + { + command: () => editor.chain().focus().deleteRow().run(), + icon: Rows, + key: "delete-row", + name: "Delete row", + }, + { + command: () => editor.chain().focus().toggleHeaderRow().run(), + icon: ToggleRight, + key: "toggle-header-row", + name: "Toggle header row", + }, + ]; + + useEffect(() => { + if (!window) return; + + const handleWindowClick = () => { + const selection: any = window?.getSelection(); + + if (selection.rangeCount !== 0) { + const range = selection.getRangeAt(0); + const tableNode = findTableAncestor(range.startContainer); + + let parent = tableNode?.parentElement; + + if (tableNode) { + const tableRect = tableNode.getBoundingClientRect(); + const tableCenter = tableRect.left + tableRect.width / 2; + const menuWidth = 45; + const menuLeft = tableCenter - menuWidth / 2; + const tableBottom = tableRect.bottom; + + setTableLocation({ bottom: tableBottom, left: menuLeft }); + + while (parent) { + if (!parent.classList.contains("disable-scroll")) + parent.classList.add("disable-scroll"); + parent = parent.parentElement; + } + } else { + const scrollDisabledContainers = document.querySelectorAll(".disable-scroll"); + + scrollDisabledContainers.forEach((container) => { + container.classList.remove("disable-scroll"); + }); + } + } + }; + + window.addEventListener("click", handleWindowClick); + + return () => { + window.removeEventListener("click", handleWindowClick); + }; + }, [tableLocation, editor]); + + return ( +
+ {items.map((item, index) => ( + + + + ))} +
+ ); +}; diff --git a/packages/editor/src/ui/editor/menus/table-menu/tooltip.tsx b/packages/editor/src/ui/editor/menus/table-menu/tooltip.tsx new file mode 100644 index 00000000000..f29d8a49177 --- /dev/null +++ b/packages/editor/src/ui/editor/menus/table-menu/tooltip.tsx @@ -0,0 +1,77 @@ +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/editor/plugins/delete-image.tsx b/packages/editor/src/ui/editor/plugins/delete-image.tsx new file mode 100644 index 00000000000..fdf515ccc99 --- /dev/null +++ b/packages/editor/src/ui/editor/plugins/delete-image.tsx @@ -0,0 +1,68 @@ +import { EditorState, Plugin, PluginKey, Transaction } from "@tiptap/pm/state"; +import { Node as ProseMirrorNode } from "@tiptap/pm/model"; +import fileService from "services/file.service"; + +const deleteKey = new PluginKey("delete-image"); +const IMAGE_NODE_TYPE = "image"; + +interface ImageNode extends ProseMirrorNode { + attrs: { + src: string; + id: string; + }; +} + +const TrackImageDeletionPlugin = (): 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); + }); + }); + + return null; + }, + }); + +export default TrackImageDeletionPlugin; + +async function onNodeDeleted(src: string): Promise { + try { + const assetUrlWithWorkspaceId = new URL(src).pathname.substring(1); + const resStatus = await fileService.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/editor/plugins/upload-image.tsx b/packages/editor/src/ui/editor/plugins/upload-image.tsx new file mode 100644 index 00000000000..bc0acdc540d --- /dev/null +++ b/packages/editor/src/ui/editor/plugins/upload-image.tsx @@ -0,0 +1,127 @@ +import { EditorState, Plugin, PluginKey } from "@tiptap/pm/state"; +import { Decoration, DecorationSet, EditorView } from "@tiptap/pm/view"; +import fileService from "services/file.service"; + +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, + 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); + 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): 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) => { + const imageUrl = await fileService + .uploadFile(workspaceSlug, formData) + .then((response) => response.asset); + + const image = new Image(); + image.src = imageUrl; + image.onload = () => { + resolve(imageUrl); + }; + }); + } catch (error) { + console.log(error); + return Promise.reject(error); + } +}; diff --git a/packages/editor/src/ui/editor/props.tsx b/packages/editor/src/ui/editor/props.tsx new file mode 100644 index 00000000000..9c478024b49 --- /dev/null +++ b/packages/editor/src/ui/editor/props.tsx @@ -0,0 +1,69 @@ +import { EditorProps } from "@tiptap/pm/view"; +import { findTableAncestor } from "@/ui/editor/menus/table-menu"; +import { startImageUpload } from "@/ui/editor/plugins/upload-image"; + +export function TiptapEditorProps( + workspaceSlug: string, + 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, 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, setIsSubmitting); + } + return true; + } + return false; + }, + }; +} diff --git a/packages/editor/src/utils.ts b/packages/editor/src/utils.ts new file mode 100644 index 00000000000..a5ef193506d --- /dev/null +++ b/packages/editor/src/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/packages/editor/tailwind.config.js b/packages/editor/tailwind.config.js new file mode 100644 index 00000000000..12079a19b40 --- /dev/null +++ b/packages/editor/tailwind.config.js @@ -0,0 +1,6 @@ +const sharedConfig = require("tailwind-config/tailwind.config.js"); + +module.exports = { + // prefix ui lib classes to avoid conflicting with the app + ...sharedConfig, +}; diff --git a/packages/editor/tsconfig.json b/packages/editor/tsconfig.json new file mode 100644 index 00000000000..8a6aeae90c2 --- /dev/null +++ b/packages/editor/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "tsconfig/react.json", + "include": ["."], + "exclude": ["dist", "build", "node_modules"], + "compilerOptions": { + "jsx": "react-jsx", + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + } + } +} diff --git a/packages/editor/tsup.config.ts b/packages/editor/tsup.config.ts new file mode 100644 index 00000000000..1173495ddbb --- /dev/null +++ b/packages/editor/tsup.config.ts @@ -0,0 +1,14 @@ +import { defineConfig, Options } from "tsup"; + +export default defineConfig((options: Options) => ({ + entry: ["src/index.ts"], + banner: { + js: "'use client'", + }, + format: ["cjs", "esm"], + dts: true, + clean: true, + external: ["react"], + injectStyle: true, + ...options, +})); diff --git a/packages/tailwind-config/package.json b/packages/tailwind-config/package.json new file mode 100644 index 00000000000..6d7dbbc7a41 --- /dev/null +++ b/packages/tailwind-config/package.json @@ -0,0 +1,15 @@ +{ + "name": "tailwind-config", + "version": "0.0.0", + "private": true, + "main": "index.js", + "devDependencies": { + "@tailwindcss/typography": "^0.5.9", + "autoprefixer": "^10.4.14", + "postcss": "^8.4.21", + "prettier": "^2.8.8", + "prettier-plugin-tailwindcss": "^0.3.0", + "tailwindcss": "^3.2.7", + "tailwindcss-animate": "^1.0.6" + } +} diff --git a/packages/tailwind-config/tailwind.config.js b/packages/tailwind-config/tailwind.config.js new file mode 100644 index 00000000000..0b7b5861aeb --- /dev/null +++ b/packages/tailwind-config/tailwind.config.js @@ -0,0 +1,206 @@ +const convertToRGB = (variableName) => `rgba(var(${variableName}))`; + +module.exports = { + darkMode: "class", + content: ["./pages/**/*.tsx", "./components/**/*.tsx", "./layouts/**/*.tsx", "./ui/**/*.tsx"], + theme: { + extend: { + boxShadow: { + "custom-shadow-2xs": "var(--color-shadow-2xs)", + "custom-shadow-xs": "var(--color-shadow-xs)", + "custom-shadow-sm": "var(--color-shadow-sm)", + "custom-shadow-rg": "var(--color-shadow-rg)", + "custom-shadow-md": "var(--color-shadow-md)", + "custom-shadow-lg": "var(--color-shadow-lg)", + "custom-shadow-xl": "var(--color-shadow-xl)", + "custom-shadow-2xl": "var(--color-shadow-2xl)", + "custom-shadow-3xl": "var(--color-shadow-3xl)", + "custom-sidebar-shadow-2xs": "var(--color-sidebar-shadow-2xs)", + "custom-sidebar-shadow-xs": "var(--color-sidebar-shadow-xs)", + "custom-sidebar-shadow-sm": "var(--color-sidebar-shadow-sm)", + "custom-sidebar-shadow-rg": "var(--color-sidebar-shadow-rg)", + "custom-sidebar-shadow-md": "var(--color-sidebar-shadow-md)", + "custom-sidebar-shadow-lg": "var(--color-sidebar-shadow-lg)", + "custom-sidebar-shadow-xl": "var(--color-sidebar-shadow-xl)", + "custom-sidebar-shadow-2xl": "var(--color-sidebar-shadow-2xl)", + "custom-sidebar-shadow-3xl": "var(--color-sidebar-shadow-3xl)", + }, + colors: { + custom: { + primary: { + 0: "rgb(255, 255, 255)", + 10: convertToRGB("--color-primary-10"), + 20: convertToRGB("--color-primary-20"), + 30: convertToRGB("--color-primary-30"), + 40: convertToRGB("--color-primary-40"), + 50: convertToRGB("--color-primary-50"), + 60: convertToRGB("--color-primary-60"), + 70: convertToRGB("--color-primary-70"), + 80: convertToRGB("--color-primary-80"), + 90: convertToRGB("--color-primary-90"), + 100: convertToRGB("--color-primary-100"), + 200: convertToRGB("--color-primary-200"), + 300: convertToRGB("--color-primary-300"), + 400: convertToRGB("--color-primary-400"), + 500: convertToRGB("--color-primary-500"), + 600: convertToRGB("--color-primary-600"), + 700: convertToRGB("--color-primary-700"), + 800: convertToRGB("--color-primary-800"), + 900: convertToRGB("--color-primary-900"), + 1000: "rgb(0, 0, 0)", + DEFAULT: convertToRGB("--color-primary-100"), + }, + background: { + 0: "rgb(255, 255, 255)", + 10: convertToRGB("--color-background-10"), + 20: convertToRGB("--color-background-20"), + 30: convertToRGB("--color-background-30"), + 40: convertToRGB("--color-background-40"), + 50: convertToRGB("--color-background-50"), + 60: convertToRGB("--color-background-60"), + 70: convertToRGB("--color-background-70"), + 80: convertToRGB("--color-background-80"), + 90: convertToRGB("--color-background-90"), + 100: convertToRGB("--color-background-100"), + 200: convertToRGB("--color-background-200"), + 300: convertToRGB("--color-background-300"), + 400: convertToRGB("--color-background-400"), + 500: convertToRGB("--color-background-500"), + 600: convertToRGB("--color-background-600"), + 700: convertToRGB("--color-background-700"), + 800: convertToRGB("--color-background-800"), + 900: convertToRGB("--color-background-900"), + 1000: "rgb(0, 0, 0)", + DEFAULT: convertToRGB("--color-background-100"), + }, + text: { + 0: "rgb(255, 255, 255)", + 10: convertToRGB("--color-text-10"), + 20: convertToRGB("--color-text-20"), + 30: convertToRGB("--color-text-30"), + 40: convertToRGB("--color-text-40"), + 50: convertToRGB("--color-text-50"), + 60: convertToRGB("--color-text-60"), + 70: convertToRGB("--color-text-70"), + 80: convertToRGB("--color-text-80"), + 90: convertToRGB("--color-text-90"), + 100: convertToRGB("--color-text-100"), + 200: convertToRGB("--color-text-200"), + 300: convertToRGB("--color-text-300"), + 400: convertToRGB("--color-text-400"), + 500: convertToRGB("--color-text-500"), + 600: convertToRGB("--color-text-600"), + 700: convertToRGB("--color-text-700"), + 800: convertToRGB("--color-text-800"), + 900: convertToRGB("--color-text-900"), + 1000: "rgb(0, 0, 0)", + DEFAULT: convertToRGB("--color-text-100"), + }, + border: { + 0: "rgb(255, 255, 255)", + 100: convertToRGB("--color-border-100"), + 200: convertToRGB("--color-border-200"), + 300: convertToRGB("--color-border-300"), + 400: convertToRGB("--color-border-400"), + 1000: "rgb(0, 0, 0)", + DEFAULT: convertToRGB("--color-border-200"), + }, + sidebar: { + background: { + 0: "rgb(255, 255, 255)", + 10: convertToRGB("--color-sidebar-background-10"), + 20: convertToRGB("--color-sidebar-background-20"), + 30: convertToRGB("--color-sidebar-background-30"), + 40: convertToRGB("--color-sidebar-background-40"), + 50: convertToRGB("--color-sidebar-background-50"), + 60: convertToRGB("--color-sidebar-background-60"), + 70: convertToRGB("--color-sidebar-background-70"), + 80: convertToRGB("--color-sidebar-background-80"), + 90: convertToRGB("--color-sidebar-background-90"), + 100: convertToRGB("--color-sidebar-background-100"), + 200: convertToRGB("--color-sidebar-background-200"), + 300: convertToRGB("--color-sidebar-background-300"), + 400: convertToRGB("--color-sidebar-background-400"), + 500: convertToRGB("--color-sidebar-background-500"), + 600: convertToRGB("--color-sidebar-background-600"), + 700: convertToRGB("--color-sidebar-background-700"), + 800: convertToRGB("--color-sidebar-background-800"), + 900: convertToRGB("--color-sidebar-background-900"), + 1000: "rgb(0, 0, 0)", + DEFAULT: convertToRGB("--color-sidebar-background-100"), + }, + text: { + 0: "rgb(255, 255, 255)", + 10: convertToRGB("--color-sidebar-text-10"), + 20: convertToRGB("--color-sidebar-text-20"), + 30: convertToRGB("--color-sidebar-text-30"), + 40: convertToRGB("--color-sidebar-text-40"), + 50: convertToRGB("--color-sidebar-text-50"), + 60: convertToRGB("--color-sidebar-text-60"), + 70: convertToRGB("--color-sidebar-text-70"), + 80: convertToRGB("--color-sidebar-text-80"), + 90: convertToRGB("--color-sidebar-text-90"), + 100: convertToRGB("--color-sidebar-text-100"), + 200: convertToRGB("--color-sidebar-text-200"), + 300: convertToRGB("--color-sidebar-text-300"), + 400: convertToRGB("--color-sidebar-text-400"), + 500: convertToRGB("--color-sidebar-text-500"), + 600: convertToRGB("--color-sidebar-text-600"), + 700: convertToRGB("--color-sidebar-text-700"), + 800: convertToRGB("--color-sidebar-text-800"), + 900: convertToRGB("--color-sidebar-text-900"), + 1000: "rgb(0, 0, 0)", + DEFAULT: convertToRGB("--color-sidebar-text-100"), + }, + border: { + 0: "rgb(255, 255, 255)", + 100: convertToRGB("--color-sidebar-border-100"), + 200: convertToRGB("--color-sidebar-border-200"), + 300: convertToRGB("--color-sidebar-border-300"), + 400: convertToRGB("--color-sidebar-border-400"), + 1000: "rgb(0, 0, 0)", + DEFAULT: convertToRGB("--color-sidebar-border-200"), + }, + }, + backdrop: "#131313", + }, + }, + keyframes: { + leftToaster: { + "0%": { left: "-20rem" }, + "100%": { left: "0" }, + }, + rightToaster: { + "0%": { right: "-20rem" }, + "100%": { right: "0" }, + }, + }, + typography: ({ theme }) => ({ + brand: { + css: { + "--tw-prose-body": convertToRGB("--color-text-100"), + "--tw-prose-p": convertToRGB("--color-text-100"), + "--tw-prose-headings": convertToRGB("--color-text-100"), + "--tw-prose-lead": convertToRGB("--color-text-100"), + "--tw-prose-links": convertToRGB("--color-primary-100"), + "--tw-prose-bold": convertToRGB("--color-text-100"), + "--tw-prose-counters": convertToRGB("--color-text-100"), + "--tw-prose-bullets": convertToRGB("--color-text-100"), + "--tw-prose-hr": convertToRGB("--color-text-100"), + "--tw-prose-quotes": convertToRGB("--color-text-100"), + "--tw-prose-quote-borders": convertToRGB("--color-border"), + "--tw-prose-code": convertToRGB("--color-text-100"), + "--tw-prose-pre-code": convertToRGB("--color-text-100"), + "--tw-prose-pre-bg": convertToRGB("--color-background-100"), + "--tw-prose-th-borders": convertToRGB("--color-border"), + "--tw-prose-td-borders": convertToRGB("--color-border"), + }, + }, + }), + }, + fontFamily: { + custom: ["Inter", "sans-serif"], + }, + }, + plugins: [require("tailwindcss-animate"), require("@tailwindcss/typography")], +}; From b841df672937a25ac0942426a545aa64879e8f18 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Fri, 8 Sep 2023 18:42:05 +0530 Subject: [PATCH 02/57] added common tailwind config to web --- web/package.json | 1 + web/tailwind.config.js | 205 +------------ yarn.lock | 652 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 627 insertions(+), 231 deletions(-) diff --git a/web/package.json b/web/package.json index 1743e4b6c8b..44b7a01e3fb 100644 --- a/web/package.json +++ b/web/package.json @@ -103,6 +103,7 @@ "prettier": "^2.8.7", "tailwindcss": "^3.1.6", "tsconfig": "*", + "tailwind-config": "*", "typescript": "4.7.4" }, "resolutions": { diff --git a/web/tailwind.config.js b/web/tailwind.config.js index 0b7b5861aeb..edc9ce06409 100644 --- a/web/tailwind.config.js +++ b/web/tailwind.config.js @@ -1,206 +1,5 @@ -const convertToRGB = (variableName) => `rgba(var(${variableName}))`; +const sharedConfig = require("tailwind-config/tailwind.config.js"); module.exports = { - darkMode: "class", - content: ["./pages/**/*.tsx", "./components/**/*.tsx", "./layouts/**/*.tsx", "./ui/**/*.tsx"], - theme: { - extend: { - boxShadow: { - "custom-shadow-2xs": "var(--color-shadow-2xs)", - "custom-shadow-xs": "var(--color-shadow-xs)", - "custom-shadow-sm": "var(--color-shadow-sm)", - "custom-shadow-rg": "var(--color-shadow-rg)", - "custom-shadow-md": "var(--color-shadow-md)", - "custom-shadow-lg": "var(--color-shadow-lg)", - "custom-shadow-xl": "var(--color-shadow-xl)", - "custom-shadow-2xl": "var(--color-shadow-2xl)", - "custom-shadow-3xl": "var(--color-shadow-3xl)", - "custom-sidebar-shadow-2xs": "var(--color-sidebar-shadow-2xs)", - "custom-sidebar-shadow-xs": "var(--color-sidebar-shadow-xs)", - "custom-sidebar-shadow-sm": "var(--color-sidebar-shadow-sm)", - "custom-sidebar-shadow-rg": "var(--color-sidebar-shadow-rg)", - "custom-sidebar-shadow-md": "var(--color-sidebar-shadow-md)", - "custom-sidebar-shadow-lg": "var(--color-sidebar-shadow-lg)", - "custom-sidebar-shadow-xl": "var(--color-sidebar-shadow-xl)", - "custom-sidebar-shadow-2xl": "var(--color-sidebar-shadow-2xl)", - "custom-sidebar-shadow-3xl": "var(--color-sidebar-shadow-3xl)", - }, - colors: { - custom: { - primary: { - 0: "rgb(255, 255, 255)", - 10: convertToRGB("--color-primary-10"), - 20: convertToRGB("--color-primary-20"), - 30: convertToRGB("--color-primary-30"), - 40: convertToRGB("--color-primary-40"), - 50: convertToRGB("--color-primary-50"), - 60: convertToRGB("--color-primary-60"), - 70: convertToRGB("--color-primary-70"), - 80: convertToRGB("--color-primary-80"), - 90: convertToRGB("--color-primary-90"), - 100: convertToRGB("--color-primary-100"), - 200: convertToRGB("--color-primary-200"), - 300: convertToRGB("--color-primary-300"), - 400: convertToRGB("--color-primary-400"), - 500: convertToRGB("--color-primary-500"), - 600: convertToRGB("--color-primary-600"), - 700: convertToRGB("--color-primary-700"), - 800: convertToRGB("--color-primary-800"), - 900: convertToRGB("--color-primary-900"), - 1000: "rgb(0, 0, 0)", - DEFAULT: convertToRGB("--color-primary-100"), - }, - background: { - 0: "rgb(255, 255, 255)", - 10: convertToRGB("--color-background-10"), - 20: convertToRGB("--color-background-20"), - 30: convertToRGB("--color-background-30"), - 40: convertToRGB("--color-background-40"), - 50: convertToRGB("--color-background-50"), - 60: convertToRGB("--color-background-60"), - 70: convertToRGB("--color-background-70"), - 80: convertToRGB("--color-background-80"), - 90: convertToRGB("--color-background-90"), - 100: convertToRGB("--color-background-100"), - 200: convertToRGB("--color-background-200"), - 300: convertToRGB("--color-background-300"), - 400: convertToRGB("--color-background-400"), - 500: convertToRGB("--color-background-500"), - 600: convertToRGB("--color-background-600"), - 700: convertToRGB("--color-background-700"), - 800: convertToRGB("--color-background-800"), - 900: convertToRGB("--color-background-900"), - 1000: "rgb(0, 0, 0)", - DEFAULT: convertToRGB("--color-background-100"), - }, - text: { - 0: "rgb(255, 255, 255)", - 10: convertToRGB("--color-text-10"), - 20: convertToRGB("--color-text-20"), - 30: convertToRGB("--color-text-30"), - 40: convertToRGB("--color-text-40"), - 50: convertToRGB("--color-text-50"), - 60: convertToRGB("--color-text-60"), - 70: convertToRGB("--color-text-70"), - 80: convertToRGB("--color-text-80"), - 90: convertToRGB("--color-text-90"), - 100: convertToRGB("--color-text-100"), - 200: convertToRGB("--color-text-200"), - 300: convertToRGB("--color-text-300"), - 400: convertToRGB("--color-text-400"), - 500: convertToRGB("--color-text-500"), - 600: convertToRGB("--color-text-600"), - 700: convertToRGB("--color-text-700"), - 800: convertToRGB("--color-text-800"), - 900: convertToRGB("--color-text-900"), - 1000: "rgb(0, 0, 0)", - DEFAULT: convertToRGB("--color-text-100"), - }, - border: { - 0: "rgb(255, 255, 255)", - 100: convertToRGB("--color-border-100"), - 200: convertToRGB("--color-border-200"), - 300: convertToRGB("--color-border-300"), - 400: convertToRGB("--color-border-400"), - 1000: "rgb(0, 0, 0)", - DEFAULT: convertToRGB("--color-border-200"), - }, - sidebar: { - background: { - 0: "rgb(255, 255, 255)", - 10: convertToRGB("--color-sidebar-background-10"), - 20: convertToRGB("--color-sidebar-background-20"), - 30: convertToRGB("--color-sidebar-background-30"), - 40: convertToRGB("--color-sidebar-background-40"), - 50: convertToRGB("--color-sidebar-background-50"), - 60: convertToRGB("--color-sidebar-background-60"), - 70: convertToRGB("--color-sidebar-background-70"), - 80: convertToRGB("--color-sidebar-background-80"), - 90: convertToRGB("--color-sidebar-background-90"), - 100: convertToRGB("--color-sidebar-background-100"), - 200: convertToRGB("--color-sidebar-background-200"), - 300: convertToRGB("--color-sidebar-background-300"), - 400: convertToRGB("--color-sidebar-background-400"), - 500: convertToRGB("--color-sidebar-background-500"), - 600: convertToRGB("--color-sidebar-background-600"), - 700: convertToRGB("--color-sidebar-background-700"), - 800: convertToRGB("--color-sidebar-background-800"), - 900: convertToRGB("--color-sidebar-background-900"), - 1000: "rgb(0, 0, 0)", - DEFAULT: convertToRGB("--color-sidebar-background-100"), - }, - text: { - 0: "rgb(255, 255, 255)", - 10: convertToRGB("--color-sidebar-text-10"), - 20: convertToRGB("--color-sidebar-text-20"), - 30: convertToRGB("--color-sidebar-text-30"), - 40: convertToRGB("--color-sidebar-text-40"), - 50: convertToRGB("--color-sidebar-text-50"), - 60: convertToRGB("--color-sidebar-text-60"), - 70: convertToRGB("--color-sidebar-text-70"), - 80: convertToRGB("--color-sidebar-text-80"), - 90: convertToRGB("--color-sidebar-text-90"), - 100: convertToRGB("--color-sidebar-text-100"), - 200: convertToRGB("--color-sidebar-text-200"), - 300: convertToRGB("--color-sidebar-text-300"), - 400: convertToRGB("--color-sidebar-text-400"), - 500: convertToRGB("--color-sidebar-text-500"), - 600: convertToRGB("--color-sidebar-text-600"), - 700: convertToRGB("--color-sidebar-text-700"), - 800: convertToRGB("--color-sidebar-text-800"), - 900: convertToRGB("--color-sidebar-text-900"), - 1000: "rgb(0, 0, 0)", - DEFAULT: convertToRGB("--color-sidebar-text-100"), - }, - border: { - 0: "rgb(255, 255, 255)", - 100: convertToRGB("--color-sidebar-border-100"), - 200: convertToRGB("--color-sidebar-border-200"), - 300: convertToRGB("--color-sidebar-border-300"), - 400: convertToRGB("--color-sidebar-border-400"), - 1000: "rgb(0, 0, 0)", - DEFAULT: convertToRGB("--color-sidebar-border-200"), - }, - }, - backdrop: "#131313", - }, - }, - keyframes: { - leftToaster: { - "0%": { left: "-20rem" }, - "100%": { left: "0" }, - }, - rightToaster: { - "0%": { right: "-20rem" }, - "100%": { right: "0" }, - }, - }, - typography: ({ theme }) => ({ - brand: { - css: { - "--tw-prose-body": convertToRGB("--color-text-100"), - "--tw-prose-p": convertToRGB("--color-text-100"), - "--tw-prose-headings": convertToRGB("--color-text-100"), - "--tw-prose-lead": convertToRGB("--color-text-100"), - "--tw-prose-links": convertToRGB("--color-primary-100"), - "--tw-prose-bold": convertToRGB("--color-text-100"), - "--tw-prose-counters": convertToRGB("--color-text-100"), - "--tw-prose-bullets": convertToRGB("--color-text-100"), - "--tw-prose-hr": convertToRGB("--color-text-100"), - "--tw-prose-quotes": convertToRGB("--color-text-100"), - "--tw-prose-quote-borders": convertToRGB("--color-border"), - "--tw-prose-code": convertToRGB("--color-text-100"), - "--tw-prose-pre-code": convertToRGB("--color-text-100"), - "--tw-prose-pre-bg": convertToRGB("--color-background-100"), - "--tw-prose-th-borders": convertToRGB("--color-border"), - "--tw-prose-td-borders": convertToRGB("--color-border"), - }, - }, - }), - }, - fontFamily: { - custom: ["Inter", "sans-serif"], - }, - }, - plugins: [require("tailwindcss-animate"), require("@tailwindcss/typography")], + presets: [sharedConfig], }; diff --git a/yarn.lock b/yarn.lock index 1aa8e5bdea4..aa733418ded 100644 --- a/yarn.lock +++ b/yarn.lock @@ -967,6 +967,13 @@ dependencies: tslib "~2.5.0" +"@blueprintjs/colors@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@blueprintjs/colors/-/colors-5.0.2.tgz#c1308fbf156b6ebc3e22e88eaad47dc274c2a4b4" + integrity sha512-icP/d5sheRT8ReRy6jf6WunvLmDQWXFjFU97/xKsqF5SMOWIYC92I0b/705dmc+z5lAXntkU67pCMRuNWSZ9lQ== + dependencies: + tslib "~2.5.0" + "@blueprintjs/core@^4.16.3", "@blueprintjs/core@^4.20.2": version "4.20.2" resolved "https://registry.yarnpkg.com/@blueprintjs/core/-/core-4.20.2.tgz#ae1bbaf13bd1bf887b506760c478cc940f6d6e20" @@ -984,6 +991,20 @@ react-transition-group "^4.4.5" tslib "~2.5.0" +"@blueprintjs/core@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@blueprintjs/core/-/core-5.3.0.tgz#5e4d00797c684f6e417e3d1707ac2141f67f70a0" + integrity sha512-Pzd/ptszeX/Vt5rMa7AFSRlxw8sMs2xhCs4Xje2tTsQUaElbmH1oJbzDyAjSs50na6ncKEmPIvkhXz5ggB1rrA== + dependencies: + "@blueprintjs/colors" "^5.0.2" + "@blueprintjs/icons" "^5.1.6" + "@popperjs/core" "^2.11.7" + classnames "^2.3.1" + normalize.css "^8.0.1" + react-popper "^2.3.0" + react-transition-group "^4.4.5" + tslib "~2.5.0" + "@blueprintjs/icons@^4.16.0": version "4.16.0" resolved "https://registry.yarnpkg.com/@blueprintjs/icons/-/icons-4.16.0.tgz#47f9e8abe64d84fc18721080b8f191d8aac075d8" @@ -993,6 +1014,15 @@ classnames "^2.3.1" tslib "~2.5.0" +"@blueprintjs/icons@^5.1.6": + version "5.1.6" + resolved "https://registry.yarnpkg.com/@blueprintjs/icons/-/icons-5.1.6.tgz#3882cd3a01a1f83dbe584851955a7459d0a78704" + integrity sha512-W87oUP082sZ+dh5oxbgARCHGDyELVKXC+ffxkMYeK3M3hDn0UBSCUZgWZMLltf0qGfFRXlkY+Vn3G08at6xXSw== + dependencies: + change-case "^4.1.2" + classnames "^2.3.1" + tslib "~2.5.0" + "@blueprintjs/popover2@^1.13.3": version "1.14.11" resolved "https://registry.yarnpkg.com/@blueprintjs/popover2/-/popover2-1.14.11.tgz#0698fdeaf6710460cef0b71bed592ca37f40d1f9" @@ -1006,6 +1036,15 @@ react-popper "^2.3.0" tslib "~2.5.0" +"@blueprintjs/popover2@^2.0.10": + version "2.0.10" + resolved "https://registry.yarnpkg.com/@blueprintjs/popover2/-/popover2-2.0.10.tgz#916718688a7d2a9dfc6a5af0a806a8ecef8273f6" + integrity sha512-NE6lgzu6MXfI4lruTw0sXkQ0i7H4RyEWJ0nCEAW1FGdy2KJOkJ7U5RNtBKjT/F4ChaKmoHVL94CaCwqQtB7yOQ== + dependencies: + "@blueprintjs/core" "^5.3.0" + classnames "^2.3.1" + tslib "~2.5.0" + "@cfcs/core@^0.0.6": version "0.0.6" resolved "https://registry.yarnpkg.com/@cfcs/core/-/core-0.0.6.tgz#9f8499dcd2ad29fd96d8fa72055411cd4a249121" @@ -1147,6 +1186,116 @@ resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz#d0fce5d07b0620caa282b5131c297bb60f9d87e6" integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww== +"@esbuild/android-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622" + integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ== + +"@esbuild/android-arm@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" + integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw== + +"@esbuild/android-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" + integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg== + +"@esbuild/darwin-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz#08172cbeccf95fbc383399a7f39cfbddaeb0d7c1" + integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA== + +"@esbuild/darwin-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" + integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ== + +"@esbuild/freebsd-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" + integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw== + +"@esbuild/freebsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" + integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ== + +"@esbuild/linux-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" + integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA== + +"@esbuild/linux-arm@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" + integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg== + +"@esbuild/linux-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" + integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA== + +"@esbuild/linux-loong64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" + integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg== + +"@esbuild/linux-mips64el@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" + integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ== + +"@esbuild/linux-ppc64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" + integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA== + +"@esbuild/linux-riscv64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" + integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A== + +"@esbuild/linux-s390x@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" + integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ== + +"@esbuild/linux-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" + integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== + +"@esbuild/netbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" + integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A== + +"@esbuild/openbsd-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" + integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg== + +"@esbuild/sunos-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" + integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ== + +"@esbuild/win32-arm64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" + integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg== + +"@esbuild/win32-ia32@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" + integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g== + +"@esbuild/win32-x64@0.18.20": + version "0.18.20" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d" + integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== + "@eslint-community/eslint-utils@^4.2.0": version "4.4.0" resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -1189,7 +1338,7 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/eslintrc@^2.1.2": +"@eslint/eslintrc@^2.0.1", "@eslint/eslintrc@^2.1.2": version "2.1.2" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396" integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g== @@ -1204,6 +1353,11 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@eslint/js@8.36.0": + version "8.36.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.36.0.tgz#9837f768c03a1e4a30bd304a64fb8844f0e72efe" + integrity sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg== + "@eslint/js@8.48.0": version "8.48.0" resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.48.0.tgz#642633964e217905436033a2bd08bf322849b7fb" @@ -1367,7 +1521,7 @@ resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.7.tgz#95bed2487bf59632125a13b8eb8f4c21e460afec" integrity sha512-sCWTUNElBPgB30iLvWe3PU7SIlTKZNf6/E/sko85iHVeHCM6WPkDw+y89CrZYjhFNmPqt2fIQM/pZu+rP2lFLA== -"@mui/icons-material@^5.14.1", "@mui/icons-material@^5.14.7": +"@mui/icons-material@^5.14.1": version "5.14.7" resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.14.7.tgz#d7f6bd188fe38adf35c89d9343b8a529c2306383" integrity sha512-mWp4DwMa8c1Gx9yOEtPgxM4b+e6hAbtZyzfSubdBwrnEE6G5D2rbAJ5MB+If6kfI48JaYaJ5j8+zAdmZLuZc0A== @@ -1467,6 +1621,13 @@ dependencies: glob "7.1.7" +"@next/eslint-plugin-next@13.2.4": + version "13.2.4" + resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-13.2.4.tgz#3e124cd10ce24dab5d3448ce04104b4f1f4c6ca7" + integrity sha512-ck1lI+7r1mMJpqLNa3LJ5pxCfOB1lfJncKmRJeJxcJqcngaFwylreLP7da6Rrjr6u2gVRTfmnkSkjc80IiQCwQ== + dependencies: + glob "7.1.7" + "@next/swc-android-arm-eabi@12.3.2": version "12.3.2" resolved "https://registry.yarnpkg.com/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.3.2.tgz#806e3be9741bc14aafdfad0f0c4c6a8de5b77ee1" @@ -2189,16 +2350,31 @@ resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.1.7.tgz#9823a3712d176849cfd281dd8229ad0719c9eb9e" integrity sha512-1pqTwlTnwTKQSNQmmTWhs2lwdvd+hFFNFZnrRAfvZhQZA6qPmPmKMNTcYmK38Tn4axKth6mhBamzTJgMZFI7ng== +"@tiptap/core@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.1.8.tgz#4555dc7d86580dee790d4aded1ce7fb79319da70" + integrity sha512-QTGgqki7hkonLJ93gWqCUkD6cCAQ3rEX9gbMLwzfnegIZ+/BKLQYKYCozsEMZnMPXgdRrKuyRBOL+RH+IolMeA== + "@tiptap/extension-blockquote@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.1.7.tgz#fe25ec1dedd1f7e3eb1a851a6ac8738ca4691a17" integrity sha512-oAsUU1c0DDZKHwK7/uCtYpnTUQt0o3w+SsJSv4S2vlSHidiFl9gCQGozUQ/Alzc7GO1Y95rOscL28DJXgXESQg== +"@tiptap/extension-blockquote@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.1.8.tgz#eb3f70d03807b2d51645cf5450a1e84ccb53633b" + integrity sha512-NhTE90ZDb/BbtkgeNjwLYPYMryAfCXCM+Zpk8AMsVODZ+bDy+lsqpnDw7uRxUK3guLMnqKgSe2eTaXqx7AKE+A== + "@tiptap/extension-bold@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.1.7.tgz#c5d89284235d75c2e65745b50a5c0681be1cbab6" integrity sha512-GZV2D91WENkWd1W29vM4kyGWObcxOKQrY8MuCvTdxni1kobEc/LPZzQ1XiQmiNTvXTMcBz5ckLpezdjASV1dNg== +"@tiptap/extension-bold@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.1.8.tgz#2047345c814cad672d150b303436928d46aecbc1" + integrity sha512-rDdmir78a0JTiV+vrycGh3yS1ZzRF1bRvBt4jr7Rne0LOl03kc7Wm936ommiL3McWUpZZV37ZpCm5JfE8rQb+w== + "@tiptap/extension-bubble-menu@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.1.7.tgz#62616c9ee456c8413ad6c120757978266052a1a0" @@ -2206,11 +2382,23 @@ dependencies: tippy.js "^6.3.7" +"@tiptap/extension-bubble-menu@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.1.8.tgz#26d5f2ebc198553c5339d9ea6d06fcb02b6a938f" + integrity sha512-Na9Maz20jS+3UrHtAGLkfFt3uu+HD9SSK3+3WyNeylkWciJa/qkZKqwhptHrjpin0IHSF2JNche+ZA+hSmnm2Q== + dependencies: + tippy.js "^6.3.7" + "@tiptap/extension-bullet-list@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.1.7.tgz#3a7356824a931122314a6bd73b5f9d8a8a313791" integrity sha512-BReix1wkGNH12DSWGnWPKNu4do92Avh98aLkRS1o1V1Y49/+YGMYtfBXB9obq40o0WqKvk4MoM+rhKbfEc44Gg== +"@tiptap/extension-bullet-list@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.1.8.tgz#d9d4ee46d1adb2b70d3b8c19540ebcdd8a1eaaec" + integrity sha512-VWj3XZMwJQVb7e4ZM0N+o6o+905lyMMS4C35yw/sxN5CDw4TJpQMSPSAmBVNtK469XUdlGOxeLc/+Q00aU+S8A== + "@tiptap/extension-code-block-lowlight@^2.0.4": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.1.7.tgz#713dad4324c9ce25c66768fc4cfdb514ecea21c7" @@ -2221,11 +2409,21 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.1.7.tgz#c087c22c305f3c87645228ad32f32595dde7f2a2" integrity sha512-uiasfWCIQuk34vGoIENqAJOHf9m3hAkcELnb9T6+uNxA3O7PUZQqBVN/27oEipj7j15pqua50D6C1jql9kFe0g== +"@tiptap/extension-code-block@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.1.8.tgz#d2dccf64a583bfb12e2ebd04b3724b7e9430549d" + integrity sha512-EjegLBBz8ATvIuJlqosGrcOsKNu8YveI8rogGfUmnXWMNcPSSqBDoWK2EpLTUzGccPWRxo7yBsr5wItikfPPYA== + "@tiptap/extension-code@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.1.7.tgz#bad3b1aedc23123a2094f8810801edb0c13acbff" integrity sha512-g0IA6Q6DFZE0AEOMXAV1mktl/XzIO3s1h/haPIKZ8GNes522qhBr9FYc5OUPQCCbgYjL7soTGzxA/W5Jk3f2AQ== +"@tiptap/extension-code@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.1.8.tgz#c3dccd1a12972cab8d0c98f75a3960bab64905bd" + integrity sha512-dQL8aUYzSEkES5P4sBYZ6SiCMnFK1cUKKGruaRV1TJyFu/ClZ8Y+BKS2GCCMcyH0tKjqsibYsNFBWz9/Q5gjEg== + "@tiptap/extension-color@^2.0.4": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-color/-/extension-color-2.1.7.tgz#7f436aed2f41087d8de6af6a4dd4cb7d964354dd" @@ -2236,11 +2434,21 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.1.7.tgz#5e1d56e899fdca8ebfad1b7cb358d5ace664b851" integrity sha512-tZyoPPmvzti7PEnyulXomEtINd/Oi2S84uOt6gw7DTCnDq5bF5sn1IfN8Icqp9t4jDwyLXy2TL0Zg/sR0a2Ibg== +"@tiptap/extension-document@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.1.8.tgz#fa4dce27fd5d25b54f7e7e9a93db69606a624b96" + integrity sha512-mLPZqd5QUv3FKo+5zOaf7dGqZPci7Myr92U1Y6Vw0V+hCRC9Emm3I/xssQYGsWXmXQuyNJ5WRlpXgag3Ae+CkA== + "@tiptap/extension-dropcursor@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.1.7.tgz#a3f79b7453579f36f326852b16e421601e881a28" integrity sha512-hNk2BuLnNSXlGOQphlzdpFKCKo7uHUFjWuBfzF1S9FMAQgcN7eTia+cCClmXABYfVLW4fT14PC1KiuGjxi9MuA== +"@tiptap/extension-dropcursor@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.1.8.tgz#f7128aebe9e2bb05cd6508d782deaf436ae3c46e" + integrity sha512-KilbUHApYya2Q6brq5qW+B+pPkb6lvgnjRfuFuv6doM/v+lfEdozUE1Ma8C19UXtzl7BmPDut9HRMDL17Pqwyg== + "@tiptap/extension-floating-menu@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.1.7.tgz#fe2def740b3136d38101634ae60d2fec5468c57e" @@ -2248,46 +2456,93 @@ dependencies: tippy.js "^6.3.7" +"@tiptap/extension-floating-menu@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.1.8.tgz#49a7f83c3a0769c044d4e83352aae0f86d63f7c5" + integrity sha512-lc8bjHGqWSgXKmoU2HAlBFWzu7wnFKb5Vg0R3PECBrOZ9hXkmNA0mHxrvHglwjLtfe7XOfZf4FLySG/5S+BdeQ== + dependencies: + tippy.js "^6.3.7" + "@tiptap/extension-gapcursor@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.1.7.tgz#5c0303ba37b4c066f3a3c5835fd0b298f0d3e919" integrity sha512-7eoInzzk1sssoD3RMkwFC86U15Ja4ANve+8wIC+xhN4R3Oe3PY3lFbp1GQxCmaJj8b3rtjNKIQZ2zO0PH58afA== +"@tiptap/extension-gapcursor@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.1.8.tgz#bc7e745fdc8990a8e370c4c728ab8733ba0910c4" + integrity sha512-0EQgV/kF2dg2dOpw0fTbwwNaubwS8QNhEPPbnXQP8xqZpupuia+DKKgC+ttzbE9XhS4Sv1fGib52Sr7MMIduhA== + "@tiptap/extension-hard-break@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.1.7.tgz#1cd783adfe2788d41614f8851b8d7a52ec027cce" integrity sha512-6gFXXlCGAdXjy27BW29q4yfCQPAEFd18k7zRTnbd4aE/zIWUtLqdiTfI3kotUMab9Tt9/z1BRmCbEUxRsf1Nww== +"@tiptap/extension-hard-break@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.1.8.tgz#b898c3c9c7f96726307bd51b24f557731e25d12e" + integrity sha512-K86FTizvZu7779Gz2XigW1IxAjZXduyZ7w0ipwe+5QBa/Lh6Vfl9wa8TgV1lFAkC2VATsAa3aa36llMIDBgeew== + "@tiptap/extension-heading@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.1.7.tgz#26d16227eab95b1f381e977f7aa1685f493c6fb5" integrity sha512-jMeTqtq3kbMFtMvUb3SeIt4FFM3W+b6TAw5H4Qd6z3gYsAU3GahRK67MtbJfPmznUkZfimrqW9VCaBezScfrsQ== +"@tiptap/extension-heading@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.1.8.tgz#d34db2bdfca559567ecb6f741fa4eb5d4d54a897" + integrity sha512-6PHWzhGPC/QjfswlflU1Cy2UYZiyzwa639bWW7Dl4BHZgK+e09lbc7RwzPrrex6+jA10K4nlww19xsI590ogBw== + "@tiptap/extension-highlight@^2.0.4": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.1.7.tgz#0f9434eedfdcb95a22ca5b6f601d13f4343a7e5c" integrity sha512-3EXrnf1BQSdOe/iqzcTIr5Tf0NOhPQ+y1B9nMi/40v3MD8WzRBLaqj0lvpwO7xMAdgxm6IiL/XFYU41n9yFl/Q== +"@tiptap/extension-highlight@^2.1.7": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.1.8.tgz#b2d2d995344e06dd36cd8a395a72113b87981bd7" + integrity sha512-OCXtFWCbwsgOHq7IP4Qr02EfjwYeRRcuL1ipv0LojGtMcvnkw7OLhQZ8oocrqi4/6QCOtPLSGlcqrQ6pmN7jww== + "@tiptap/extension-history@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.1.7.tgz#baa566875ef1278c5dd8821970362d85348b266c" integrity sha512-8SIEKSImrIkqJThym1bPD13sC4/76UrG+piQ30xKQU4B7zUFCbutvrwYuQHSRvaEt8BPdTv2LWIK+wBkIgbWVA== +"@tiptap/extension-history@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.1.8.tgz#68a65b51effc1d612e3862928c3ccede3ce83592" + integrity sha512-Cyq4YsmosfgHGlaf2wiiU8VaLweUMG8LHuhZ5A2RAoriy3G09Bqgn6eqLmho8KoU1VgvffXTVBaYKxz9gVgu3w== + "@tiptap/extension-horizontal-rule@^2.0.4", "@tiptap/extension-horizontal-rule@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.1.7.tgz#7c21bc4917e4ced9382e81626e0f0068b224bfbb" integrity sha512-hJupsDxDVmjmKI/Ewl/gtiyUx52Y3wRUhT8dCXNOA5eldmPXN23E2Fa2BC8XB47dyc5pubyNcLuqaLeaZ5hedw== +"@tiptap/extension-horizontal-rule@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.1.8.tgz#db23468176fd5359240feb8601fd3fcf747d5e6d" + integrity sha512-qUNz8p/p3gth0ueYFkmMdVRcRVmtCwQGJsHWwbx23XrF/a7AJ0FSdiW0sk8YD6Dbw+i1cB3cnRyO+qq9XuWdqw== + "@tiptap/extension-image@^2.0.4": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.1.7.tgz#597129fb072f6b0014c980892c367a283077f564" integrity sha512-aWa/NPMc1U9Z6xuV0gk1O1nk4H7BAwQMwqXWdvUQCJhmW5+LJPdEiKvt3P6j+ClIN7sdyokZCgr6eGr817qTLA== +"@tiptap/extension-image@^2.1.7": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.1.8.tgz#99d78ad1d8c6f513f945beae7de352759f30189f" + integrity sha512-o+vUIYLvYcJHftIMoIukzZZ+fTTfC/gXXvQIYz51p3f1qeYXszD11FbtkaJCgXYj8BcGCO7QuzcCdQg+wyROZw== + "@tiptap/extension-italic@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.1.7.tgz#d077683597d4282ae272c48b313d768d71985b67" integrity sha512-7e37f+OFqisdY19nWIthbSNHMJy4+4dec06rUICPrkiuFaADj5HjUQr0dyWpL/LkZh92Wf/rWgp4V/lEwon3jA== +"@tiptap/extension-italic@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.1.8.tgz#b559c8d6b387e292e047985acd0def48a80a7aa0" + integrity sha512-cR6kSoMraA/dCdwmus8A09WAwpxiZiGG+B0OqsludGF+MdZLilhoGyXDbTeO3aKoKccfqxZGk1YKK13C/gRM1Q== + "@tiptap/extension-link@^2.0.4": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.1.7.tgz#2705c212d105ccf411d505e334ece4a723971ee4" @@ -2295,21 +2550,48 @@ dependencies: linkifyjs "^4.1.0" +"@tiptap/extension-link@^2.1.7": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.1.8.tgz#644229c309ef9a91db329126df23cba083ec3c61" + integrity sha512-f3yPNbbo3rNuusEX+Xh/oKUWkq/P1yyVip6ZmtUJVrrG4PFeq/w+f1vEVnlC+uZk3qoC4o8J1DTAOrlrZehx/g== + dependencies: + linkifyjs "^4.1.0" + "@tiptap/extension-list-item@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.1.7.tgz#dc24045e445d0f91baec9b113f711dc90c6682ac" integrity sha512-hd/E4qQopBXWa6kdFY19qFVgqj4fzdPgAnzdXJ2XW7bC6O2CusmHphRRZ5FBsuspYTN/6/fv0i0jK9rSGlsEyA== +"@tiptap/extension-list-item@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.1.8.tgz#b5dc1e04bfb96ca10a0821821ade5014fa188dbb" + integrity sha512-fiYVRhHvcXMcVuuiXBx/0AFWwGoKzs9784VSuVUeSSzSuH6vOchM1kZCH+v6acs7vltFKNDrluyEiwGIz1b8qA== + "@tiptap/extension-ordered-list@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.1.7.tgz#72d9ddc432ecf0fd19c8acd3c6b44f5358d8e0d0" integrity sha512-3XIXqbZmYkNzF+8PQ2jcCOCj0lpC3y9HGM/+joPIunhiUiktrIgpbUDv2E1Gq5lJHYqthIeujniI2dB85tkwJQ== +"@tiptap/extension-ordered-list@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.1.8.tgz#f489ac85ccd93ad811318bed6af7906c035ba313" + integrity sha512-qTVSWTlSjFNRwPNmWmfe9TsW9XL3LQCNJsfaBxtVZfhDN9rhoIZ6rPTBO7f2TTiPK1+uyLTvK+znWYvU9RtD5A== + "@tiptap/extension-paragraph@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.1.7.tgz#76408706f0037a510a384b86780bd50c6e8ffeea" integrity sha512-cLqX27hNrXrwZCKrIW8OC3rW2+MT8hhS37+cdqOxZo5hUqQ9EF/puwS0w8uUZ7B3awX9Jm1QZDMjjERLkcmobw== +"@tiptap/extension-paragraph@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.1.8.tgz#f337c3f84cbfddd1ea16860e934f2049c46211ce" + integrity sha512-ZuwvwKaG5GeoYRgeh96PToLk2TjxsLiZKnLN6rkUCsW6aLoseK7/8/7vm3dP2N9dAUN35ESw0/pRk2Q/VK1/+g== + +"@tiptap/extension-placeholder@2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.0.3.tgz#69575353f09fc7524c9cdbfbf16c04f73c29d154" + integrity sha512-Z42jo0termRAf0S0L8oxrts94IWX5waU4isS2CUw8xCUigYyCFslkhQXkWATO1qRbjNFLKN2C9qvCgGf4UeBrw== + "@tiptap/extension-placeholder@^2.0.4": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.1.7.tgz#8477cf5116c89f0f75e8e2e3b8528e146a7f0f24" @@ -2320,6 +2602,11 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.1.7.tgz#b7b7f49254f1de22416b1415ca88a2a20edd0627" integrity sha512-ONLXYnuZGM2EoGcxkyvJSDMBeAp7K6l83UXkK9TSj+VpEEDdeV7m8mJs8/vACJjJxD5HMN61+EPgU7VTEukQCA== +"@tiptap/extension-strike@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.1.8.tgz#ba6966a9afb9493d8bd30d4c617ffe6966b90379" + integrity sha512-JGPiGudEZAKTiOirua9gtDG+HILHEx4CGODW5PDBMA1xYDfyo7ZJk5xgfJWZ1SOo7YviF26HSY4KKV9ThINq2Q== + "@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" @@ -2345,26 +2632,51 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-2.1.7.tgz#384a55308f3524f36388560486a2508a4b3c5413" integrity sha512-4wFLZmhYqr87SEI/Qgk3FiH+qfp6IOmuYVhpL5zGLa6p+ytUdmPH3+zOaD1rthn5JiRU9KwYWFvTo2f+/O0NAg== +"@tiptap/extension-task-item@^2.1.7": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-2.1.8.tgz#2036360be6702ab753cbc77b60ab24fb33ff20a6" + integrity sha512-PoY2PDiYEQC44qDQLubzDuhZ3f6OL7sui89960M1HUQR2URnPvToOBaa5veNY8VyACdAolm+LwTpseBKKkcpmw== + "@tiptap/extension-task-list@^2.0.4": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-task-list/-/extension-task-list-2.1.7.tgz#abaad3a7b964e58dac6b96b08000a50a06a071b4" integrity sha512-eerV8pbGuYoFji6arWk+LBsIfURXPWNSLi1ZCuPfXP6N8sAV3fNT+VDm6RlGQwadQNae7rnibNClk67+55h9Zg== +"@tiptap/extension-task-list@^2.1.7": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-task-list/-/extension-task-list-2.1.8.tgz#993c415d85d414039baf7379df7c3b19b1d342d9" + integrity sha512-PmEPJHTOgy0AveE6YoxY6w09+bh5OqkrMI/sluY88291cnSPPEf9sFWmBHOrONNj54Ti6ua37arudUY5mqxOCA== + "@tiptap/extension-text-style@^2.0.4": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-text-style/-/extension-text-style-2.1.7.tgz#57f5dc5b223a855e782f24e09dc7fc53d9bd4b00" integrity sha512-0QhEMDiDqMpyBGRt6o4GvbN9cUibZe4LT9e0ujarT6ElSe2fbtwGPnXSXApUtgHDDwHw95M5ZVxX/H5cjyjw1g== +"@tiptap/extension-text-style@^2.1.7": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-text-style/-/extension-text-style-2.1.8.tgz#42e9fa179f76d4e88f73f2c66aee3b06162e659b" + integrity sha512-xnx/Pq5ttt2/gOQPmqVQIBz/jo3MErtYdYk22fUaOyu1xT36X4BDJYsrLyWhcs3aWR/tv1/XylbNOFvhrDOHoQ== + "@tiptap/extension-text@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.1.7.tgz#071053ab0a8804a3bce36d1488a603b7446dff4e" integrity sha512-3xaMMMNydLgoS+o+yOvaZF04ui9spJwJZl8VyYgcJKVGGLGRlWHrireXN5/OqXG2jLb/jWqXVx5idppQjX+PMA== +"@tiptap/extension-text@^2.1.8": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.1.8.tgz#7f537d0c490feab8b800644e2ad24b6478c67044" + integrity sha512-ha7oTtUdcJdTVLr8CrxbNMucbAmOBCi83MLxdKZclVf1VpdIVpE3NTojfH2mnZCVMvtPhj4PILQp2hGO95SFig== + "@tiptap/extension-underline@^2.0.4": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-2.1.7.tgz#ab815645770f7d2013ac69327975837b4937c8df" integrity sha512-mL95afyEJvg+C2yrTVn7QltfyE9ja1+94+OUkRBbB8PN3N6HvfSL4K/QSqecOLQ38bSQm/6ZGPkBLDkDGhGPdw== +"@tiptap/extension-underline@^2.1.7": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-2.1.8.tgz#a2f0904805f57e118c2f0b165929abe41b5c1fbf" + integrity sha512-vsmdyR8z40xNPZzTSNGLcCMaIf8Tgm9OzsZb1qWILe+PYuv/mIM1LogBbfouEzVpG5sPoxwFTDgxnC+M3Ohgzg== + "@tiptap/pm@^2.0.4": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.1.7.tgz#91e1b87d4ddbddca3cfe46e3c052b0072e4e1d97" @@ -2389,6 +2701,30 @@ prosemirror-transform "^1.7.0" prosemirror-view "^1.28.2" +"@tiptap/pm@^2.1.7": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.1.8.tgz#9108af0365fd653d64d620d45016e7079961bebc" + integrity sha512-H3NGAu5xdH1PpXa6OQlvecaWJIZR/9tVkc1mdpLanvG7mW85DuY+5fC36Xnv9SPMVcO3zWXS6Ii4os6HbdP6bQ== + dependencies: + prosemirror-changeset "^2.2.0" + prosemirror-collab "^1.3.0" + prosemirror-commands "^1.3.1" + prosemirror-dropcursor "^1.5.0" + prosemirror-gapcursor "^1.3.1" + prosemirror-history "^1.3.0" + prosemirror-inputrules "^1.2.0" + prosemirror-keymap "^1.2.0" + prosemirror-markdown "^1.10.1" + prosemirror-menu "^1.2.1" + prosemirror-model "^1.18.1" + prosemirror-schema-basic "^1.2.0" + prosemirror-schema-list "^1.2.2" + prosemirror-state "^1.4.1" + prosemirror-tables "^1.3.0" + prosemirror-trailing-node "^2.0.2" + prosemirror-transform "^1.7.0" + prosemirror-view "^1.28.2" + "@tiptap/react@^2.0.4": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-2.1.7.tgz#0c5a5407bcb398ff75234dd9c7a3f8878d943088" @@ -2397,6 +2733,14 @@ "@tiptap/extension-bubble-menu" "^2.1.7" "@tiptap/extension-floating-menu" "^2.1.7" +"@tiptap/react@^2.1.7": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-2.1.8.tgz#50a834a9b76b36eebb33e71dcb765aa9cb80f276" + integrity sha512-yTjlin4tOfYNwBdpX4+2CmNxybq2Ms50rX0RIRLABbnCTqhBIKko/eBLFq7DCot/Dwdw6c5Y098/fayKywfJWg== + dependencies: + "@tiptap/extension-bubble-menu" "^2.1.8" + "@tiptap/extension-floating-menu" "^2.1.8" + "@tiptap/starter-kit@^2.0.4": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.1.7.tgz#a33a7928b7051ac9cd89d1798745f9855b7b72d9" @@ -2422,11 +2766,41 @@ "@tiptap/extension-strike" "^2.1.7" "@tiptap/extension-text" "^2.1.7" +"@tiptap/starter-kit@^2.1.7": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.1.8.tgz#d33f04478cd7b4956cb312335bcbed109269b651" + integrity sha512-LfCQgENw501XyTbCEcmiKt1d7XQi+6nTrQQfI16cCwc7lqp+LREz9EOFidkjTtrKuUHwlTaZzS7C76Cfc87mXA== + dependencies: + "@tiptap/core" "^2.1.8" + "@tiptap/extension-blockquote" "^2.1.8" + "@tiptap/extension-bold" "^2.1.8" + "@tiptap/extension-bullet-list" "^2.1.8" + "@tiptap/extension-code" "^2.1.8" + "@tiptap/extension-code-block" "^2.1.8" + "@tiptap/extension-document" "^2.1.8" + "@tiptap/extension-dropcursor" "^2.1.8" + "@tiptap/extension-gapcursor" "^2.1.8" + "@tiptap/extension-hard-break" "^2.1.8" + "@tiptap/extension-heading" "^2.1.8" + "@tiptap/extension-history" "^2.1.8" + "@tiptap/extension-horizontal-rule" "^2.1.8" + "@tiptap/extension-italic" "^2.1.8" + "@tiptap/extension-list-item" "^2.1.8" + "@tiptap/extension-ordered-list" "^2.1.8" + "@tiptap/extension-paragraph" "^2.1.8" + "@tiptap/extension-strike" "^2.1.8" + "@tiptap/extension-text" "^2.1.8" + "@tiptap/suggestion@^2.0.4": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.1.7.tgz#ac88deef2ade8d836ca9084c276cc9d64c6e604a" integrity sha512-FKlXFMWf9rCnNJQsUfeX6WpS2VUs2O98ENkyhfV8ehCB7X5+57mkkxJxl/88SMbjZL+FbWPBKLaiOvsXfIUoww== +"@tiptap/suggestion@^2.1.7": + version "2.1.8" + resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.1.8.tgz#ffd61c13aa11c4b51e50a9c83f0813f71ab0881b" + integrity sha512-3QypKFCeZSRrjgSz0n0JE5SimisolaxDZn45GGtkXuJWmKGCmsJw9UsXeH3S9ZuP3pvPImL0P9uAHlhRReRw1w== + "@types/debug@^4.0.0": version "4.1.8" resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.8.tgz#cef723a5d0a90990313faec2d1e22aee5eecb317" @@ -2549,6 +2923,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.14.1.tgz#90dad8476f1e42797c49d6f8b69aaf9f876fc69f" integrity sha512-QH+37Qds3E0eDlReeboBxfHbX9omAcBCXEzswCu6jySP642jiM3cYSIkU/REqwhCUqXdonHFuBfJDiAJxMNhaQ== +"@types/node@18.15.3": + version "18.15.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.3.tgz#f0b991c32cfc6a4e7f3399d6cb4b8cf9a0315014" + integrity sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw== + "@types/nprogress@^0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@types/nprogress/-/nprogress-0.2.0.tgz#86c593682d4199212a0509cc3c4d562bbbd6e45f" @@ -3046,7 +3425,7 @@ attr-accept@^2.2.2: resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b" integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== -autoprefixer@^10.4.13, autoprefixer@^10.4.7: +autoprefixer@^10.4.13, autoprefixer@^10.4.14, autoprefixer@^10.4.7: version "10.4.15" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.15.tgz#a1230f4aeb3636b89120b34a1f513e2f6834d530" integrity sha512-KCuPB8ZCIqFdA4HwKXsvz7j6gvSDNhDP7WnUjBleRkKjPdvCmHFuQ77ocavI8FT6NdvlBnE2UFr2H4Mycn8Vew== @@ -3216,6 +3595,18 @@ builtin-modules@^3.1.0: resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== +bundle-require@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/bundle-require/-/bundle-require-4.0.1.tgz#2cc1ad76428043d15e0e7f30990ee3d5404aa2e3" + integrity sha512-9NQkRHlNdNpDBGmLpngF3EFDcwodhMUuLz9PaWYciVcQF9SE4LFjM2DB/xV1Li5JiuDMv7ZUWuC3rGbqR0MAXQ== + dependencies: + load-tsconfig "^0.2.3" + +cac@^6.7.12: + version "6.7.14" + resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" + integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== + call-bind@^1.0.0, call-bind@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" @@ -3309,7 +3700,7 @@ character-entities@^2.0.0: resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.2.tgz#2d09c2e72cd9523076ccb21157dff66ad43fcc22" integrity sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ== -chokidar@^3.5.3: +chokidar@^3.5.1, chokidar@^3.5.3: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -3346,6 +3737,11 @@ client-only@^0.0.1: resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== +clsx@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" + integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== + clsx@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.0.0.tgz#12658f3fd98fafe62075595a5c30e43d18f3d00b" @@ -3488,7 +3884,7 @@ crelt@^1.0.0: resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.6.tgz#7cc898ea74e190fb6ef9dae57f8f81cf7302df72" integrity sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g== -cross-spawn@^7.0.2: +cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -3637,7 +4033,7 @@ date-fns@^2.0.1, date-fns@^2.30.0: dependencies: "@babel/runtime" "^7.21.0" -debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: +debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -3957,6 +4353,34 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" +esbuild@^0.18.2: + version "0.18.20" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6" + integrity sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA== + optionalDependencies: + "@esbuild/android-arm" "0.18.20" + "@esbuild/android-arm64" "0.18.20" + "@esbuild/android-x64" "0.18.20" + "@esbuild/darwin-arm64" "0.18.20" + "@esbuild/darwin-x64" "0.18.20" + "@esbuild/freebsd-arm64" "0.18.20" + "@esbuild/freebsd-x64" "0.18.20" + "@esbuild/linux-arm" "0.18.20" + "@esbuild/linux-arm64" "0.18.20" + "@esbuild/linux-ia32" "0.18.20" + "@esbuild/linux-loong64" "0.18.20" + "@esbuild/linux-mips64el" "0.18.20" + "@esbuild/linux-ppc64" "0.18.20" + "@esbuild/linux-riscv64" "0.18.20" + "@esbuild/linux-s390x" "0.18.20" + "@esbuild/linux-x64" "0.18.20" + "@esbuild/netbsd-x64" "0.18.20" + "@esbuild/openbsd-x64" "0.18.20" + "@esbuild/sunos-x64" "0.18.20" + "@esbuild/win32-arm64" "0.18.20" + "@esbuild/win32-ia32" "0.18.20" + "@esbuild/win32-x64" "0.18.20" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -4017,6 +4441,21 @@ eslint-config-next@13.2.1: eslint-plugin-react "^7.31.7" eslint-plugin-react-hooks "^4.5.0" +eslint-config-next@13.2.4: + version "13.2.4" + resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-13.2.4.tgz#8aa4d42da3a575a814634ba9c88c8d25266c5fdd" + integrity sha512-lunIBhsoeqw6/Lfkd6zPt25w1bn0znLA/JCL+au1HoEpSb4/PpsOYsYtgV/q+YPsoKIOzFyU5xnb04iZnXjUvg== + dependencies: + "@next/eslint-plugin-next" "13.2.4" + "@rushstack/eslint-patch" "^1.1.3" + "@typescript-eslint/parser" "^5.42.0" + eslint-import-resolver-node "^0.3.6" + eslint-import-resolver-typescript "^3.5.2" + eslint-plugin-import "^2.26.0" + eslint-plugin-jsx-a11y "^6.5.1" + eslint-plugin-react "^7.31.7" + eslint-plugin-react-hooks "^4.5.0" + eslint-config-prettier@^8.3.0: version "8.10.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz#3a06a662130807e2502fc3ff8b4143d8a0658e11" @@ -4258,6 +4697,52 @@ eslint@8.34.0: strip-json-comments "^3.1.0" text-table "^0.2.0" +eslint@8.36.0: + version "8.36.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.36.0.tgz#1bd72202200a5492f91803b113fb8a83b11285cf" + integrity sha512-Y956lmS7vDqomxlaaQAHVmeb4tNMp2FWIvU/RnU5BD3IKMD/MJPr76xdyr68P8tV1iNMvN2mRK0yy3c+UjL+bw== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.4.0" + "@eslint/eslintrc" "^2.0.1" + "@eslint/js" "8.36.0" + "@humanwhocodes/config-array" "^0.11.8" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.1.1" + eslint-visitor-keys "^3.3.0" + espree "^9.5.0" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + grapheme-splitter "^1.0.4" + ignore "^5.2.0" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-sdsl "^4.1.4" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.1" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" + text-table "^0.2.0" + eslint@^7.23.0, eslint@^7.32.0: version "7.32.0" resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.32.0.tgz#c6d328a14be3fb08c8d1d21e12c02fdb7a2a812d" @@ -4356,7 +4841,7 @@ espree@^7.3.0, espree@^7.3.1: acorn-jsx "^5.3.1" eslint-visitor-keys "^1.3.0" -espree@^9.4.0, espree@^9.6.0, espree@^9.6.1: +espree@^9.4.0, espree@^9.5.0, espree@^9.6.0, espree@^9.6.1: version "9.6.1" resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== @@ -4409,6 +4894,26 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +eventsource-parser@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/eventsource-parser/-/eventsource-parser-0.1.0.tgz#4a6b84751ca8e704040e6f7f50e7d77344fa1b7c" + integrity sha512-M9QjFtEIkwytUarnx113HGmgtk52LSn3jNAtnWKi3V+b9rqSfQeVdLsaD5AG/O4IrGQwmAAHBIsqbmURPTd2rA== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + expand-template@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" @@ -4663,6 +5168,11 @@ get-own-enumerable-property-symbols@^3.0.0: resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz#b5fde77f22cbe35f390b4e089922c50bce6ef664" integrity sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g== +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + get-symbol-description@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" @@ -4763,7 +5273,7 @@ globalthis@^1.0.3: dependencies: define-properties "^1.1.3" -globby@^11.0.4, globby@^11.1.0: +globby@^11.0.3, globby@^11.0.4, globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -4892,10 +5402,10 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" -husky@^8.0.3: - version "8.0.3" - resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.3.tgz#4936d7212e46d1dea28fef29bb3a108872cd9184" - integrity sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg== +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== idb@^7.0.1: version "7.1.1" @@ -5301,6 +5811,11 @@ jiti@^1.18.2: resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.19.3.tgz#ef554f76465b3c2b222dc077834a71f0d4a37569" integrity sha512-5eEbBDQT/jF1xg6l36P+mWGGoH9Spuy0PCdSr2dtWRDGC6ph/w9ZCL4lmESW8f8F7MwT3XKescfP0wnZWAKL9w== +joycon@^3.0.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03" + integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw== + js-cookie@^3.0.1: version "3.0.5" resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-3.0.5.tgz#0b7e2fd0c01552c58ba86e0841f94dc2557dcdbc" @@ -5488,6 +6003,11 @@ linkifyjs@^4.1.0: resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-4.1.1.tgz#73d427e3bbaaf4ca8e71c589ad4ffda11a9a5fde" integrity sha512-zFN/CTVmbcVef+WaDXT63dNzzkfRBKT1j464NJQkV7iSgJU0sLBus9W0HBwnXK13/hf168pbrx/V/bjEHOXNHA== +load-tsconfig@^0.2.3: + version "0.2.5" + resolved "https://registry.yarnpkg.com/load-tsconfig/-/load-tsconfig-0.2.5.tgz#453b8cd8961bfb912dea77eb6c168fe8cca3d3a1" + integrity sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg== + loader-utils@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.4.tgz#8b5cb38b5c34a9a018ee1fc0e6a066d1dfcc528c" @@ -5600,6 +6120,11 @@ lru_map@^0.3.3: resolved "https://registry.yarnpkg.com/lru_map/-/lru_map-0.3.3.tgz#b5c8351b9464cbd750335a79650a0ec0e56118dd" integrity sha512-Pn9cox5CsMYngeDbmChANltQl+5pi6XmTrraMSzhPmMBbmgcxmqWry0U3PGapCU1yB4/LqCcom7qhHZiF/jGfQ== +lucide-react@^0.244.0: + version "0.244.0" + resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.244.0.tgz#9626f44881830280012dad23afda7ddbcffff24b" + integrity sha512-PeDVbx5PlIRrVvdxiuSxPfBo7sK5qrL3LbvvRoGVNiHYRAkBm/48lKqoioxcmp0bgsyJs9lMw7CdtGFvnMJbVg== + lucide-react@^0.263.1: version "0.263.1" resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.263.1.tgz#a456ee0d171aa373929bd3ee20d6f9fb4429c301" @@ -5934,6 +6459,11 @@ mime-types@^2.1.12, mime-types@^2.1.27: dependencies: mime-db "1.52.0" +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + mimic-response@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" @@ -6046,11 +6576,6 @@ next-pwa@^5.6.0: workbox-webpack-plugin "^6.5.4" workbox-window "^6.5.4" -next-theme@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/next-theme/-/next-theme-0.1.5.tgz#aa6655c516892925e577349d7715a8ed54bad727" - integrity sha512-WR8UCLEFjWvRl+UO2lTM4pGo7R4jzGZqQ6YL3hiL1Ns587Qb91GhJZLPu/Aa4ExtGQ/5wlcDX8zDYZoCN9oDPw== - next-themes@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.2.1.tgz#0c9f128e847979daf6c67f70b38e6b6567856e45" @@ -6129,6 +6654,13 @@ normalize.css@^8.0.1: resolved "https://registry.yarnpkg.com/normalize.css/-/normalize.css-8.0.1.tgz#9b98a208738b9cc2634caacbc42d131c97487bf3" integrity sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg== +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + nprogress@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/nprogress/-/nprogress-0.2.0.tgz#cb8f34c53213d895723fcbab907e9422adbcafb1" @@ -6238,6 +6770,13 @@ once@^1.3.0, once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + optionator@^0.9.1, optionator@^0.9.3: version "0.9.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" @@ -6356,7 +6895,7 @@ path-is-inside@^1.0.2: resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w== -path-key@^3.1.0: +path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== @@ -6481,7 +7020,7 @@ postcss@8.4.14: picocolors "^1.0.0" source-map-js "^1.0.2" -postcss@^8.4.14, postcss@^8.4.21, postcss@^8.4.23: +postcss@^8.4.14, postcss@^8.4.21, postcss@^8.4.23, postcss@^8.4.29: version "8.4.29" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.29.tgz#33bc121cf3b3688d4ddef50be869b2a54185a1dd" integrity sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw== @@ -6513,7 +7052,12 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier@^2.8.7: +prettier-plugin-tailwindcss@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.3.0.tgz#8299b307c7f6467f52732265579ed9375be6c818" + integrity sha512-009/Xqdy7UmkcTBpwlq7jsViDqXAYSOMLDrHAdTMlVZOrKfM2o9Ci7EMWTMZ7SkKBFTG04UM9F9iM2+4i6boDA== + +prettier@^2.8.7, prettier@^2.8.8: version "2.8.8" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== @@ -7109,6 +7653,11 @@ resolve-from@^4.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + resolve-pkg-maps@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" @@ -7175,6 +7724,13 @@ rollup@^2.43.1: optionalDependencies: fsevents "~2.3.2" +rollup@^3.2.5: + version "3.29.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.0.tgz#1b40e64818afc979c7e5bef93de675829288986b" + integrity sha512-nszM8DINnx1vSS+TpbWKMkxem0CDWk3cSit/WWCBVs9/JZ1I/XLwOsiUglYuYReaeWWSsW9kge5zE5NZtf/a4w== + optionalDependencies: + fsevents "~2.3.2" + rope-sequence@^1.3.0: version "1.3.4" resolved "https://registry.yarnpkg.com/rope-sequence/-/rope-sequence-1.3.4.tgz#df85711aaecd32f1e756f76e43a415171235d425" @@ -7329,6 +7885,11 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" +signal-exit@^3.0.3: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + simple-concat@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" @@ -7377,6 +7938,11 @@ sonner@^0.6.2: resolved "https://registry.yarnpkg.com/sonner/-/sonner-0.6.2.tgz#d87420e80d8b25b6d2bd6aabcc28465f03962bdc" integrity sha512-bh4FWhYoNN481ZIW94W4e0kSLBTMGislYg2YXvDS1px1AJJz4erQe9jHV8s5pS1VMVDgfh3CslNSFLaU6Ldrnw== +sonner@^0.7.0: + version "0.7.1" + resolved "https://registry.yarnpkg.com/sonner/-/sonner-0.7.1.tgz#46441caa4e94a0491fe8e7ce56887d097f90c4df" + integrity sha512-awbVcBwV0xV5TN7kJEZv6Sx7Fi9JBL26vTn0FnBcf6YsyWKnyvz16I/jE6omCtBjd0/YXsPHJ//VuA5fvD2vEg== + source-list-map@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" @@ -7395,6 +7961,13 @@ source-map-support@~0.5.20: buffer-from "^1.0.0" source-map "^0.6.0" +source-map@0.8.0-beta.0, source-map@^0.8.0-beta.0: + version "0.8.0-beta.0" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.8.0-beta.0.tgz#d4c1bb42c3f7ee925f005927ba10709e0d1d1f11" + integrity sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA== + dependencies: + whatwg-url "^7.0.0" + source-map@^0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -7405,13 +7978,6 @@ source-map@^0.6.0, source-map@~0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -source-map@^0.8.0-beta.0: - version "0.8.0-beta.0" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.8.0-beta.0.tgz#d4c1bb42c3f7ee925f005927ba10709e0d1d1f11" - integrity sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA== - dependencies: - whatwg-url "^7.0.0" - sourcemap-codec@^1.4.8: version "1.4.8" resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" @@ -7525,6 +8091,11 @@ strip-comments@^2.0.1: resolved "https://registry.yarnpkg.com/strip-comments/-/strip-comments-2.0.1.tgz#4ad11c3fbcac177a67a40ac224ca339ca1c1ba9b" integrity sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw== +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" @@ -7552,7 +8123,7 @@ stylis@4.2.0: resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51" integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw== -sucrase@^3.32.0: +sucrase@^3.20.3, sucrase@^3.32.0: version "3.34.0" resolved "https://registry.yarnpkg.com/sucrase/-/sucrase-3.34.0.tgz#1e0e2d8fcf07f8b9c3569067d92fbd8690fb576f" integrity sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw== @@ -7808,6 +8379,11 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== +tree-kill@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + trim-lines@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/trim-lines/-/trim-lines-3.0.1.tgz#d802e332a07df861c48802c04321017b1bd87338" @@ -7848,6 +8424,26 @@ tslib@~2.5.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.3.tgz#24944ba2d990940e6e982c4bea147aba80209913" integrity sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w== +tsup@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/tsup/-/tsup-7.2.0.tgz#bb24c0d5e436477900c712e42adc67200607303c" + integrity sha512-vDHlczXbgUvY3rWvqFEbSqmC1L7woozbzngMqTtL2PGBODTtWlRwGDDawhvWzr5c1QjKe4OAKqJGfE1xeXUvtQ== + dependencies: + bundle-require "^4.0.0" + cac "^6.7.12" + chokidar "^3.5.1" + debug "^4.3.1" + esbuild "^0.18.2" + execa "^5.0.0" + globby "^11.0.3" + joycon "^3.0.1" + postcss-load-config "^4.0.1" + resolve-from "^5.0.0" + rollup "^3.2.5" + source-map "0.8.0-beta.0" + sucrase "^3.20.3" + tree-kill "^1.2.2" + tsutils@^3.21.0: version "3.21.0" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" From 8e76809c9bf13b6b541787632185898f57b1225b Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Tue, 19 Sep 2023 13:42:54 +0530 Subject: [PATCH 03/57] abstracted upload and delete functions --- .gitignore | 4 + packages/editor/{src => }/README.md | 0 packages/editor/package.json | 6 +- packages/editor/src/index.ts | 4 + .../editor/src/{style => styles}/editor.css | 0 packages/editor/src/styles/tailwind.css | 3 + packages/editor/src/types/delete-file.ts | 1 + packages/editor/src/types/upload-file.ts | 1 + .../editor/extensions/image/updated-image.tsx | 9 +- .../editor/src/ui/editor/extensions/index.tsx | 32 ++- .../ui/editor/extensions/slash-command.tsx | 22 +- packages/editor/src/{ => ui/editor}/index.tsx | 17 +- .../src/ui/editor/menus/bubble-menu/index.tsx | 2 +- .../menus/bubble-menu/link-selector.tsx | 5 +- .../menus/bubble-menu/node-selector.tsx | 2 +- .../utils/{link-validator.tsx => index.tsx} | 2 +- .../src/ui/editor/menus/table-menu/index.tsx | 4 +- .../src/ui/editor/plugins/delete-image.tsx | 10 +- .../src/ui/editor/plugins/upload-image.tsx | 35 ++- packages/editor/src/ui/editor/props.tsx | 6 +- packages/editor/src/utils.ts | 6 - packages/editor/tsconfig.json | 2 +- packages/editor/tsup.config.ts | 3 - packages/tsconfig/base.json | 11 +- .../{react-library.json => react.json} | 8 +- web/components/issues/description-form.tsx | 19 +- web/components/tiptap/index.tsx | 2 +- web/package.json | 3 +- web/services/file.service.ts | 2 + yarn.lock | 248 ++++++++++-------- 30 files changed, 272 insertions(+), 197 deletions(-) rename packages/editor/{src => }/README.md (100%) create mode 100644 packages/editor/src/index.ts rename packages/editor/src/{style => styles}/editor.css (100%) create mode 100644 packages/editor/src/styles/tailwind.css create mode 100644 packages/editor/src/types/delete-file.ts create mode 100644 packages/editor/src/types/upload-file.ts rename packages/editor/src/{ => ui/editor}/index.tsx (82%) rename packages/editor/src/ui/editor/menus/bubble-menu/utils/{link-validator.tsx => index.tsx} (92%) delete mode 100644 packages/editor/src/utils.ts rename packages/tsconfig/{react-library.json => react.json} (68%) diff --git a/.gitignore b/.gitignore index 1e99e102ad5..9439ea3acad 100644 --- a/.gitignore +++ b/.gitignore @@ -73,3 +73,7 @@ pnpm-lock.yaml pnpm-workspace.yaml .npmrc + + +## packages +dist diff --git a/packages/editor/src/README.md b/packages/editor/README.md similarity index 100% rename from packages/editor/src/README.md rename to packages/editor/README.md diff --git a/packages/editor/package.json b/packages/editor/package.json index 21861559145..e9e7cd079d0 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -27,11 +27,15 @@ "dependencies": { "@blueprintjs/popover2": "^2.0.10", "@tiptap/core": "^2.1.7", + "@tiptap/extension-blockquote": "^2.1.10", + "@tiptap/extension-bullet-list": "^2.1.10", "@tiptap/extension-code-block-lowlight": "^2.0.4", "@tiptap/extension-highlight": "^2.1.7", "@tiptap/extension-horizontal-rule": "^2.1.7", "@tiptap/extension-image": "^2.1.7", "@tiptap/extension-link": "^2.1.7", + "@tiptap/extension-list-item": "^2.1.10", + "@tiptap/extension-ordered-list": "^2.1.10", "@tiptap/extension-placeholder": "2.0.3", "@tiptap/extension-table": "^2.1.6", "@tiptap/extension-table-cell": "^2.1.6", @@ -43,7 +47,7 @@ "@tiptap/extension-underline": "^2.1.7", "@tiptap/pm": "^2.1.7", "@tiptap/react": "^2.1.7", - "@tiptap/starter-kit": "^2.1.7", + "@tiptap/starter-kit": "^2.1.10", "@tiptap/suggestion": "^2.1.7", "@types/node": "18.15.3", "@types/react": "18.0.28", diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts new file mode 100644 index 00000000000..2141d356b02 --- /dev/null +++ b/packages/editor/src/index.ts @@ -0,0 +1,4 @@ +import "@/styles/tailwind.css"; +import "@/styles/editor.css"; + +export { TipTapEditor } from "@/ui/editor"; diff --git a/packages/editor/src/style/editor.css b/packages/editor/src/styles/editor.css similarity index 100% rename from packages/editor/src/style/editor.css rename to packages/editor/src/styles/editor.css diff --git a/packages/editor/src/styles/tailwind.css b/packages/editor/src/styles/tailwind.css new file mode 100644 index 00000000000..b5c61c95671 --- /dev/null +++ b/packages/editor/src/styles/tailwind.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/packages/editor/src/types/delete-file.ts b/packages/editor/src/types/delete-file.ts new file mode 100644 index 00000000000..40bfffe2fd3 --- /dev/null +++ b/packages/editor/src/types/delete-file.ts @@ -0,0 +1 @@ +export type DeleteImage = (assetUrlWithWorkspaceId: string) => Promise; diff --git a/packages/editor/src/types/upload-file.ts b/packages/editor/src/types/upload-file.ts new file mode 100644 index 00000000000..bb2003b0c4b --- /dev/null +++ b/packages/editor/src/types/upload-file.ts @@ -0,0 +1 @@ +export type UploadImage = (workspaceSlug: string, formData: FormData) => Promise; diff --git a/packages/editor/src/ui/editor/extensions/image/updated-image.tsx b/packages/editor/src/ui/editor/extensions/image/updated-image.tsx index b620509535e..0162fc15af8 100644 --- a/packages/editor/src/ui/editor/extensions/image/updated-image.tsx +++ b/packages/editor/src/ui/editor/extensions/image/updated-image.tsx @@ -1,10 +1,11 @@ import Image from "@tiptap/extension-image"; -import TrackImageDeletionPlugin from "../plugins/delete-image"; -import UploadImagesPlugin from "../plugins/upload-image"; +import TrackImageDeletionPlugin from "@/ui/editor/plugins/delete-image"; +import UploadImagesPlugin from "@/ui/editor/plugins/upload-image"; +import { DeleteFileFunction } from "@/types/delete-file"; -const UpdatedImage = Image.extend({ +const UpdatedImage = (deleteImage: DeleteFileFunction) => Image.extend({ addProseMirrorPlugins() { - return [UploadImagesPlugin(), TrackImageDeletionPlugin()]; + return [UploadImagesPlugin(), TrackImageDeletionPlugin(deleteImage)]; }, addAttributes() { return { diff --git a/packages/editor/src/ui/editor/extensions/index.tsx b/packages/editor/src/ui/editor/extensions/index.tsx index e13d83a09f3..303a46c0680 100644 --- a/packages/editor/src/ui/editor/extensions/index.tsx +++ b/packages/editor/src/ui/editor/extensions/index.tsx @@ -10,23 +10,34 @@ import TaskList from "@tiptap/extension-task-list"; import { Markdown } from "tiptap-markdown"; import Highlight from "@tiptap/extension-highlight"; import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight"; -import { lowlight } from "lowlight/lib/core"; import { InputRule } from "@tiptap/core"; import Gapcursor from "@tiptap/extension-gapcursor"; +import OrderedList from "@tiptap/extension-ordered-list"; +import ListItem from "@tiptap/extension-list-item"; +import BulletList from "@tiptap/extension-bullet-list"; +import { Table } from "@/ui/editor/extensions/table/table"; +import { TableHeader } from "@/ui/editor/extensions/table/table-header"; +import { TableRow } from "@tiptap/extension-table-row"; +import { CustomTableCell } from "@/ui/editor/extensions/table/table-cell"; -import ts from "highlight.js/lib/languages/typescript"; +import UpdatedImage from "@/ui/editor/extensions/image/updated-image"; +import SlashCommand from "@/ui/editor/extensions/slash-command"; + +import { DeleteFileFunction } from "@/types/delete-file"; +import { UploadFileFunction } from "@/types/upload-file"; + +import isValidHttpUrl from "@/ui/editor/menus/bubble-menu/utils" +import ts from "highlight.js/lib/languages/typescript"; +import { lowlight } from "lowlight/lib/core"; import "highlight.js/styles/github-dark.css"; -import UniqueID from "@tiptap-pro/extension-unique-id"; -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); export const TiptapExtensions = ( workspaceSlug: string, + uploadFile: UploadFileFunction, + deleteFile: DeleteFileFunction, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void ) => [ StarterKit.configure({ @@ -100,7 +111,7 @@ export const TiptapExtensions = ( "text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer", }, }), - UpdatedImage.configure({ + UpdatedImage(deleteFile).configure({ HTMLAttributes: { class: "rounded-lg border border-custom-border-300", }, @@ -118,10 +129,7 @@ export const TiptapExtensions = ( }, includeChildren: true, }), - UniqueID.configure({ - types: ["image"], - }), - SlashCommand(workspaceSlug, setIsSubmitting), + SlashCommand(workspaceSlug, uploadFile, setIsSubmitting), TiptapUnderline, TextStyle, Color, diff --git a/packages/editor/src/ui/editor/extensions/slash-command.tsx b/packages/editor/src/ui/editor/extensions/slash-command.tsx index 9dd4d8f9366..76cbda8b9c8 100644 --- a/packages/editor/src/ui/editor/extensions/slash-command.tsx +++ b/packages/editor/src/ui/editor/extensions/slash-command.tsx @@ -17,8 +17,9 @@ import { ImageIcon, Table, } from "lucide-react"; -import { startImageUpload } from "../plugins/upload-image"; -import { cn } from "../utils"; +import { startImageUpload } from "@/ui/editor/plugins/upload-image"; +import { cn } from "@/lib/utils"; +import { UploadImage } from "@/types/upload-file"; interface CommandItemProps { title: string; @@ -59,6 +60,7 @@ const Command = Extension.create({ const getSuggestionItems = ( workspaceSlug: string, + uploadFile: UploadImage, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void ) => ({ query }: { query: string }) => @@ -114,6 +116,7 @@ const getSuggestionItems = searchTerms: ["unordered", "point"], icon: , command: ({ editor, range }: CommandProps) => { + // @ts-ignore editor.chain().focus().deleteRange(range).toggleBulletList().run(); }, }, @@ -146,6 +149,7 @@ const getSuggestionItems = searchTerms: ["ordered"], icon: , command: ({ editor, range }: CommandProps) => { + // @ts-ignore editor.chain().focus().deleteRange(range).toggleOrderedList().run(); }, }, @@ -155,13 +159,8 @@ const getSuggestionItems = searchTerms: ["blockquote"], icon: , command: ({ editor, range }: CommandProps) => - editor - .chain() - .focus() - .deleteRange(range) - .toggleNode("paragraph", "paragraph") - .toggleBlockquote() - .run(), + // @ts-ignore + editor.chain().focus().deleteRange(range).toggleNode("paragraph", "paragraph").toggleBlockquote().run(), }, { title: "Code", @@ -186,7 +185,7 @@ const getSuggestionItems = if (input.files?.length) { const file = input.files[0]; const pos = editor.view.state.selection.from; - startImageUpload(file, editor.view, pos, workspaceSlug, setIsSubmitting); + startImageUpload(file, editor.view, pos, workspaceSlug, uploadFile, setIsSubmitting); } }; input.click(); @@ -353,11 +352,12 @@ const renderItems = () => { export const SlashCommand = ( workspaceSlug: string, + uploadFile: UploadImage, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void ) => Command.configure({ suggestion: { - items: getSuggestionItems(workspaceSlug, setIsSubmitting), + items: getSuggestionItems(workspaceSlug, uploadFile, setIsSubmitting), render: renderItems, }, }); diff --git a/packages/editor/src/index.tsx b/packages/editor/src/ui/editor/index.tsx similarity index 82% rename from packages/editor/src/index.tsx rename to packages/editor/src/ui/editor/index.tsx index 1a692d8d0bc..d534d57eb86 100644 --- a/packages/editor/src/index.tsx +++ b/packages/editor/src/ui/editor/index.tsx @@ -1,12 +1,20 @@ +"use client" 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 { UploadImage } from '@/types/upload-file'; +import { DeleteImage } from '@/types/delete-file'; export interface ITipTapRichTextEditor { value: string; + uploadFile: UploadImage; + deleteFile: DeleteImage; noBorder?: boolean; borderOnFocus?: boolean; customClassName?: string; @@ -30,6 +38,8 @@ const Tiptap = (props: ITipTapRichTextEditor) => { setShouldShowAlert, editorContentCustomClassNames, value, + uploadFile, + deleteFile, noBorder, workspaceSlug, borderOnFocus, @@ -38,9 +48,10 @@ const Tiptap = (props: ITipTapRichTextEditor) => { const editor = useEditor({ editable: editable ?? true, - editorProps: TiptapEditorProps(workspaceSlug, setIsSubmitting), - extensions: TiptapExtensions(workspaceSlug, setIsSubmitting), - content: value, + editorProps: TiptapEditorProps(workspaceSlug, uploadFile, setIsSubmitting), + // @ts-ignore + extensions: TiptapExtensions(workspaceSlug, uploadFile, deleteFile, setIsSubmitting), + content: (typeof value === "string" && value.trim() !== "") ? value : "

", onUpdate: async ({ editor }) => { // for instant feedback loop setIsSubmitting?.("submitting"); diff --git a/packages/editor/src/ui/editor/menus/bubble-menu/index.tsx b/packages/editor/src/ui/editor/menus/bubble-menu/index.tsx index 217317ea105..9592cf6175f 100644 --- a/packages/editor/src/ui/editor/menus/bubble-menu/index.tsx +++ b/packages/editor/src/ui/editor/menus/bubble-menu/index.tsx @@ -4,7 +4,7 @@ import { BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, CodeIcon } from import { NodeSelector } from "./node-selector"; import { LinkSelector } from "./link-selector"; -import { cn } from "../utils"; +import { cn } from "@/lib/utils"; export interface BubbleMenuItem { name: string; diff --git a/packages/editor/src/ui/editor/menus/bubble-menu/link-selector.tsx b/packages/editor/src/ui/editor/menus/bubble-menu/link-selector.tsx index 559521db66f..4f82845069b 100644 --- a/packages/editor/src/ui/editor/menus/bubble-menu/link-selector.tsx +++ b/packages/editor/src/ui/editor/menus/bubble-menu/link-selector.tsx @@ -1,8 +1,9 @@ +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 { cn } from "../utils"; -import isValidHttpUrl from "./utils/link-validator"; +import isValidHttpUrl from "@/ui/editor/menus/bubble-menu/utils"; + interface LinkSelectorProps { editor: Editor; isOpen: boolean; diff --git a/packages/editor/src/ui/editor/menus/bubble-menu/node-selector.tsx b/packages/editor/src/ui/editor/menus/bubble-menu/node-selector.tsx index 34d40ec06d5..99918450699 100644 --- a/packages/editor/src/ui/editor/menus/bubble-menu/node-selector.tsx +++ b/packages/editor/src/ui/editor/menus/bubble-menu/node-selector.tsx @@ -1,3 +1,4 @@ +import { cn } from "@/lib/utils"; import { Editor } from "@tiptap/core"; import { Check, @@ -14,7 +15,6 @@ import { import { Dispatch, FC, SetStateAction } from "react"; import { BubbleMenuItem } from "."; -import { cn } from "../utils"; interface NodeSelectorProps { editor: Editor; diff --git a/packages/editor/src/ui/editor/menus/bubble-menu/utils/link-validator.tsx b/packages/editor/src/ui/editor/menus/bubble-menu/utils/index.tsx similarity index 92% rename from packages/editor/src/ui/editor/menus/bubble-menu/utils/link-validator.tsx rename to packages/editor/src/ui/editor/menus/bubble-menu/utils/index.tsx index 9af366c0266..b5add3f544e 100644 --- a/packages/editor/src/ui/editor/menus/bubble-menu/utils/link-validator.tsx +++ b/packages/editor/src/ui/editor/menus/bubble-menu/utils/index.tsx @@ -1,5 +1,5 @@ export default function isValidHttpUrl(string: string): boolean { - let url; + let url: URL; try { url = new URL(string); diff --git a/packages/editor/src/ui/editor/menus/table-menu/index.tsx b/packages/editor/src/ui/editor/menus/table-menu/index.tsx index 94f9c0f8d87..4b342e6e64d 100644 --- a/packages/editor/src/ui/editor/menus/table-menu/index.tsx +++ b/packages/editor/src/ui/editor/menus/table-menu/index.tsx @@ -1,11 +1,11 @@ import { useState, useEffect } from "react"; import { Rows, Columns, ToggleRight } from "lucide-react"; -import { cn } from "../utils"; -import { Tooltip } from "components/ui"; import InsertLeftTableIcon from "./InsertLeftTableIcon"; import InsertRightTableIcon from "./InsertRightTableIcon"; import InsertTopTableIcon from "./InsertTopTableIcon"; import InsertBottomTableIcon from "./InsertBottomTableIcon"; +import { cn } from "@/lib/utils"; +import { Tooltip } from "./tooltip"; interface TableMenuItem { command: () => void; diff --git a/packages/editor/src/ui/editor/plugins/delete-image.tsx b/packages/editor/src/ui/editor/plugins/delete-image.tsx index fdf515ccc99..a240cb2598d 100644 --- a/packages/editor/src/ui/editor/plugins/delete-image.tsx +++ b/packages/editor/src/ui/editor/plugins/delete-image.tsx @@ -1,6 +1,6 @@ import { EditorState, Plugin, PluginKey, Transaction } from "@tiptap/pm/state"; import { Node as ProseMirrorNode } from "@tiptap/pm/model"; -import fileService from "services/file.service"; +import { DeleteFileFunction } from "@/types/delete-file"; const deleteKey = new PluginKey("delete-image"); const IMAGE_NODE_TYPE = "image"; @@ -12,7 +12,7 @@ interface ImageNode extends ProseMirrorNode { }; } -const TrackImageDeletionPlugin = (): Plugin => +const TrackImageDeletionPlugin = (deleteImage: DeleteFileFunction): Plugin => new Plugin({ key: deleteKey, appendTransaction: (transactions: readonly Transaction[], oldState: EditorState, newState: EditorState) => { @@ -45,7 +45,7 @@ const TrackImageDeletionPlugin = (): Plugin => removedImages.forEach(async (node) => { const src = node.attrs.src; - await onNodeDeleted(src); + await onNodeDeleted(src, deleteImage); }); }); @@ -55,10 +55,10 @@ const TrackImageDeletionPlugin = (): Plugin => export default TrackImageDeletionPlugin; -async function onNodeDeleted(src: string): Promise { +async function onNodeDeleted(src: string, deleteImage: DeleteFileFunction): Promise { try { const assetUrlWithWorkspaceId = new URL(src).pathname.substring(1); - const resStatus = await fileService.deleteImage(assetUrlWithWorkspaceId); + const resStatus = await deleteImage(assetUrlWithWorkspaceId); if (resStatus === 204) { console.log("Image deleted successfully"); } diff --git a/packages/editor/src/ui/editor/plugins/upload-image.tsx b/packages/editor/src/ui/editor/plugins/upload-image.tsx index bc0acdc540d..99a963fd2cf 100644 --- a/packages/editor/src/ui/editor/plugins/upload-image.tsx +++ b/packages/editor/src/ui/editor/plugins/upload-image.tsx @@ -1,6 +1,6 @@ +import { UploadFileFunction, UploadImage } from "@/types/upload-file"; import { EditorState, Plugin, PluginKey } from "@tiptap/pm/state"; import { Decoration, DecorationSet, EditorView } from "@tiptap/pm/view"; -import fileService from "services/file.service"; const uploadKey = new PluginKey("upload-image"); @@ -58,6 +58,7 @@ export async function startImageUpload( view: EditorView, pos: number, workspaceSlug: string, + uploadFile: UploadImage, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void ) { if (!file.type.includes("image/")) { @@ -86,7 +87,7 @@ export async function startImageUpload( return; } setIsSubmitting?.("submitting"); - const src = await UploadImageHandler(file, workspaceSlug); + const src = await UploadImageHandler(file, workspaceSlug, uploadFile); const { schema } = view.state; pos = findPlaceholder(view.state, id); @@ -100,7 +101,9 @@ export async function startImageUpload( view.dispatch(transaction); } -const UploadImageHandler = (file: File, workspaceSlug: string): Promise => { +const UploadImageHandler = (file: File, workspaceSlug: string, + uploadFile: UploadFileFunction +): Promise => { if (!workspaceSlug) { return Promise.reject("Workspace slug is missing"); } @@ -110,18 +113,26 @@ const UploadImageHandler = (file: File, workspaceSlug: string): Promise formData.append("attributes", JSON.stringify({})); return new Promise(async (resolve, reject) => { - const imageUrl = await fileService - .uploadFile(workspaceSlug, formData) - .then((response) => response.asset); + try { + const imageUrl = await uploadFile(workspaceSlug, formData) + .then((response: { asset: string }) => response.asset); - const image = new Image(); - image.src = imageUrl; - image.onload = () => { - resolve(imageUrl); - }; + 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) { - console.log(error); + if (error instanceof Error) { + console.log(error.message); + } return Promise.reject(error); } }; diff --git a/packages/editor/src/ui/editor/props.tsx b/packages/editor/src/ui/editor/props.tsx index 9c478024b49..3de3294bf8a 100644 --- a/packages/editor/src/ui/editor/props.tsx +++ b/packages/editor/src/ui/editor/props.tsx @@ -1,9 +1,11 @@ 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-file"; export function TiptapEditorProps( workspaceSlug: string, + uploadFile: UploadImage, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void ): EditorProps { return { @@ -35,7 +37,7 @@ export function TiptapEditorProps( event.preventDefault(); const file = event.clipboardData.files[0]; const pos = view.state.selection.from; - startImageUpload(file, view, pos, workspaceSlug, setIsSubmitting); + startImageUpload(file, view, pos, workspaceSlug, uploadFile, setIsSubmitting); return true; } return false; @@ -59,7 +61,7 @@ export function TiptapEditorProps( }); // 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, setIsSubmitting); + startImageUpload(file, view, coordinates.pos - 1, workspaceSlug, uploadFile, setIsSubmitting); } return true; } diff --git a/packages/editor/src/utils.ts b/packages/editor/src/utils.ts deleted file mode 100644 index a5ef193506d..00000000000 --- a/packages/editor/src/utils.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { clsx, type ClassValue } from "clsx"; -import { twMerge } from "tailwind-merge"; - -export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)); -} diff --git a/packages/editor/tsconfig.json b/packages/editor/tsconfig.json index 8a6aeae90c2..9799dcdfcd9 100644 --- a/packages/editor/tsconfig.json +++ b/packages/editor/tsconfig.json @@ -2,8 +2,8 @@ "extends": "tsconfig/react.json", "include": ["."], "exclude": ["dist", "build", "node_modules"], + "compilerOptions": { - "jsx": "react-jsx", "baseUrl": ".", "paths": { "@/*": ["src/*"] diff --git a/packages/editor/tsup.config.ts b/packages/editor/tsup.config.ts index 1173495ddbb..236e425ed30 100644 --- a/packages/editor/tsup.config.ts +++ b/packages/editor/tsup.config.ts @@ -2,9 +2,6 @@ import { defineConfig, Options } from "tsup"; export default defineConfig((options: Options) => ({ entry: ["src/index.ts"], - banner: { - js: "'use client'", - }, format: ["cjs", "esm"], dts: true, clean: true, diff --git a/packages/tsconfig/base.json b/packages/tsconfig/base.json index d72a9f3a278..0659d31a203 100644 --- a/packages/tsconfig/base.json +++ b/packages/tsconfig/base.json @@ -14,7 +14,14 @@ "noUnusedParameters": false, "preserveWatchOutput": true, "skipLibCheck": true, - "strict": true + "strict": true, + "paths": { + "@/*": [ + "./*" + ] + } }, - "exclude": ["node_modules"] + "exclude": [ + "node_modules" + ] } diff --git a/packages/tsconfig/react-library.json b/packages/tsconfig/react.json similarity index 68% rename from packages/tsconfig/react-library.json rename to packages/tsconfig/react.json index bdd954367b0..ab1283da77f 100644 --- a/packages/tsconfig/react-library.json +++ b/packages/tsconfig/react.json @@ -3,9 +3,11 @@ "display": "React Library", "extends": "./base.json", "compilerOptions": { - "jsx": "react", - "lib": ["ES2015"], + "lib": [ + "DOM" + ], "module": "ESNext", - "target": "es6" + "target": "ES6", + "jsx": "react-jsx" } } diff --git a/web/components/issues/description-form.tsx b/web/components/issues/description-form.tsx index 54ea0a9760d..215a0f50264 100644 --- a/web/components/issues/description-form.tsx +++ b/web/components/issues/description-form.tsx @@ -7,9 +7,10 @@ import useReloadConfirmations from "hooks/use-reload-confirmation"; import { useDebouncedCallback } from "use-debounce"; // components import { TextArea } from "components/ui"; -import { TipTapEditor } from "components/tiptap"; // types import { IIssue } from "types"; +import { TipTapEditor } from "plane-editor" +import fileService from "services/file.service"; export interface IssueDescriptionFormValues { name: string; @@ -115,9 +116,8 @@ export const IssueDescriptionForm: FC = ({ {characterLimit && isAllowed && (
255 ? "text-red-500" : "" - }`} + className={`${watch("name").length === 0 || watch("name").length > 255 ? "text-red-500" : "" + }`} > {watch("name").length} @@ -135,10 +135,12 @@ export const IssueDescriptionForm: FC = ({ return (

" : value } @@ -164,9 +166,8 @@ export const IssueDescriptionForm: FC = ({ }} />
{isSubmitting === "submitting" ? "Saving..." : "Saved"}
diff --git a/web/components/tiptap/index.tsx b/web/components/tiptap/index.tsx index 84f691c35d5..a1e730e24a6 100644 --- a/web/components/tiptap/index.tsx +++ b/web/components/tiptap/index.tsx @@ -43,7 +43,7 @@ const Tiptap = (props: ITipTapRichTextEditor) => { editable: editable ?? true, editorProps: TiptapEditorProps(workspaceSlug, setIsSubmitting), extensions: TiptapExtensions(workspaceSlug, setIsSubmitting), - content: value, + content: (typeof value === "string" && value.trim() !== "") ? value : "

", onUpdate: async ({ editor }) => { // for instant feedback loop setIsSubmitting?.("submitting"); diff --git a/web/package.json b/web/package.json index a144bba0781..8a12f8ec55e 100644 --- a/web/package.json +++ b/web/package.json @@ -80,7 +80,8 @@ "tiptap-markdown": "^0.8.2", "tlds": "^1.238.0", "use-debounce": "^9.0.4", - "uuid": "^9.0.0" + "uuid": "^9.0.0", + "plane-editor": "*" }, "devDependencies": { "@types/js-cookie": "^3.0.2", diff --git a/web/services/file.service.ts b/web/services/file.service.ts index cbed73fc897..53e3db810fb 100644 --- a/web/services/file.service.ts +++ b/web/services/file.service.ts @@ -29,6 +29,8 @@ interface UnSplashImageUrls { class FileServices extends APIService { constructor() { super(API_BASE_URL); + this.uploadFile = this.uploadFile.bind(this); + this.deleteImage = this.deleteImage.bind(this); } async uploadFile(workspaceSlug: string, file: FormData): Promise { diff --git a/yarn.lock b/yarn.lock index aa733418ded..d2bca703d7f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2328,6 +2328,16 @@ dependencies: tslib "^2.4.0" +"@tailwindcss/typography@^0.5.10": + version "0.5.10" + resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.10.tgz#2abde4c6d5c797ab49cf47610830a301de4c1e0a" + integrity sha512-Pe8BuPJQJd3FfRnm6H0ulKIGoMEQS+Vq01R6M5aCrFB/ccR/shT+0kXLjouGC1gFLm9hopTFN+DMP0pfwRWzPw== + dependencies: + lodash.castarray "^4.4.0" + lodash.isplainobject "^4.0.6" + lodash.merge "^4.6.2" + postcss-selector-parser "6.0.10" + "@tailwindcss/typography@^0.5.9": version "0.5.9" resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.9.tgz#027e4b0674929daaf7c921c900beee80dbad93e8" @@ -2345,36 +2355,36 @@ dependencies: uuid "^8.3.2" +"@tiptap/core@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.1.10.tgz#6d8f3c777f1700dcc6c903b1185576754175e366" + integrity sha512-yhUKsac6nlqbPQfwQnp+4Jb110EqmzocXKoZacLwzHpM7JVsr2+LXMDu9kahtrvHNJErJljhnQvDHRsrrYeJkQ== + "@tiptap/core@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.1.7.tgz#9823a3712d176849cfd281dd8229ad0719c9eb9e" integrity sha512-1pqTwlTnwTKQSNQmmTWhs2lwdvd+hFFNFZnrRAfvZhQZA6qPmPmKMNTcYmK38Tn4axKth6mhBamzTJgMZFI7ng== -"@tiptap/core@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.1.8.tgz#4555dc7d86580dee790d4aded1ce7fb79319da70" - integrity sha512-QTGgqki7hkonLJ93gWqCUkD6cCAQ3rEX9gbMLwzfnegIZ+/BKLQYKYCozsEMZnMPXgdRrKuyRBOL+RH+IolMeA== +"@tiptap/extension-blockquote@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.1.10.tgz#dc475bef70dd460fc730a14b3b4cc18f37cd1b2d" + integrity sha512-lpBF/a+qgv4Bdf7HYisTkMFdFdGfn2SqspsydvG8UI7N9B/PfnCCrtoMaC3bqTaT6u8ZVxyM3Y3vnq2AxXJvBw== "@tiptap/extension-blockquote@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.1.7.tgz#fe25ec1dedd1f7e3eb1a851a6ac8738ca4691a17" integrity sha512-oAsUU1c0DDZKHwK7/uCtYpnTUQt0o3w+SsJSv4S2vlSHidiFl9gCQGozUQ/Alzc7GO1Y95rOscL28DJXgXESQg== -"@tiptap/extension-blockquote@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.1.8.tgz#eb3f70d03807b2d51645cf5450a1e84ccb53633b" - integrity sha512-NhTE90ZDb/BbtkgeNjwLYPYMryAfCXCM+Zpk8AMsVODZ+bDy+lsqpnDw7uRxUK3guLMnqKgSe2eTaXqx7AKE+A== +"@tiptap/extension-bold@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.1.10.tgz#fb71c2575087d3d2a9c6d214b3c1587da931cc61" + integrity sha512-I43WCwc7pyz5vtKGj24Rjv7HN0EK5S4PlADQPBuhC1qQvfCTFvjrBB6ZmsekUMGmllW0qMOFVLSjtffpckqshA== "@tiptap/extension-bold@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.1.7.tgz#c5d89284235d75c2e65745b50a5c0681be1cbab6" integrity sha512-GZV2D91WENkWd1W29vM4kyGWObcxOKQrY8MuCvTdxni1kobEc/LPZzQ1XiQmiNTvXTMcBz5ckLpezdjASV1dNg== -"@tiptap/extension-bold@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.1.8.tgz#2047345c814cad672d150b303436928d46aecbc1" - integrity sha512-rDdmir78a0JTiV+vrycGh3yS1ZzRF1bRvBt4jr7Rne0LOl03kc7Wm936ommiL3McWUpZZV37ZpCm5JfE8rQb+w== - "@tiptap/extension-bubble-menu@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.1.7.tgz#62616c9ee456c8413ad6c120757978266052a1a0" @@ -2389,66 +2399,66 @@ dependencies: tippy.js "^6.3.7" +"@tiptap/extension-bullet-list@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.1.10.tgz#e7d7fb578502da6c6208a4daa3e2fe4249ae6280" + integrity sha512-e6aFr29OSOmXsjFZB2zt3p8aeCWOx0C9Ayrpdf4QBUCOUJtt6FQPxxiYc+XZcdrYbLGLznA7QJlulCK9SGv2Fw== + "@tiptap/extension-bullet-list@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.1.7.tgz#3a7356824a931122314a6bd73b5f9d8a8a313791" integrity sha512-BReix1wkGNH12DSWGnWPKNu4do92Avh98aLkRS1o1V1Y49/+YGMYtfBXB9obq40o0WqKvk4MoM+rhKbfEc44Gg== -"@tiptap/extension-bullet-list@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.1.8.tgz#d9d4ee46d1adb2b70d3b8c19540ebcdd8a1eaaec" - integrity sha512-VWj3XZMwJQVb7e4ZM0N+o6o+905lyMMS4C35yw/sxN5CDw4TJpQMSPSAmBVNtK469XUdlGOxeLc/+Q00aU+S8A== - "@tiptap/extension-code-block-lowlight@^2.0.4": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.1.7.tgz#713dad4324c9ce25c66768fc4cfdb514ecea21c7" integrity sha512-GOmpe3bwjlhMC79vFICInkJwaHx5dTiKQCTzdjZ5qRsvKgk/0YTrmWaN+w+JW5BBUaChj8IrgAPy7VZ20l7GKQ== +"@tiptap/extension-code-block@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.1.10.tgz#a125a12f716728b271a130178c6fc60237ed46f5" + integrity sha512-M+s89V9mP3tOoS6p/X2Dzw/Z7Fcg9EF0ZXlsMNifdlpwJlhAIYxI7vjPBmkMAFXTDB5eMZblXyNQaZ7v6V2Yeg== + "@tiptap/extension-code-block@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.1.7.tgz#c087c22c305f3c87645228ad32f32595dde7f2a2" integrity sha512-uiasfWCIQuk34vGoIENqAJOHf9m3hAkcELnb9T6+uNxA3O7PUZQqBVN/27oEipj7j15pqua50D6C1jql9kFe0g== -"@tiptap/extension-code-block@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.1.8.tgz#d2dccf64a583bfb12e2ebd04b3724b7e9430549d" - integrity sha512-EjegLBBz8ATvIuJlqosGrcOsKNu8YveI8rogGfUmnXWMNcPSSqBDoWK2EpLTUzGccPWRxo7yBsr5wItikfPPYA== +"@tiptap/extension-code@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.1.10.tgz#704798f90a32d6166ce96dc65ef4a541f424f895" + integrity sha512-1yy/kR0FAeMkDdAt1LW/FH6vlyZLqLZqY6BM+wBCiGrr+XeA5FTXih9iT/4gbTRuIzG0EPqx18nvroG7hUsWBg== "@tiptap/extension-code@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.1.7.tgz#bad3b1aedc23123a2094f8810801edb0c13acbff" integrity sha512-g0IA6Q6DFZE0AEOMXAV1mktl/XzIO3s1h/haPIKZ8GNes522qhBr9FYc5OUPQCCbgYjL7soTGzxA/W5Jk3f2AQ== -"@tiptap/extension-code@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.1.8.tgz#c3dccd1a12972cab8d0c98f75a3960bab64905bd" - integrity sha512-dQL8aUYzSEkES5P4sBYZ6SiCMnFK1cUKKGruaRV1TJyFu/ClZ8Y+BKS2GCCMcyH0tKjqsibYsNFBWz9/Q5gjEg== - "@tiptap/extension-color@^2.0.4": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-color/-/extension-color-2.1.7.tgz#7f436aed2f41087d8de6af6a4dd4cb7d964354dd" integrity sha512-NLspH5taSpZP60rXJjDKu8AP9VDd+dlqz4guxvijtuPEePw87Fzidxx9w6X0uYQfx1O0xdPFq3UodlDz591scA== +"@tiptap/extension-document@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.1.10.tgz#6d2ab2301c86139d711fa460a311aa2c8bb343f8" + integrity sha512-jNlNGQIGg471DvzhADaEoRINa3LNghowrBbKK9d5wGVnbKRykNEPwjCf8zNl+m5NBmCZl3lsdznlwBk5zyh5Bg== + "@tiptap/extension-document@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.1.7.tgz#5e1d56e899fdca8ebfad1b7cb358d5ace664b851" integrity sha512-tZyoPPmvzti7PEnyulXomEtINd/Oi2S84uOt6gw7DTCnDq5bF5sn1IfN8Icqp9t4jDwyLXy2TL0Zg/sR0a2Ibg== -"@tiptap/extension-document@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.1.8.tgz#fa4dce27fd5d25b54f7e7e9a93db69606a624b96" - integrity sha512-mLPZqd5QUv3FKo+5zOaf7dGqZPci7Myr92U1Y6Vw0V+hCRC9Emm3I/xssQYGsWXmXQuyNJ5WRlpXgag3Ae+CkA== +"@tiptap/extension-dropcursor@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.1.10.tgz#490c9aa82656592c9820c55214381fb9bfea92f2" + integrity sha512-GhsWsCq6wLb8HJ32BeAm7ndv4lPyu1F7FFwmnARzEF5q54FV20kWSv2zC+Dv0dTvynXR3quXybdUM92xeNDovw== "@tiptap/extension-dropcursor@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.1.7.tgz#a3f79b7453579f36f326852b16e421601e881a28" integrity sha512-hNk2BuLnNSXlGOQphlzdpFKCKo7uHUFjWuBfzF1S9FMAQgcN7eTia+cCClmXABYfVLW4fT14PC1KiuGjxi9MuA== -"@tiptap/extension-dropcursor@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.1.8.tgz#f7128aebe9e2bb05cd6508d782deaf436ae3c46e" - integrity sha512-KilbUHApYya2Q6brq5qW+B+pPkb6lvgnjRfuFuv6doM/v+lfEdozUE1Ma8C19UXtzl7BmPDut9HRMDL17Pqwyg== - "@tiptap/extension-floating-menu@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.1.7.tgz#fe2def740b3136d38101634ae60d2fec5468c57e" @@ -2463,36 +2473,36 @@ dependencies: tippy.js "^6.3.7" +"@tiptap/extension-gapcursor@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.1.10.tgz#712853ce82642108e50a37014d585ff72af6758d" + integrity sha512-WSBT9X7dzg0HyMoMP/Yyxl28QwIJO90YzobI9z5mav86BQv7C5wU0fQSpbpAbsN3s7lxKhPwNrXkwkpnXT4ZCA== + "@tiptap/extension-gapcursor@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.1.7.tgz#5c0303ba37b4c066f3a3c5835fd0b298f0d3e919" integrity sha512-7eoInzzk1sssoD3RMkwFC86U15Ja4ANve+8wIC+xhN4R3Oe3PY3lFbp1GQxCmaJj8b3rtjNKIQZ2zO0PH58afA== -"@tiptap/extension-gapcursor@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.1.8.tgz#bc7e745fdc8990a8e370c4c728ab8733ba0910c4" - integrity sha512-0EQgV/kF2dg2dOpw0fTbwwNaubwS8QNhEPPbnXQP8xqZpupuia+DKKgC+ttzbE9XhS4Sv1fGib52Sr7MMIduhA== +"@tiptap/extension-hard-break@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.1.10.tgz#e885e83d936b45891bf4dc40c713d042f84eb8c4" + integrity sha512-sYrzpPoV5jQri+duGb50nDTs+hOBQDxXTKlJuZNFfZMwgx6epwxb8xICcGAUJFShuuW8UAWCNcB4jG9tMqgvyw== "@tiptap/extension-hard-break@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.1.7.tgz#1cd783adfe2788d41614f8851b8d7a52ec027cce" integrity sha512-6gFXXlCGAdXjy27BW29q4yfCQPAEFd18k7zRTnbd4aE/zIWUtLqdiTfI3kotUMab9Tt9/z1BRmCbEUxRsf1Nww== -"@tiptap/extension-hard-break@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.1.8.tgz#b898c3c9c7f96726307bd51b24f557731e25d12e" - integrity sha512-K86FTizvZu7779Gz2XigW1IxAjZXduyZ7w0ipwe+5QBa/Lh6Vfl9wa8TgV1lFAkC2VATsAa3aa36llMIDBgeew== +"@tiptap/extension-heading@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.1.10.tgz#1b32726551466c29987861181966e5675417b28c" + integrity sha512-1OgmrRPMcY52WI7I4799xd4eIsEX/bI813B8mZvNYXLzZI75pLW1hmz1mUvBYyMwlcek74zVTGYgPy11o+2JEg== "@tiptap/extension-heading@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.1.7.tgz#26d16227eab95b1f381e977f7aa1685f493c6fb5" integrity sha512-jMeTqtq3kbMFtMvUb3SeIt4FFM3W+b6TAw5H4Qd6z3gYsAU3GahRK67MtbJfPmznUkZfimrqW9VCaBezScfrsQ== -"@tiptap/extension-heading@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.1.8.tgz#d34db2bdfca559567ecb6f741fa4eb5d4d54a897" - integrity sha512-6PHWzhGPC/QjfswlflU1Cy2UYZiyzwa639bWW7Dl4BHZgK+e09lbc7RwzPrrex6+jA10K4nlww19xsI590ogBw== - "@tiptap/extension-highlight@^2.0.4": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.1.7.tgz#0f9434eedfdcb95a22ca5b6f601d13f4343a7e5c" @@ -2503,25 +2513,25 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.1.8.tgz#b2d2d995344e06dd36cd8a395a72113b87981bd7" integrity sha512-OCXtFWCbwsgOHq7IP4Qr02EfjwYeRRcuL1ipv0LojGtMcvnkw7OLhQZ8oocrqi4/6QCOtPLSGlcqrQ6pmN7jww== +"@tiptap/extension-history@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.1.10.tgz#efa60d657a76818361a3af14769660672d4bc227" + integrity sha512-tApuN8MIJMzc0dxvkYJPt3t5cea9NuZBGNiuVedJwMMUF6hbFpMZAt20GW2qwjBaZ76rQwbLp1s3KnImFsPe5A== + "@tiptap/extension-history@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.1.7.tgz#baa566875ef1278c5dd8821970362d85348b266c" integrity sha512-8SIEKSImrIkqJThym1bPD13sC4/76UrG+piQ30xKQU4B7zUFCbutvrwYuQHSRvaEt8BPdTv2LWIK+wBkIgbWVA== -"@tiptap/extension-history@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.1.8.tgz#68a65b51effc1d612e3862928c3ccede3ce83592" - integrity sha512-Cyq4YsmosfgHGlaf2wiiU8VaLweUMG8LHuhZ5A2RAoriy3G09Bqgn6eqLmho8KoU1VgvffXTVBaYKxz9gVgu3w== - "@tiptap/extension-horizontal-rule@^2.0.4", "@tiptap/extension-horizontal-rule@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.1.7.tgz#7c21bc4917e4ced9382e81626e0f0068b224bfbb" integrity sha512-hJupsDxDVmjmKI/Ewl/gtiyUx52Y3wRUhT8dCXNOA5eldmPXN23E2Fa2BC8XB47dyc5pubyNcLuqaLeaZ5hedw== -"@tiptap/extension-horizontal-rule@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.1.8.tgz#db23468176fd5359240feb8601fd3fcf747d5e6d" - integrity sha512-qUNz8p/p3gth0ueYFkmMdVRcRVmtCwQGJsHWwbx23XrF/a7AJ0FSdiW0sk8YD6Dbw+i1cB3cnRyO+qq9XuWdqw== +"@tiptap/extension-horizontal-rule@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.1.10.tgz#cfdb67530be100054fc8511942d4ec3534acf828" + integrity sha512-91lGpK2d6WMPhrMDPBURS8z8pEg1CUBYy7GmBenKvvgh+JzVhG+U6MtykfWNfm2R4iRXOl1xLbyUOCiOSUXodQ== "@tiptap/extension-image@^2.0.4": version "2.1.7" @@ -2533,16 +2543,16 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.1.8.tgz#99d78ad1d8c6f513f945beae7de352759f30189f" integrity sha512-o+vUIYLvYcJHftIMoIukzZZ+fTTfC/gXXvQIYz51p3f1qeYXszD11FbtkaJCgXYj8BcGCO7QuzcCdQg+wyROZw== +"@tiptap/extension-italic@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.1.10.tgz#7183119c8c61beb2ac635ca3c2066624530b4a56" + integrity sha512-ebw5m+rWx6K5UoBVXSkz3fpvDJh/wScfYmwl6pkbjc2jNbZiln2LSiLHYc2eIYJ2aTsVxcw/n0Azfk5Lb19InA== + "@tiptap/extension-italic@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.1.7.tgz#d077683597d4282ae272c48b313d768d71985b67" integrity sha512-7e37f+OFqisdY19nWIthbSNHMJy4+4dec06rUICPrkiuFaADj5HjUQr0dyWpL/LkZh92Wf/rWgp4V/lEwon3jA== -"@tiptap/extension-italic@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.1.8.tgz#b559c8d6b387e292e047985acd0def48a80a7aa0" - integrity sha512-cR6kSoMraA/dCdwmus8A09WAwpxiZiGG+B0OqsludGF+MdZLilhoGyXDbTeO3aKoKccfqxZGk1YKK13C/gRM1Q== - "@tiptap/extension-link@^2.0.4": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.1.7.tgz#2705c212d105ccf411d505e334ece4a723971ee4" @@ -2557,36 +2567,36 @@ dependencies: linkifyjs "^4.1.0" +"@tiptap/extension-list-item@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.1.10.tgz#0615e4fb68161e6457e6041e195f454bfd537d44" + integrity sha512-rRRyB14vOcSjTMAh8Y+50TRC/jO469CelGwFjOLrK1ZSEag5wmLDaqpWOOb52BFYnvCHuIm1HqZtdL5bTI/J1w== + "@tiptap/extension-list-item@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.1.7.tgz#dc24045e445d0f91baec9b113f711dc90c6682ac" integrity sha512-hd/E4qQopBXWa6kdFY19qFVgqj4fzdPgAnzdXJ2XW7bC6O2CusmHphRRZ5FBsuspYTN/6/fv0i0jK9rSGlsEyA== -"@tiptap/extension-list-item@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.1.8.tgz#b5dc1e04bfb96ca10a0821821ade5014fa188dbb" - integrity sha512-fiYVRhHvcXMcVuuiXBx/0AFWwGoKzs9784VSuVUeSSzSuH6vOchM1kZCH+v6acs7vltFKNDrluyEiwGIz1b8qA== +"@tiptap/extension-ordered-list@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.1.10.tgz#ef5d5ba68baf86e9b66c1b2c1cec458aa111ad44" + integrity sha512-jouo3RHUMxU4dPzZcfZdUzmsLVp1KHrLIAD2YAxBuqArACrBNfJpIhtkTKuGLlaFhKqGr+EmNdNQnK8JOBhLtQ== "@tiptap/extension-ordered-list@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.1.7.tgz#72d9ddc432ecf0fd19c8acd3c6b44f5358d8e0d0" integrity sha512-3XIXqbZmYkNzF+8PQ2jcCOCj0lpC3y9HGM/+joPIunhiUiktrIgpbUDv2E1Gq5lJHYqthIeujniI2dB85tkwJQ== -"@tiptap/extension-ordered-list@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.1.8.tgz#f489ac85ccd93ad811318bed6af7906c035ba313" - integrity sha512-qTVSWTlSjFNRwPNmWmfe9TsW9XL3LQCNJsfaBxtVZfhDN9rhoIZ6rPTBO7f2TTiPK1+uyLTvK+znWYvU9RtD5A== +"@tiptap/extension-paragraph@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.1.10.tgz#ee1238d2d6e9460b2a929b05a5fd43cfb58a6017" + integrity sha512-kzuHbrxcxpWkha5P+JFzCKT54pNqb4IBKMU5qT9YGhZSdNTtU63ncdCHM+Ad1ukLuvXAv95zh1IQC5j+Z1Qk4A== "@tiptap/extension-paragraph@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.1.7.tgz#76408706f0037a510a384b86780bd50c6e8ffeea" integrity sha512-cLqX27hNrXrwZCKrIW8OC3rW2+MT8hhS37+cdqOxZo5hUqQ9EF/puwS0w8uUZ7B3awX9Jm1QZDMjjERLkcmobw== -"@tiptap/extension-paragraph@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.1.8.tgz#f337c3f84cbfddd1ea16860e934f2049c46211ce" - integrity sha512-ZuwvwKaG5GeoYRgeh96PToLk2TjxsLiZKnLN6rkUCsW6aLoseK7/8/7vm3dP2N9dAUN35ESw0/pRk2Q/VK1/+g== - "@tiptap/extension-placeholder@2.0.3": version "2.0.3" resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.0.3.tgz#69575353f09fc7524c9cdbfbf16c04f73c29d154" @@ -2597,16 +2607,16 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.1.7.tgz#8477cf5116c89f0f75e8e2e3b8528e146a7f0f24" integrity sha512-IiBoItYYNS7hb/zmPitw3w6Cylmp9qX+zW+QKe3lDkCNPeKxyQr86AnVLcQYOuXg62cLV9dp+4azZzHoz9SOcg== +"@tiptap/extension-strike@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.1.10.tgz#ec311395d16af15345b63d2dac2d459b9ad5fa9e" + integrity sha512-KW63lZLPFIir5AIeh2I7UK6Tx1O3jetD7JIPUzEqp1I1BfJlHGHVQxV8VXAmJl0hTOzjQBsHW42PmBxSC97NUg== + "@tiptap/extension-strike@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.1.7.tgz#b7b7f49254f1de22416b1415ca88a2a20edd0627" integrity sha512-ONLXYnuZGM2EoGcxkyvJSDMBeAp7K6l83UXkK9TSj+VpEEDdeV7m8mJs8/vACJjJxD5HMN61+EPgU7VTEukQCA== -"@tiptap/extension-strike@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.1.8.tgz#ba6966a9afb9493d8bd30d4c617ffe6966b90379" - integrity sha512-JGPiGudEZAKTiOirua9gtDG+HILHEx4CGODW5PDBMA1xYDfyo7ZJk5xgfJWZ1SOo7YviF26HSY4KKV9ThINq2Q== - "@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" @@ -2657,16 +2667,16 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-text-style/-/extension-text-style-2.1.8.tgz#42e9fa179f76d4e88f73f2c66aee3b06162e659b" integrity sha512-xnx/Pq5ttt2/gOQPmqVQIBz/jo3MErtYdYk22fUaOyu1xT36X4BDJYsrLyWhcs3aWR/tv1/XylbNOFvhrDOHoQ== +"@tiptap/extension-text@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.1.10.tgz#db297fb5d2ee50ef7a14650539e3d335f772f755" + integrity sha512-ubU/WQwNB0MVKyMAHr8ka3Nu3jCR03HARGKUwNRzppZYtRXWyXHNlAaJdplNb1NMGb8hd0ElBJmwFlVqmh8haQ== + "@tiptap/extension-text@^2.1.7": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.1.7.tgz#071053ab0a8804a3bce36d1488a603b7446dff4e" integrity sha512-3xaMMMNydLgoS+o+yOvaZF04ui9spJwJZl8VyYgcJKVGGLGRlWHrireXN5/OqXG2jLb/jWqXVx5idppQjX+PMA== -"@tiptap/extension-text@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.1.8.tgz#7f537d0c490feab8b800644e2ad24b6478c67044" - integrity sha512-ha7oTtUdcJdTVLr8CrxbNMucbAmOBCi83MLxdKZclVf1VpdIVpE3NTojfH2mnZCVMvtPhj4PILQp2hGO95SFig== - "@tiptap/extension-underline@^2.0.4": version "2.1.7" resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-2.1.7.tgz#ab815645770f7d2013ac69327975837b4937c8df" @@ -2766,30 +2776,30 @@ "@tiptap/extension-strike" "^2.1.7" "@tiptap/extension-text" "^2.1.7" -"@tiptap/starter-kit@^2.1.7": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.1.8.tgz#d33f04478cd7b4956cb312335bcbed109269b651" - integrity sha512-LfCQgENw501XyTbCEcmiKt1d7XQi+6nTrQQfI16cCwc7lqp+LREz9EOFidkjTtrKuUHwlTaZzS7C76Cfc87mXA== - dependencies: - "@tiptap/core" "^2.1.8" - "@tiptap/extension-blockquote" "^2.1.8" - "@tiptap/extension-bold" "^2.1.8" - "@tiptap/extension-bullet-list" "^2.1.8" - "@tiptap/extension-code" "^2.1.8" - "@tiptap/extension-code-block" "^2.1.8" - "@tiptap/extension-document" "^2.1.8" - "@tiptap/extension-dropcursor" "^2.1.8" - "@tiptap/extension-gapcursor" "^2.1.8" - "@tiptap/extension-hard-break" "^2.1.8" - "@tiptap/extension-heading" "^2.1.8" - "@tiptap/extension-history" "^2.1.8" - "@tiptap/extension-horizontal-rule" "^2.1.8" - "@tiptap/extension-italic" "^2.1.8" - "@tiptap/extension-list-item" "^2.1.8" - "@tiptap/extension-ordered-list" "^2.1.8" - "@tiptap/extension-paragraph" "^2.1.8" - "@tiptap/extension-strike" "^2.1.8" - "@tiptap/extension-text" "^2.1.8" +"@tiptap/starter-kit@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.1.10.tgz#5f19c199c79d90ef5e3b8990ca3aa76ce625d68c" + integrity sha512-h5mH1qv7SDFXWZPbOWC8zpGZ62EnDizRNtM45Gani0HYWJXcbPFpgN1qJmESP/jP+v+0hxtnVEkgfpiy3LRm6A== + dependencies: + "@tiptap/core" "^2.1.10" + "@tiptap/extension-blockquote" "^2.1.10" + "@tiptap/extension-bold" "^2.1.10" + "@tiptap/extension-bullet-list" "^2.1.10" + "@tiptap/extension-code" "^2.1.10" + "@tiptap/extension-code-block" "^2.1.10" + "@tiptap/extension-document" "^2.1.10" + "@tiptap/extension-dropcursor" "^2.1.10" + "@tiptap/extension-gapcursor" "^2.1.10" + "@tiptap/extension-hard-break" "^2.1.10" + "@tiptap/extension-heading" "^2.1.10" + "@tiptap/extension-history" "^2.1.10" + "@tiptap/extension-horizontal-rule" "^2.1.10" + "@tiptap/extension-italic" "^2.1.10" + "@tiptap/extension-list-item" "^2.1.10" + "@tiptap/extension-ordered-list" "^2.1.10" + "@tiptap/extension-paragraph" "^2.1.10" + "@tiptap/extension-strike" "^2.1.10" + "@tiptap/extension-text" "^2.1.10" "@tiptap/suggestion@^2.0.4": version "2.1.7" @@ -3425,7 +3435,7 @@ attr-accept@^2.2.2: resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b" integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== -autoprefixer@^10.4.13, autoprefixer@^10.4.14, autoprefixer@^10.4.7: +autoprefixer@^10.4.14, autoprefixer@^10.4.15: version "10.4.15" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.15.tgz#a1230f4aeb3636b89120b34a1f513e2f6834d530" integrity sha512-KCuPB8ZCIqFdA4HwKXsvz7j6gvSDNhDP7WnUjBleRkKjPdvCmHFuQ77ocavI8FT6NdvlBnE2UFr2H4Mycn8Vew== @@ -6130,6 +6140,11 @@ lucide-react@^0.263.1: resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.263.1.tgz#a456ee0d171aa373929bd3ee20d6f9fb4429c301" integrity sha512-keqxAx97PlaEN89PXZ6ki1N8nRjGWtDa4021GFYLNj0RgruM5odbpl8GHTExj0hhPq3sF6Up0gnxt6TSHu+ovw== +lucide-react@^0.269.0: + version "0.269.0" + resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.269.0.tgz#610a4c85dd60b0e1826842ec563eb9bc9b249be5" + integrity sha512-+ViEb/2eJJt43/CtxpTfvqu/8gzK49cSUdeuqRuFYiZmX9AvwfumtETM4plhXHymfHb6/mVbHg9uIlc13y+uew== + magic-string@^0.25.0, magic-string@^0.25.7: version "0.25.9" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" @@ -7020,7 +7035,7 @@ postcss@8.4.14: picocolors "^1.0.0" source-map-js "^1.0.2" -postcss@^8.4.14, postcss@^8.4.21, postcss@^8.4.23, postcss@^8.4.29: +postcss@^8.4.21, postcss@^8.4.23, postcss@^8.4.29: version "8.4.29" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.29.tgz#33bc121cf3b3688d4ddef50be869b2a54185a1dd" integrity sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw== @@ -7057,6 +7072,11 @@ prettier-plugin-tailwindcss@^0.3.0: resolved "https://registry.yarnpkg.com/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.3.0.tgz#8299b307c7f6467f52732265579ed9375be6c818" integrity sha512-009/Xqdy7UmkcTBpwlq7jsViDqXAYSOMLDrHAdTMlVZOrKfM2o9Ci7EMWTMZ7SkKBFTG04UM9F9iM2+4i6boDA== +prettier-plugin-tailwindcss@^0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.5.4.tgz#ebfacbcb90e2ca1df671ffe4083e99f81d72040d" + integrity sha512-QZzzB1bID6qPsKHTeA9qPo1APmmxfFrA5DD3LQ+vbTmAnY40eJI7t9Q1ocqel2EKMWNPLJqdTDWZj1hKYgqSgg== + prettier@^2.8.7, prettier@^2.8.8: version "2.8.8" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" @@ -8186,12 +8206,12 @@ tailwind-merge@^1.14.0: resolved "https://registry.yarnpkg.com/tailwind-merge/-/tailwind-merge-1.14.0.tgz#e677f55d864edc6794562c63f5001f45093cdb8b" integrity sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ== -tailwindcss-animate@^1.0.6: +tailwindcss-animate@^1.0.6, tailwindcss-animate@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz#318b692c4c42676cc9e67b19b78775742388bef4" integrity sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA== -tailwindcss@^3.1.6, tailwindcss@^3.2.7: +tailwindcss@^3.2.7, tailwindcss@^3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.3.tgz#90da807393a2859189e48e9e7000e6880a736daf" integrity sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w== From 35ffb850b7cbc101366d2a236a892a4e8ea7d505 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Tue, 19 Sep 2023 16:37:40 +0530 Subject: [PATCH 04/57] removed tiptap pro extension --- README.md | 11 ----------- space/components/tiptap/extensions/index.tsx | 4 ---- space/package.json | 1 - web/components/tiptap/extensions/index.tsx | 4 ---- web/package.json | 1 - yarn.lock | 12 ------------ 6 files changed, 33 deletions(-) diff --git a/README.md b/README.md index a5a7ddd87d8..3cbeed8c4bc 100644 --- a/README.md +++ b/README.md @@ -59,17 +59,6 @@ chmod +x setup.sh > If running in a cloud env replace localhost with public facing IP address of the VM -- Setup Tiptap Pro - - Visit [Tiptap Pro](https://collab.tiptap.dev/pro-extensions) and signup (it is free). - - Create a **`.npmrc`** file, copy the following and replace your registry token generated from Tiptap Pro. - -``` -@tiptap-pro:registry=https://registry.tiptap.dev/ -//registry.tiptap.dev/:_authToken=YOUR_REGISTRY_TOKEN -``` - - Run Docker compose up ```bash diff --git a/space/components/tiptap/extensions/index.tsx b/space/components/tiptap/extensions/index.tsx index f5dc1138474..8ad4e07b4d5 100644 --- a/space/components/tiptap/extensions/index.tsx +++ b/space/components/tiptap/extensions/index.tsx @@ -18,7 +18,6 @@ import Gapcursor from "@tiptap/extension-gapcursor"; import ts from "highlight.js/lib/languages/typescript"; 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"; @@ -121,9 +120,6 @@ export const TiptapExtensions = ( }, includeChildren: true, }), - UniqueID.configure({ - types: ["image"], - }), SlashCommand(workspaceSlug, setIsSubmitting), TiptapUnderline, TextStyle, diff --git a/space/package.json b/space/package.json index 2cf52bbf494..6ce9ecefee6 100644 --- a/space/package.json +++ b/space/package.json @@ -17,7 +17,6 @@ "@heroicons/react": "^2.0.12", "@mui/icons-material": "^5.14.1", "@mui/material": "^5.14.1", - "@tiptap-pro/extension-unique-id": "^2.1.0", "@tiptap/extension-code-block-lowlight": "^2.0.4", "@tiptap/extension-color": "^2.0.4", "@tiptap/extension-gapcursor": "^2.1.7", diff --git a/web/components/tiptap/extensions/index.tsx b/web/components/tiptap/extensions/index.tsx index f5dc1138474..8ad4e07b4d5 100644 --- a/web/components/tiptap/extensions/index.tsx +++ b/web/components/tiptap/extensions/index.tsx @@ -18,7 +18,6 @@ import Gapcursor from "@tiptap/extension-gapcursor"; import ts from "highlight.js/lib/languages/typescript"; 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"; @@ -121,9 +120,6 @@ export const TiptapExtensions = ( }, includeChildren: true, }), - UniqueID.configure({ - types: ["image"], - }), SlashCommand(workspaceSlug, setIsSubmitting), TiptapUnderline, TextStyle, diff --git a/web/package.json b/web/package.json index 8a12f8ec55e..eddd4a06da8 100644 --- a/web/package.json +++ b/web/package.json @@ -26,7 +26,6 @@ "@nivo/pie": "0.80.0", "@nivo/scatterplot": "0.80.0", "@sentry/nextjs": "^7.36.0", - "@tiptap-pro/extension-unique-id": "^2.1.0", "@tiptap/extension-code-block-lowlight": "^2.0.4", "@tiptap/extension-color": "^2.0.4", "@tiptap/extension-gapcursor": "^2.1.7", diff --git a/yarn.lock b/yarn.lock index d2bca703d7f..0449ae903df 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2348,13 +2348,6 @@ lodash.merge "^4.6.2" postcss-selector-parser "6.0.10" -"@tiptap-pro/extension-unique-id@^2.1.0": - version "2.2.1" - resolved "https://registry.tiptap.dev/@tiptap-pro%2fextension-unique-id/-/extension-unique-id-2.2.1.tgz#656803254760314d4e1b453dc5b75c86023048a6" - integrity sha512-B0GNLrWDVcfhbUOOi/lJfow6I4Y8xwJYXnSlhAENnGgOGERjinY1J5nZaR5dDMu1chcJYqAt3I7vkVLA/UMwmQ== - dependencies: - uuid "^8.3.2" - "@tiptap/core@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.1.10.tgz#6d8f3c777f1700dcc6c903b1185576754175e366" @@ -8785,11 +8778,6 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2: resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - uuid@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" From e35848718d0272f654c1fcf78a32c9e49e009c24 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Tue, 19 Sep 2023 19:49:15 +0530 Subject: [PATCH 05/57] fixed types --- packages/editor/README.md | 139 ------------------ packages/editor/package.json | 7 +- .../types/{delete-file.ts => delete-image.ts} | 0 .../types/{upload-file.ts => upload-image.ts} | 2 +- .../editor/extensions/image/updated-image.tsx | 4 +- .../editor/src/ui/editor/extensions/index.tsx | 11 +- .../ui/editor/extensions/slash-command.tsx | 2 +- packages/editor/src/ui/editor/index.tsx | 4 +- .../src/ui/editor/plugins/delete-image.tsx | 6 +- .../src/ui/editor/plugins/upload-image.tsx | 4 +- packages/editor/src/ui/editor/props.tsx | 2 +- web/package.json | 5 +- yarn.lock | 14 +- 13 files changed, 26 insertions(+), 174 deletions(-) delete mode 100644 packages/editor/README.md rename packages/editor/src/types/{delete-file.ts => delete-image.ts} (100%) rename packages/editor/src/types/{upload-file.ts => upload-image.ts} (71%) diff --git a/packages/editor/README.md b/packages/editor/README.md deleted file mode 100644 index aa673e39f7d..00000000000 --- a/packages/editor/README.md +++ /dev/null @@ -1,139 +0,0 @@ - - This is the core engine that supports Rich Text Editing at Plane -

Plane's Editor

-
- -

- An open-source Notion-style WYSIWYG editor with AI-powered autocompletions. -

- -

- Hacker News - - License - - Novel.sh's GitHub repo -

- -

- Introduction · - Installation · - Deploy Your Own · - Setting Up Locally · - Tech Stack · - Contributing · - License -

-
- -## Introduction - -[Novel](https://novel.sh/) is a Notion-style WYSIWYG editor with AI-powered autocompletions. - -https://github.com/steven-tey/novel/assets/28986134/2099877f-4f2b-4b1c-8782-5d803d63be5c - -
- -## Installation - -To use Novel in a project, you can run the following command to install the `novel` [NPM package](https://www.npmjs.com/package/novel): - -``` -npm i novel -``` - -Then, you can use it in your code like this: - -```jsx -import { Editor } from "novel"; - -export default function App() { - return ; -} -``` - -The `Editor` is a React component that takes in the following props: - -| Prop | Type | Description | Default | -| ------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------- | -| `completionApi` | `string` | The API route to use for the OpenAI completion API. | `/api/generate` | -| `className` | `string` | Editor container classname. | `"relative min-h-[500px] w-full max-w-screen-lg border-stone-200 bg-white sm:mb-[calc(20vh)] sm:rounded-lg sm:border sm:shadow-lg"` | -| `defaultValue` | `JSONContent` or `string` | The default value to use for the editor. | [`defaultEditorContent`](https://github.com/steven-tey/novel/blob/main/packages/core/src/ui/editor/default-content.tsx) | -| `extensions` | `Extension[]` | A list of extensions to use for the editor, in addition to the [default Novel extensions](https://github.com/steven-tey/novel/blob/main/packages/core/src/ui/editor/extensions/index.tsx). | `[]` | -| `editorProps` | `EditorProps` | Props to pass to the underlying Tiptap editor, in addition to the [default Novel editor props](https://github.com/steven-tey/novel/blob/main/packages/core/src/ui/editor/props.ts). | `{}` | -| `onUpdate` | `(editor?: Editor) => void` | A callback function that is called whenever the editor is updated. | `() => {}` | -| `onDebouncedUpdate` | `(editor?: Editor) => void` | A callback function that is called whenever the editor is updated, but only after the defined debounce duration. | `() => {}` | -| `debounceDuration` | `number` | The duration (in milliseconds) to debounce the `onDebouncedUpdate` callback. | `750` | -| `storageKey` | `string` | The key to use for storing the editor's value in local storage. | `novel__content` | - -> **Note**: Make sure to define an API endpoint that matches the `completionApi` prop (default is `/api/generate`). This is needed for the AI autocompletions to work. Here's an example: https://github.com/steven-tey/novel/blob/main/apps/web/app/api/generate/route.ts - -Here's an example application: https://github.com/steven-tey/novella - -## Deploy Your Own - -You can deploy your own version of Novel to Vercel with one click: - -[![Deploy with Vercel](https://vercel.com/button)](https://stey.me/novel-deploy) - -## Setting Up Locally - -To set up Novel locally, you'll need to clone the repository and set up the following environment variables: - -- `OPENAI_API_KEY` – your OpenAI API key (you can get one [here](https://platform.openai.com/account/api-keys)) -- `BLOB_READ_WRITE_TOKEN` – your Vercel Blob read/write token (currently [still in beta](https://vercel.com/docs/storage/vercel-blob/quickstart#quickstart), but feel free to [sign up on this form](https://vercel.fyi/blob-beta) for access) - -If you've deployed this to Vercel, you can also use [`vc env pull`](https://vercel.com/docs/cli/env#exporting-development-environment-variables) to pull the environment variables from your Vercel project. - -To run the app locally, you can run the following commands: - -``` -pnpm i -pnpm build -pnpm dev -``` - -## Cross-framework support - -While Novel is built for React, we also have a few community-maintained packages for non-React frameworks: - -- Svelte: https://novel.sh/svelte -- Vue: https://novel.sh/vue - -## VSCode Extension - -Thanks to @bennykok, Novel also has a VSCode Extension: https://novel.sh/vscode - -https://github.com/steven-tey/novel/assets/28986134/58ebf7e3-cdb3-43df-878b-119e304f7373 - -## Tech Stack - -Novel is built on the following stack: - -- [Next.js](https://nextjs.org/) – framework -- [Tiptap](https://tiptap.dev/) – text editor -- [OpenAI](https://openai.com/) - AI completions -- [Vercel AI SDK](https://sdk.vercel.ai/docs) – AI library -- [Vercel](https://vercel.com) – deployments -- [TailwindCSS](https://tailwindcss.com/) – styles -- [Cal Sans](https://github.com/calcom/font) – font - -## Contributing - -Here's how you can contribute: - -- [Open an issue](https://github.com/steven-tey/novel/issues) if you believe you've encountered a bug. -- Make a [pull request](https://github.com/steven-tey/novel/pull) to add new features/make quality-of-life improvements/fix bugs. - - - - - -## Repo Activity - -![Novel.sh repo activity – generated by Axiom](https://repobeats.axiom.co/api/embed/2ebdaa143b0ad6e7c2ee23151da7b37f67da0b36.svg) - -## License - -Licensed under the [Apache-2.0 license](https://github.com/steven-tey/novel/blob/main/LICENSE.md). - diff --git a/packages/editor/package.json b/packages/editor/package.json index e9e7cd079d0..b27a020ac1d 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -1,5 +1,5 @@ { - "name": "plane-editor", + "name": "@plane/editor", "version": "0.0.1", "description": "Rich Text Editor that powers Plane", "main": "./dist/index.js", @@ -27,15 +27,11 @@ "dependencies": { "@blueprintjs/popover2": "^2.0.10", "@tiptap/core": "^2.1.7", - "@tiptap/extension-blockquote": "^2.1.10", - "@tiptap/extension-bullet-list": "^2.1.10", "@tiptap/extension-code-block-lowlight": "^2.0.4", "@tiptap/extension-highlight": "^2.1.7", "@tiptap/extension-horizontal-rule": "^2.1.7", "@tiptap/extension-image": "^2.1.7", "@tiptap/extension-link": "^2.1.7", - "@tiptap/extension-list-item": "^2.1.10", - "@tiptap/extension-ordered-list": "^2.1.10", "@tiptap/extension-placeholder": "2.0.3", "@tiptap/extension-table": "^2.1.6", "@tiptap/extension-table-cell": "^2.1.6", @@ -63,7 +59,6 @@ "react": "18.2.0", "react-dom": "18.2.0", "react-markdown": "^8.0.7", - "sonner": "^0.7.0", "tailwind-merge": "^1.14.0", "tippy.js": "^6.3.7", "tiptap-markdown": "^0.8.2", diff --git a/packages/editor/src/types/delete-file.ts b/packages/editor/src/types/delete-image.ts similarity index 100% rename from packages/editor/src/types/delete-file.ts rename to packages/editor/src/types/delete-image.ts diff --git a/packages/editor/src/types/upload-file.ts b/packages/editor/src/types/upload-image.ts similarity index 71% rename from packages/editor/src/types/upload-file.ts rename to packages/editor/src/types/upload-image.ts index bb2003b0c4b..e9d35ad486b 100644 --- a/packages/editor/src/types/upload-file.ts +++ b/packages/editor/src/types/upload-image.ts @@ -1 +1 @@ -export type UploadImage = (workspaceSlug: string, formData: FormData) => Promise; +export type UploadImage = (workspaceSlug: string, formData: FormData) => Promise; diff --git a/packages/editor/src/ui/editor/extensions/image/updated-image.tsx b/packages/editor/src/ui/editor/extensions/image/updated-image.tsx index 0162fc15af8..2ba977f575e 100644 --- a/packages/editor/src/ui/editor/extensions/image/updated-image.tsx +++ b/packages/editor/src/ui/editor/extensions/image/updated-image.tsx @@ -1,9 +1,9 @@ import Image from "@tiptap/extension-image"; import TrackImageDeletionPlugin from "@/ui/editor/plugins/delete-image"; import UploadImagesPlugin from "@/ui/editor/plugins/upload-image"; -import { DeleteFileFunction } from "@/types/delete-file"; +import { DeleteImage } from "@/types/delete-image"; -const UpdatedImage = (deleteImage: DeleteFileFunction) => Image.extend({ +const UpdatedImage = (deleteImage: DeleteImage) => Image.extend({ addProseMirrorPlugins() { return [UploadImagesPlugin(), TrackImageDeletionPlugin(deleteImage)]; }, diff --git a/packages/editor/src/ui/editor/extensions/index.tsx b/packages/editor/src/ui/editor/extensions/index.tsx index 303a46c0680..5fd7f9ad140 100644 --- a/packages/editor/src/ui/editor/extensions/index.tsx +++ b/packages/editor/src/ui/editor/extensions/index.tsx @@ -12,9 +12,6 @@ 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 OrderedList from "@tiptap/extension-ordered-list"; -import ListItem from "@tiptap/extension-list-item"; -import BulletList from "@tiptap/extension-bullet-list"; import { Table } from "@/ui/editor/extensions/table/table"; import { TableHeader } from "@/ui/editor/extensions/table/table-header"; import { TableRow } from "@tiptap/extension-table-row"; @@ -23,8 +20,8 @@ import { CustomTableCell } from "@/ui/editor/extensions/table/table-cell"; import UpdatedImage from "@/ui/editor/extensions/image/updated-image"; import SlashCommand from "@/ui/editor/extensions/slash-command"; -import { DeleteFileFunction } from "@/types/delete-file"; -import { UploadFileFunction } from "@/types/upload-file"; +import { DeleteImage } from "@/types/delete-image"; +import { UploadImage } from "@/types/upload-image"; import isValidHttpUrl from "@/ui/editor/menus/bubble-menu/utils" @@ -36,8 +33,8 @@ lowlight.registerLanguage("ts", ts); export const TiptapExtensions = ( workspaceSlug: string, - uploadFile: UploadFileFunction, - deleteFile: DeleteFileFunction, + uploadFile: UploadImage, + deleteFile: DeleteImage, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void ) => [ StarterKit.configure({ diff --git a/packages/editor/src/ui/editor/extensions/slash-command.tsx b/packages/editor/src/ui/editor/extensions/slash-command.tsx index 76cbda8b9c8..4fba7af5ff8 100644 --- a/packages/editor/src/ui/editor/extensions/slash-command.tsx +++ b/packages/editor/src/ui/editor/extensions/slash-command.tsx @@ -19,7 +19,7 @@ import { } from "lucide-react"; import { startImageUpload } from "@/ui/editor/plugins/upload-image"; import { cn } from "@/lib/utils"; -import { UploadImage } from "@/types/upload-file"; +import { UploadImage } from "@/types/upload-image"; interface CommandItemProps { title: string; diff --git a/packages/editor/src/ui/editor/index.tsx b/packages/editor/src/ui/editor/index.tsx index d534d57eb86..e296d400aed 100644 --- a/packages/editor/src/ui/editor/index.tsx +++ b/packages/editor/src/ui/editor/index.tsx @@ -8,8 +8,8 @@ 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 { UploadImage } from '@/types/upload-file'; -import { DeleteImage } from '@/types/delete-file'; +import { UploadImage } from '@/types/upload-image'; +import { DeleteImage } from '@/types/delete-image'; export interface ITipTapRichTextEditor { value: string; diff --git a/packages/editor/src/ui/editor/plugins/delete-image.tsx b/packages/editor/src/ui/editor/plugins/delete-image.tsx index a240cb2598d..9204481a8dd 100644 --- a/packages/editor/src/ui/editor/plugins/delete-image.tsx +++ b/packages/editor/src/ui/editor/plugins/delete-image.tsx @@ -1,6 +1,6 @@ import { EditorState, Plugin, PluginKey, Transaction } from "@tiptap/pm/state"; import { Node as ProseMirrorNode } from "@tiptap/pm/model"; -import { DeleteFileFunction } from "@/types/delete-file"; +import { DeleteImage } from "@/types/delete-image"; const deleteKey = new PluginKey("delete-image"); const IMAGE_NODE_TYPE = "image"; @@ -12,7 +12,7 @@ interface ImageNode extends ProseMirrorNode { }; } -const TrackImageDeletionPlugin = (deleteImage: DeleteFileFunction): Plugin => +const TrackImageDeletionPlugin = (deleteImage: DeleteImage): Plugin => new Plugin({ key: deleteKey, appendTransaction: (transactions: readonly Transaction[], oldState: EditorState, newState: EditorState) => { @@ -55,7 +55,7 @@ const TrackImageDeletionPlugin = (deleteImage: DeleteFileFunction): Plugin => export default TrackImageDeletionPlugin; -async function onNodeDeleted(src: string, deleteImage: DeleteFileFunction): Promise { +async function onNodeDeleted(src: string, deleteImage: DeleteImage): Promise { try { const assetUrlWithWorkspaceId = new URL(src).pathname.substring(1); const resStatus = await deleteImage(assetUrlWithWorkspaceId); diff --git a/packages/editor/src/ui/editor/plugins/upload-image.tsx b/packages/editor/src/ui/editor/plugins/upload-image.tsx index 99a963fd2cf..4c3bbf9a82b 100644 --- a/packages/editor/src/ui/editor/plugins/upload-image.tsx +++ b/packages/editor/src/ui/editor/plugins/upload-image.tsx @@ -1,4 +1,4 @@ -import { UploadFileFunction, UploadImage } from "@/types/upload-file"; +import { UploadImage } from "@/types/upload-image"; import { EditorState, Plugin, PluginKey } from "@tiptap/pm/state"; import { Decoration, DecorationSet, EditorView } from "@tiptap/pm/view"; @@ -102,7 +102,7 @@ export async function startImageUpload( } const UploadImageHandler = (file: File, workspaceSlug: string, - uploadFile: UploadFileFunction + uploadFile: UploadImage ): Promise => { if (!workspaceSlug) { return Promise.reject("Workspace slug is missing"); diff --git a/packages/editor/src/ui/editor/props.tsx b/packages/editor/src/ui/editor/props.tsx index 3de3294bf8a..ff5b2f11b25 100644 --- a/packages/editor/src/ui/editor/props.tsx +++ b/packages/editor/src/ui/editor/props.tsx @@ -1,7 +1,7 @@ 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-file"; +import { UploadImage } from "@/types/upload-image"; export function TiptapEditorProps( workspaceSlug: string, diff --git a/web/package.json b/web/package.json index eddd4a06da8..deae3980f36 100644 --- a/web/package.json +++ b/web/package.json @@ -80,7 +80,7 @@ "tlds": "^1.238.0", "use-debounce": "^9.0.4", "uuid": "^9.0.0", - "plane-editor": "*" + "@plane/editor": "*" }, "devDependencies": { "@types/js-cookie": "^3.0.2", @@ -101,8 +101,5 @@ "tsconfig": "*", "tailwind-config": "*", "typescript": "4.7.4" - }, - "resolutions": { - "prosemirror-model": "1.18.1" } } diff --git a/yarn.lock b/yarn.lock index 0449ae903df..c958eb62bf8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7190,7 +7190,14 @@ prosemirror-menu@^1.2.1: prosemirror-history "^1.0.0" prosemirror-state "^1.0.0" -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== @@ -7951,11 +7958,6 @@ sonner@^0.6.2: resolved "https://registry.yarnpkg.com/sonner/-/sonner-0.6.2.tgz#d87420e80d8b25b6d2bd6aabcc28465f03962bdc" integrity sha512-bh4FWhYoNN481ZIW94W4e0kSLBTMGislYg2YXvDS1px1AJJz4erQe9jHV8s5pS1VMVDgfh3CslNSFLaU6Ldrnw== -sonner@^0.7.0: - version "0.7.1" - resolved "https://registry.yarnpkg.com/sonner/-/sonner-0.7.1.tgz#46441caa4e94a0491fe8e7ce56887d097f90c4df" - integrity sha512-awbVcBwV0xV5TN7kJEZv6Sx7Fi9JBL26vTn0FnBcf6YsyWKnyvz16I/jE6omCtBjd0/YXsPHJ//VuA5fvD2vEg== - source-list-map@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" From 7ef1745e380d883cca3bd7211d0067271687a327 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Wed, 20 Sep 2023 10:10:11 +0530 Subject: [PATCH 06/57] removed old tailwind config and fixed plane package imports --- packages/tailwind-config/package.json | 15 -- packages/tailwind-config/tailwind.config.js | 206 -------------------- web/components/issues/description-form.tsx | 2 +- web/package.json | 1 - 4 files changed, 1 insertion(+), 223 deletions(-) delete mode 100644 packages/tailwind-config/package.json delete mode 100644 packages/tailwind-config/tailwind.config.js diff --git a/packages/tailwind-config/package.json b/packages/tailwind-config/package.json deleted file mode 100644 index 6d7dbbc7a41..00000000000 --- a/packages/tailwind-config/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "tailwind-config", - "version": "0.0.0", - "private": true, - "main": "index.js", - "devDependencies": { - "@tailwindcss/typography": "^0.5.9", - "autoprefixer": "^10.4.14", - "postcss": "^8.4.21", - "prettier": "^2.8.8", - "prettier-plugin-tailwindcss": "^0.3.0", - "tailwindcss": "^3.2.7", - "tailwindcss-animate": "^1.0.6" - } -} diff --git a/packages/tailwind-config/tailwind.config.js b/packages/tailwind-config/tailwind.config.js deleted file mode 100644 index 0b7b5861aeb..00000000000 --- a/packages/tailwind-config/tailwind.config.js +++ /dev/null @@ -1,206 +0,0 @@ -const convertToRGB = (variableName) => `rgba(var(${variableName}))`; - -module.exports = { - darkMode: "class", - content: ["./pages/**/*.tsx", "./components/**/*.tsx", "./layouts/**/*.tsx", "./ui/**/*.tsx"], - theme: { - extend: { - boxShadow: { - "custom-shadow-2xs": "var(--color-shadow-2xs)", - "custom-shadow-xs": "var(--color-shadow-xs)", - "custom-shadow-sm": "var(--color-shadow-sm)", - "custom-shadow-rg": "var(--color-shadow-rg)", - "custom-shadow-md": "var(--color-shadow-md)", - "custom-shadow-lg": "var(--color-shadow-lg)", - "custom-shadow-xl": "var(--color-shadow-xl)", - "custom-shadow-2xl": "var(--color-shadow-2xl)", - "custom-shadow-3xl": "var(--color-shadow-3xl)", - "custom-sidebar-shadow-2xs": "var(--color-sidebar-shadow-2xs)", - "custom-sidebar-shadow-xs": "var(--color-sidebar-shadow-xs)", - "custom-sidebar-shadow-sm": "var(--color-sidebar-shadow-sm)", - "custom-sidebar-shadow-rg": "var(--color-sidebar-shadow-rg)", - "custom-sidebar-shadow-md": "var(--color-sidebar-shadow-md)", - "custom-sidebar-shadow-lg": "var(--color-sidebar-shadow-lg)", - "custom-sidebar-shadow-xl": "var(--color-sidebar-shadow-xl)", - "custom-sidebar-shadow-2xl": "var(--color-sidebar-shadow-2xl)", - "custom-sidebar-shadow-3xl": "var(--color-sidebar-shadow-3xl)", - }, - colors: { - custom: { - primary: { - 0: "rgb(255, 255, 255)", - 10: convertToRGB("--color-primary-10"), - 20: convertToRGB("--color-primary-20"), - 30: convertToRGB("--color-primary-30"), - 40: convertToRGB("--color-primary-40"), - 50: convertToRGB("--color-primary-50"), - 60: convertToRGB("--color-primary-60"), - 70: convertToRGB("--color-primary-70"), - 80: convertToRGB("--color-primary-80"), - 90: convertToRGB("--color-primary-90"), - 100: convertToRGB("--color-primary-100"), - 200: convertToRGB("--color-primary-200"), - 300: convertToRGB("--color-primary-300"), - 400: convertToRGB("--color-primary-400"), - 500: convertToRGB("--color-primary-500"), - 600: convertToRGB("--color-primary-600"), - 700: convertToRGB("--color-primary-700"), - 800: convertToRGB("--color-primary-800"), - 900: convertToRGB("--color-primary-900"), - 1000: "rgb(0, 0, 0)", - DEFAULT: convertToRGB("--color-primary-100"), - }, - background: { - 0: "rgb(255, 255, 255)", - 10: convertToRGB("--color-background-10"), - 20: convertToRGB("--color-background-20"), - 30: convertToRGB("--color-background-30"), - 40: convertToRGB("--color-background-40"), - 50: convertToRGB("--color-background-50"), - 60: convertToRGB("--color-background-60"), - 70: convertToRGB("--color-background-70"), - 80: convertToRGB("--color-background-80"), - 90: convertToRGB("--color-background-90"), - 100: convertToRGB("--color-background-100"), - 200: convertToRGB("--color-background-200"), - 300: convertToRGB("--color-background-300"), - 400: convertToRGB("--color-background-400"), - 500: convertToRGB("--color-background-500"), - 600: convertToRGB("--color-background-600"), - 700: convertToRGB("--color-background-700"), - 800: convertToRGB("--color-background-800"), - 900: convertToRGB("--color-background-900"), - 1000: "rgb(0, 0, 0)", - DEFAULT: convertToRGB("--color-background-100"), - }, - text: { - 0: "rgb(255, 255, 255)", - 10: convertToRGB("--color-text-10"), - 20: convertToRGB("--color-text-20"), - 30: convertToRGB("--color-text-30"), - 40: convertToRGB("--color-text-40"), - 50: convertToRGB("--color-text-50"), - 60: convertToRGB("--color-text-60"), - 70: convertToRGB("--color-text-70"), - 80: convertToRGB("--color-text-80"), - 90: convertToRGB("--color-text-90"), - 100: convertToRGB("--color-text-100"), - 200: convertToRGB("--color-text-200"), - 300: convertToRGB("--color-text-300"), - 400: convertToRGB("--color-text-400"), - 500: convertToRGB("--color-text-500"), - 600: convertToRGB("--color-text-600"), - 700: convertToRGB("--color-text-700"), - 800: convertToRGB("--color-text-800"), - 900: convertToRGB("--color-text-900"), - 1000: "rgb(0, 0, 0)", - DEFAULT: convertToRGB("--color-text-100"), - }, - border: { - 0: "rgb(255, 255, 255)", - 100: convertToRGB("--color-border-100"), - 200: convertToRGB("--color-border-200"), - 300: convertToRGB("--color-border-300"), - 400: convertToRGB("--color-border-400"), - 1000: "rgb(0, 0, 0)", - DEFAULT: convertToRGB("--color-border-200"), - }, - sidebar: { - background: { - 0: "rgb(255, 255, 255)", - 10: convertToRGB("--color-sidebar-background-10"), - 20: convertToRGB("--color-sidebar-background-20"), - 30: convertToRGB("--color-sidebar-background-30"), - 40: convertToRGB("--color-sidebar-background-40"), - 50: convertToRGB("--color-sidebar-background-50"), - 60: convertToRGB("--color-sidebar-background-60"), - 70: convertToRGB("--color-sidebar-background-70"), - 80: convertToRGB("--color-sidebar-background-80"), - 90: convertToRGB("--color-sidebar-background-90"), - 100: convertToRGB("--color-sidebar-background-100"), - 200: convertToRGB("--color-sidebar-background-200"), - 300: convertToRGB("--color-sidebar-background-300"), - 400: convertToRGB("--color-sidebar-background-400"), - 500: convertToRGB("--color-sidebar-background-500"), - 600: convertToRGB("--color-sidebar-background-600"), - 700: convertToRGB("--color-sidebar-background-700"), - 800: convertToRGB("--color-sidebar-background-800"), - 900: convertToRGB("--color-sidebar-background-900"), - 1000: "rgb(0, 0, 0)", - DEFAULT: convertToRGB("--color-sidebar-background-100"), - }, - text: { - 0: "rgb(255, 255, 255)", - 10: convertToRGB("--color-sidebar-text-10"), - 20: convertToRGB("--color-sidebar-text-20"), - 30: convertToRGB("--color-sidebar-text-30"), - 40: convertToRGB("--color-sidebar-text-40"), - 50: convertToRGB("--color-sidebar-text-50"), - 60: convertToRGB("--color-sidebar-text-60"), - 70: convertToRGB("--color-sidebar-text-70"), - 80: convertToRGB("--color-sidebar-text-80"), - 90: convertToRGB("--color-sidebar-text-90"), - 100: convertToRGB("--color-sidebar-text-100"), - 200: convertToRGB("--color-sidebar-text-200"), - 300: convertToRGB("--color-sidebar-text-300"), - 400: convertToRGB("--color-sidebar-text-400"), - 500: convertToRGB("--color-sidebar-text-500"), - 600: convertToRGB("--color-sidebar-text-600"), - 700: convertToRGB("--color-sidebar-text-700"), - 800: convertToRGB("--color-sidebar-text-800"), - 900: convertToRGB("--color-sidebar-text-900"), - 1000: "rgb(0, 0, 0)", - DEFAULT: convertToRGB("--color-sidebar-text-100"), - }, - border: { - 0: "rgb(255, 255, 255)", - 100: convertToRGB("--color-sidebar-border-100"), - 200: convertToRGB("--color-sidebar-border-200"), - 300: convertToRGB("--color-sidebar-border-300"), - 400: convertToRGB("--color-sidebar-border-400"), - 1000: "rgb(0, 0, 0)", - DEFAULT: convertToRGB("--color-sidebar-border-200"), - }, - }, - backdrop: "#131313", - }, - }, - keyframes: { - leftToaster: { - "0%": { left: "-20rem" }, - "100%": { left: "0" }, - }, - rightToaster: { - "0%": { right: "-20rem" }, - "100%": { right: "0" }, - }, - }, - typography: ({ theme }) => ({ - brand: { - css: { - "--tw-prose-body": convertToRGB("--color-text-100"), - "--tw-prose-p": convertToRGB("--color-text-100"), - "--tw-prose-headings": convertToRGB("--color-text-100"), - "--tw-prose-lead": convertToRGB("--color-text-100"), - "--tw-prose-links": convertToRGB("--color-primary-100"), - "--tw-prose-bold": convertToRGB("--color-text-100"), - "--tw-prose-counters": convertToRGB("--color-text-100"), - "--tw-prose-bullets": convertToRGB("--color-text-100"), - "--tw-prose-hr": convertToRGB("--color-text-100"), - "--tw-prose-quotes": convertToRGB("--color-text-100"), - "--tw-prose-quote-borders": convertToRGB("--color-border"), - "--tw-prose-code": convertToRGB("--color-text-100"), - "--tw-prose-pre-code": convertToRGB("--color-text-100"), - "--tw-prose-pre-bg": convertToRGB("--color-background-100"), - "--tw-prose-th-borders": convertToRGB("--color-border"), - "--tw-prose-td-borders": convertToRGB("--color-border"), - }, - }, - }), - }, - fontFamily: { - custom: ["Inter", "sans-serif"], - }, - }, - plugins: [require("tailwindcss-animate"), require("@tailwindcss/typography")], -}; diff --git a/web/components/issues/description-form.tsx b/web/components/issues/description-form.tsx index 215a0f50264..6f80a7d4b29 100644 --- a/web/components/issues/description-form.tsx +++ b/web/components/issues/description-form.tsx @@ -9,7 +9,7 @@ import { useDebouncedCallback } from "use-debounce"; import { TextArea } from "components/ui"; // types import { IIssue } from "types"; -import { TipTapEditor } from "plane-editor" +import { TipTapEditor } from "@plane/editor" import fileService from "services/file.service"; export interface IssueDescriptionFormValues { diff --git a/web/package.json b/web/package.json index deae3980f36..37b7447caea 100644 --- a/web/package.json +++ b/web/package.json @@ -99,7 +99,6 @@ "prettier": "^2.8.7", "tailwind-config-custom": "*", "tsconfig": "*", - "tailwind-config": "*", "typescript": "4.7.4" } } From 3b9c29cfd42f3a30893d5132120d1c721e51f7dc Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Wed, 20 Sep 2023 11:26:16 +0530 Subject: [PATCH 07/57] exported tiptap editor with and without ref --- packages/editor/package.json | 13 +++- packages/editor/src/index.ts | 2 +- packages/editor/src/ui/editor/index.tsx | 77 ++++++++++++---------- packages/editor/tailwind.config.js | 2 +- web/components/issues/description-form.tsx | 4 +- web/package.json | 4 +- web/tailwind.config.js | 2 +- 7 files changed, 61 insertions(+), 43 deletions(-) diff --git a/packages/editor/package.json b/packages/editor/package.json index b27a020ac1d..dac6c71649b 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -1,5 +1,5 @@ { - "name": "@plane/editor", + "name": "plane-editor", "version": "0.0.1", "description": "Rich Text Editor that powers Plane", "main": "./dist/index.js", @@ -69,7 +69,7 @@ "eslint": "^7.32.0", "postcss": "^8.4.29", "react": "^18.2.0", - "tailwind-config": "*", + "tailwind-config-custom": "*", "tsconfig": "*", "tsup": "^7.2.0", "typescript": "4.9.5" @@ -80,5 +80,12 @@ "markdown", "nextjs", "react" - ] + ], + "typesVersions": { + "*": { + "*": [ + "src/*" + ] + } + } } diff --git a/packages/editor/src/index.ts b/packages/editor/src/index.ts index 2141d356b02..14c8c26564a 100644 --- a/packages/editor/src/index.ts +++ b/packages/editor/src/index.ts @@ -1,4 +1,4 @@ import "@/styles/tailwind.css"; import "@/styles/editor.css"; -export { TipTapEditor } from "@/ui/editor"; +export { TiptapEditor, TiptapEditorWithRef } from "@/ui/editor"; diff --git a/packages/editor/src/ui/editor/index.tsx b/packages/editor/src/ui/editor/index.tsx index e296d400aed..a24c6ac44b2 100644 --- a/packages/editor/src/ui/editor/index.tsx +++ b/packages/editor/src/ui/editor/index.tsx @@ -10,8 +10,9 @@ import { ImageResizer } from '@/ui/editor/extensions/image/image-resize'; import { TiptapEditorProps } from '@/ui/editor/props'; import { UploadImage } from '@/types/upload-image'; import { DeleteImage } from '@/types/delete-image'; +import { cn } from '@/lib/utils'; -export interface ITipTapRichTextEditor { +interface ITiptapEditor { value: string; uploadFile: UploadImage; deleteFile: DeleteImage; @@ -28,28 +29,37 @@ export interface ITipTapRichTextEditor { debouncedUpdatesEnabled?: boolean; } -const Tiptap = (props: ITipTapRichTextEditor) => { - const { - onChange, - debouncedUpdatesEnabled, - forwardedRef, - editable, - setIsSubmitting, - setShouldShowAlert, - editorContentCustomClassNames, - value, - uploadFile, - deleteFile, - noBorder, - workspaceSlug, - borderOnFocus, - customClassName, - } = props; +interface TiptapProps extends ITiptapEditor { + forwardedRef?: React.Ref; +} + +interface EditorHandle { + clearEditor: () => void; + setEditorValue: (content: string) => void; +} + +const DEBOUNCE_DELAY = 1500; +const TiptapEditor = ({ + onChange, + debouncedUpdatesEnabled, + editable, + setIsSubmitting, + setShouldShowAlert, + editorContentCustomClassNames, + value, + uploadFile, + deleteFile, + noBorder, + workspaceSlug, + borderOnFocus, + customClassName, + forwardedRef, +}: TiptapProps) => { const editor = useEditor({ editable: editable ?? true, editorProps: TiptapEditorProps(workspaceSlug, uploadFile, setIsSubmitting), - // @ts-ignore + // @ts-expect-error extensions: TiptapExtensions(workspaceSlug, uploadFile, deleteFile, setIsSubmitting), content: (typeof value === "string" && value.trim() !== "") ? value : "

", onUpdate: async ({ editor }) => { @@ -65,6 +75,7 @@ const Tiptap = (props: ITipTapRichTextEditor) => { }); const editorRef: React.MutableRefObject = useRef(null); + editorRef.current = editor; useImperativeHandle(forwardedRef, () => ({ clearEditor: () => { @@ -76,19 +87,19 @@ const Tiptap = (props: ITipTapRichTextEditor) => { })); const debouncedUpdates = useDebouncedCallback(async ({ onChange, editor }) => { - setTimeout(async () => { - if (onChange) { - onChange(editor.getJSON(), editor.getHTML()); - } - }, 500); - }, 1000); + if (onChange) { + onChange(editor.getJSON(), editor.getHTML()); + } + }, DEBOUNCE_DELAY); - const editorClassNames = `relative w-full max-w-full sm:rounded-lg mt-2 p-3 relative focus:outline-none rounded-md - ${noBorder ? "" : "border border-custom-border-200"} ${borderOnFocus ? "focus:border border-custom-border-300" : "focus:border-0" - } ${customClassName}`; + const editorClassNames = cn( + 'relative w-full max-w-full sm:rounded-lg mt-2 p-3 relative focus:outline-none rounded-md', + noBorder ? '' : 'border border-custom-border-200', + borderOnFocus ? 'focus:border border-custom-border-300' : 'focus:border-0', + customClassName + ); if (!editor) return null; - editorRef.current = editor; return (
{ ); }; -const TipTapEditor = forwardRef((props, ref) => ( - +const TiptapEditorWithRef = forwardRef((props, ref) => ( + )); -TipTapEditor.displayName = "TipTapEditor"; +TiptapEditorWithRef.displayName = "TiptapEditorWithRef"; -export { TipTapEditor }; +export { TiptapEditor, TiptapEditorWithRef }; diff --git a/packages/editor/tailwind.config.js b/packages/editor/tailwind.config.js index 12079a19b40..f3206315889 100644 --- a/packages/editor/tailwind.config.js +++ b/packages/editor/tailwind.config.js @@ -1,4 +1,4 @@ -const sharedConfig = require("tailwind-config/tailwind.config.js"); +const sharedConfig = require("tailwind-config-custom/tailwind.config.js"); module.exports = { // prefix ui lib classes to avoid conflicting with the app diff --git a/web/components/issues/description-form.tsx b/web/components/issues/description-form.tsx index 6f80a7d4b29..8f3cb65f481 100644 --- a/web/components/issues/description-form.tsx +++ b/web/components/issues/description-form.tsx @@ -9,7 +9,7 @@ import { useDebouncedCallback } from "use-debounce"; import { TextArea } from "components/ui"; // types import { IIssue } from "types"; -import { TipTapEditor } from "@plane/editor" +import { TiptapEditor } from "plane-editor" import fileService from "services/file.service"; export interface IssueDescriptionFormValues { @@ -134,7 +134,7 @@ export const IssueDescriptionForm: FC = ({ if (!value) return <>; return ( - Date: Wed, 20 Sep 2023 12:19:35 +0530 Subject: [PATCH 08/57] updated package name to @plane/editor --- packages/editor/package.json | 13 +- packages/editor/src/ui/editor/index.tsx | 2 +- packages/tsconfig/react.json | 8 +- web/components/issues/description-form.tsx | 4 +- web/package.json | 2 +- yarn.lock | 1552 +++++++++----------- 6 files changed, 681 insertions(+), 900 deletions(-) diff --git a/packages/editor/package.json b/packages/editor/package.json index dac6c71649b..49a1c2d2b98 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -1,16 +1,17 @@ { - "name": "plane-editor", + "name": "@plane/editor", "version": "0.0.1", "description": "Rich Text Editor that powers Plane", - "main": "./dist/index.js", - "module": "./dist/index.mjs", - "types": "./dist/index.d.ts", + "main": "dist/index.js", + "source": "src/index.ts", + "module": "dist/index.mjs", + "types": "dist/index.d.mts", "files": [ - "dist/**/*" + "dist" ], "exports": { ".": { - "types": "./dist/index.d.ts", + "types": "./dist/index.d.mts", "import": "./dist/index.mjs", "module": "./dist/index.mjs", "require": "./dist/index.js" diff --git a/packages/editor/src/ui/editor/index.tsx b/packages/editor/src/ui/editor/index.tsx index a24c6ac44b2..0952869a7a6 100644 --- a/packages/editor/src/ui/editor/index.tsx +++ b/packages/editor/src/ui/editor/index.tsx @@ -59,7 +59,7 @@ const TiptapEditor = ({ const editor = useEditor({ editable: editable ?? true, editorProps: TiptapEditorProps(workspaceSlug, uploadFile, setIsSubmitting), - // @ts-expect-error + // @ts-expect-err extensions: TiptapExtensions(workspaceSlug, uploadFile, deleteFile, setIsSubmitting), content: (typeof value === "string" && value.trim() !== "") ? value : "

", onUpdate: async ({ editor }) => { diff --git a/packages/tsconfig/react.json b/packages/tsconfig/react.json index ab1283da77f..36b62be3894 100644 --- a/packages/tsconfig/react.json +++ b/packages/tsconfig/react.json @@ -3,11 +3,9 @@ "display": "React Library", "extends": "./base.json", "compilerOptions": { - "lib": [ - "DOM" - ], + "jsx": "react-jsx", + "lib": ["ES2015", "DOM"], "module": "ESNext", - "target": "ES6", - "jsx": "react-jsx" + "target": "es6" } } diff --git a/web/components/issues/description-form.tsx b/web/components/issues/description-form.tsx index 8f3cb65f481..f4ec6c268e3 100644 --- a/web/components/issues/description-form.tsx +++ b/web/components/issues/description-form.tsx @@ -9,7 +9,7 @@ import { useDebouncedCallback } from "use-debounce"; import { TextArea } from "components/ui"; // types import { IIssue } from "types"; -import { TiptapEditor } from "plane-editor" +import { TiptapEditor } from "@plane/editor" import fileService from "services/file.service"; export interface IssueDescriptionFormValues { @@ -100,7 +100,7 @@ export const IssueDescriptionForm: FC = ({ placeholder="Enter issue name" register={register} onFocus={() => setCharacterLimit(true)} - onChange={(e) => { + onChange={() => { setCharacterLimit(false); setIsSubmitting("submitting"); debouncedTitleSave(); diff --git a/web/package.json b/web/package.json index 6300530a81e..4682e0f3daa 100644 --- a/web/package.json +++ b/web/package.json @@ -26,7 +26,7 @@ "@nivo/pie": "0.80.0", "@nivo/scatterplot": "0.80.0", "@sentry/nextjs": "^7.36.0", - "plane-editor": "*", + "@plane/editor": "*", "@tiptap/extension-code-block-lowlight": "^2.0.4", "@tiptap/extension-color": "^2.0.4", "@tiptap/extension-gapcursor": "^2.1.7", diff --git a/yarn.lock b/yarn.lock index c958eb62bf8..a6e284a2802 100644 --- a/yarn.lock +++ b/yarn.lock @@ -36,7 +36,7 @@ dependencies: "@babel/highlight" "^7.10.4" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.22.10", "@babel/code-frame@^7.22.5": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.22.13": version "7.22.13" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e" integrity sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w== @@ -44,38 +44,38 @@ "@babel/highlight" "^7.22.13" chalk "^2.4.2" -"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.22.9": - version "7.22.9" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.9.tgz#71cdb00a1ce3a329ce4cbec3a44f9fef35669730" - integrity sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ== +"@babel/compat-data@^7.22.20", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.22.9": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.22.20.tgz#8df6e96661209623f1975d66c35ffca66f3306d0" + integrity sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw== "@babel/core@^7.11.1": - version "7.22.11" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.11.tgz#8033acaa2aa24c3f814edaaa057f3ce0ba559c24" - integrity sha512-lh7RJrtPdhibbxndr6/xx0w8+CVlY5FJZiaSz908Fpy+G0xkBFTvwLcKJFF4PJxVfGhVWNebikpWGnOoC71juQ== + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.22.20.tgz#e3d0eed84c049e2a2ae0a64d27b6a37edec385b7" + integrity sha512-Y6jd1ahLubuYweD/zJH+vvOY141v4f9igNQAQ+MBgq9JlHS2iTsZKn1aMsb3vGccZsXI16VzTBw52Xx0DWmtnA== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.22.10" - "@babel/generator" "^7.22.10" - "@babel/helper-compilation-targets" "^7.22.10" - "@babel/helper-module-transforms" "^7.22.9" - "@babel/helpers" "^7.22.11" - "@babel/parser" "^7.22.11" - "@babel/template" "^7.22.5" - "@babel/traverse" "^7.22.11" - "@babel/types" "^7.22.11" + "@babel/code-frame" "^7.22.13" + "@babel/generator" "^7.22.15" + "@babel/helper-compilation-targets" "^7.22.15" + "@babel/helper-module-transforms" "^7.22.20" + "@babel/helpers" "^7.22.15" + "@babel/parser" "^7.22.16" + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.22.20" + "@babel/types" "^7.22.19" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.22.10": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.10.tgz#c92254361f398e160645ac58831069707382b722" - integrity sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A== +"@babel/generator@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.22.15.tgz#1564189c7ec94cb8f77b5e8a90c4d200d21b2339" + integrity sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA== dependencies: - "@babel/types" "^7.22.10" + "@babel/types" "^7.22.15" "@jridgewell/gen-mapping" "^0.3.2" "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" @@ -88,32 +88,32 @@ "@babel/types" "^7.22.5" "@babel/helper-builder-binary-assignment-operator-visitor@^7.22.5": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.10.tgz#573e735937e99ea75ea30788b57eb52fab7468c9" - integrity sha512-Av0qubwDQxC56DoUReVDeLfMEjYYSN1nZrTUrWkXd7hpU73ymRANkbuDm3yni9npkn+RXy9nNbEJZEzXr7xrfQ== + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz#5426b109cf3ad47b91120f8328d8ab1be8b0b956" + integrity sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw== dependencies: - "@babel/types" "^7.22.10" + "@babel/types" "^7.22.15" -"@babel/helper-compilation-targets@^7.22.10", "@babel/helper-compilation-targets@^7.22.5", "@babel/helper-compilation-targets@^7.22.6": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz#01d648bbc25dd88f513d862ee0df27b7d4e67024" - integrity sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q== +"@babel/helper-compilation-targets@^7.22.15", "@babel/helper-compilation-targets@^7.22.5", "@babel/helper-compilation-targets@^7.22.6": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52" + integrity sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw== dependencies: "@babel/compat-data" "^7.22.9" - "@babel/helper-validator-option" "^7.22.5" + "@babel/helper-validator-option" "^7.22.15" browserslist "^4.21.9" lru-cache "^5.1.1" semver "^6.3.1" "@babel/helper-create-class-features-plugin@^7.22.11", "@babel/helper-create-class-features-plugin@^7.22.5": - version "7.22.11" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.11.tgz#4078686740459eeb4af3494a273ac09148dfb213" - integrity sha512-y1grdYL4WzmUDBRGK0pDbIoFd7UZKoDurDzWEoNMYoj1EL+foGRQNyPWDcC+YyegN5y1DUsFFmzjGijB3nSVAQ== + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.15.tgz#97a61b385e57fe458496fad19f8e63b63c867de4" + integrity sha512-jKkwA59IXcvSaiK2UN45kKwSC9o+KuoXsBDvHvU/7BecYIp8GQ2UwrVvFgJASUT+hBnwJx6MhvMCuMzwZZ7jlg== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" "@babel/helper-environment-visitor" "^7.22.5" "@babel/helper-function-name" "^7.22.5" - "@babel/helper-member-expression-to-functions" "^7.22.5" + "@babel/helper-member-expression-to-functions" "^7.22.15" "@babel/helper-optimise-call-expression" "^7.22.5" "@babel/helper-replace-supers" "^7.22.9" "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" @@ -121,9 +121,9 @@ semver "^6.3.1" "@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.22.5": - version "7.22.9" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.9.tgz#9d8e61a8d9366fe66198f57c40565663de0825f6" - integrity sha512-+svjVa/tFwsNSG4NEy1h85+HQ5imbT92Q5/bgtS7P0GTQlP8WuFdqsiABmQouhiFGyV66oGxZFpeYHza1rNsKw== + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz#5ee90093914ea09639b01c711db0d6775e558be1" + integrity sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" regexpu-core "^5.3.1" @@ -140,10 +140,10 @@ lodash.debounce "^4.0.8" resolve "^1.14.2" -"@babel/helper-environment-visitor@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz#f06dd41b7c1f44e1f8da6c4055b41ab3a09a7e98" - integrity sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q== +"@babel/helper-environment-visitor@^7.22.20", "@babel/helper-environment-visitor@^7.22.5": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== "@babel/helper-function-name@^7.22.5": version "7.22.5" @@ -160,30 +160,30 @@ dependencies: "@babel/types" "^7.22.5" -"@babel/helper-member-expression-to-functions@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.5.tgz#0a7c56117cad3372fbf8d2fb4bf8f8d64a1e76b2" - integrity sha512-aBiH1NKMG0H2cGZqspNvsaBe6wNGjbJjuLy29aU+eDZjSbbN53BaxlpB02xm9v34pLTZ1nIQPFYn2qMZoa5BQQ== +"@babel/helper-member-expression-to-functions@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.15.tgz#b95a144896f6d491ca7863576f820f3628818621" + integrity sha512-qLNsZbgrNh0fDQBCPocSL8guki1hcPvltGDv/NxvUoABwFq7GkKSu1nRXeJkVZc+wJvne2E0RKQz+2SQrz6eAA== dependencies: - "@babel/types" "^7.22.5" + "@babel/types" "^7.22.15" -"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz#1a8f4c9f4027d23f520bd76b364d44434a72660c" - integrity sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg== +"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.22.15", "@babel/helper-module-imports@^7.22.5": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" + integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== dependencies: - "@babel/types" "^7.22.5" + "@babel/types" "^7.22.15" -"@babel/helper-module-transforms@^7.22.5", "@babel/helper-module-transforms@^7.22.9": - version "7.22.9" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz#92dfcb1fbbb2bc62529024f72d942a8c97142129" - integrity sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ== +"@babel/helper-module-transforms@^7.22.15", "@babel/helper-module-transforms@^7.22.20", "@babel/helper-module-transforms@^7.22.5", "@babel/helper-module-transforms@^7.22.9": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.22.20.tgz#da9edc14794babbe7386df438f3768067132f59e" + integrity sha512-dLT7JVWIUUxKOs1UnJUBR3S70YK+pKX6AbJgB2vMIvEkZkrfJDbYDJesnPshtKV4LhDOR3Oc5YULeDizRek+5A== dependencies: - "@babel/helper-environment-visitor" "^7.22.5" - "@babel/helper-module-imports" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-module-imports" "^7.22.15" "@babel/helper-simple-access" "^7.22.5" "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/helper-validator-identifier" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.20" "@babel/helper-optimise-call-expression@^7.22.5": version "7.22.5" @@ -198,21 +198,21 @@ integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== "@babel/helper-remap-async-to-generator@^7.22.5", "@babel/helper-remap-async-to-generator@^7.22.9": - version "7.22.9" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.9.tgz#53a25b7484e722d7efb9c350c75c032d4628de82" - integrity sha512-8WWC4oR4Px+tr+Fp0X3RHDVfINGpF3ad1HIbrc8A77epiR6eMMc6jsgozkzT2uDiOOdoS9cLIQ+XD2XvI2WSmQ== + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz#7b68e1cb4fa964d2996fd063723fb48eca8498e0" + integrity sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-environment-visitor" "^7.22.5" - "@babel/helper-wrap-function" "^7.22.9" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-wrap-function" "^7.22.20" "@babel/helper-replace-supers@^7.22.5", "@babel/helper-replace-supers@^7.22.9": - version "7.22.9" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.22.9.tgz#cbdc27d6d8d18cd22c81ae4293765a5d9afd0779" - integrity sha512-LJIKvvpgPOPUThdYqcX6IXRuIcTkcAub0IaDRGCZH0p5GPUp7PhRU9QVgFcDDd51BaPkk77ZjqFwh6DZTAEmGg== + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz#e37d367123ca98fe455a9887734ed2e16eb7a793" + integrity sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw== dependencies: - "@babel/helper-environment-visitor" "^7.22.5" - "@babel/helper-member-expression-to-functions" "^7.22.5" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-member-expression-to-functions" "^7.22.15" "@babel/helper-optimise-call-expression" "^7.22.5" "@babel/helper-simple-access@^7.22.5": @@ -241,63 +241,63 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== -"@babel/helper-validator-identifier@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz#9544ef6a33999343c8740fa51350f30eeaaaf193" - integrity sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ== +"@babel/helper-validator-identifier@^7.22.19", "@babel/helper-validator-identifier@^7.22.20", "@babel/helper-validator-identifier@^7.22.5": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== -"@babel/helper-validator-option@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz#de52000a15a177413c8234fa3a8af4ee8102d0ac" - integrity sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw== +"@babel/helper-validator-option@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz#694c30dfa1d09a6534cdfcafbe56789d36aba040" + integrity sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA== -"@babel/helper-wrap-function@^7.22.9": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.22.10.tgz#d845e043880ed0b8c18bd194a12005cb16d2f614" - integrity sha512-OnMhjWjuGYtdoO3FmsEFWvBStBAe2QOgwOLsLNDjN+aaiMD8InJk1/O3HSD8lkqTjCgg5YI34Tz15KNNA3p+nQ== +"@babel/helper-wrap-function@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz#15352b0b9bfb10fc9c76f79f6342c00e3411a569" + integrity sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw== dependencies: "@babel/helper-function-name" "^7.22.5" - "@babel/template" "^7.22.5" - "@babel/types" "^7.22.10" + "@babel/template" "^7.22.15" + "@babel/types" "^7.22.19" -"@babel/helpers@^7.22.11": - version "7.22.11" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.11.tgz#b02f5d5f2d7abc21ab59eeed80de410ba70b056a" - integrity sha512-vyOXC8PBWaGc5h7GMsNx68OH33cypkEDJCHvYVVgVbbxJDROYVtexSk0gK5iCF1xNjRIN2s8ai7hwkWDq5szWg== +"@babel/helpers@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.22.15.tgz#f09c3df31e86e3ea0b7ff7556d85cdebd47ea6f1" + integrity sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw== dependencies: - "@babel/template" "^7.22.5" - "@babel/traverse" "^7.22.11" - "@babel/types" "^7.22.11" + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.22.15" + "@babel/types" "^7.22.15" "@babel/highlight@^7.10.4", "@babel/highlight@^7.22.13": - version "7.22.13" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.13.tgz#9cda839e5d3be9ca9e8c26b6dd69e7548f0cbf16" - integrity sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ== + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.22.20.tgz#4ca92b71d80554b01427815e06f2df965b9c1f54" + integrity sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg== dependencies: - "@babel/helper-validator-identifier" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.20" chalk "^2.4.2" js-tokens "^4.0.0" -"@babel/parser@^7.22.11", "@babel/parser@^7.22.5": - version "7.22.14" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.14.tgz#c7de58e8de106e88efca42ce17f0033209dfd245" - integrity sha512-1KucTHgOvaw/LzCVrEOAyXkr9rQlp0A1HiHRYnSUE9dmb8PvPW7o5sscg+5169r54n3vGlbx6GevTE/Iw/P3AQ== +"@babel/parser@^7.22.15", "@babel/parser@^7.22.16": + version "7.22.16" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.22.16.tgz#180aead7f247305cce6551bea2720934e2fa2c95" + integrity sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA== -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.5.tgz#87245a21cd69a73b0b81bcda98d443d6df08f05e" - integrity sha512-NP1M5Rf+u2Gw9qfSO4ihjcTGW5zXTi36ITLd4/EoAcEhIZ0yjMqmftDNl3QC19CX7olhrjpyU454g/2W7X0jvQ== +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.22.15.tgz#02dc8a03f613ed5fdc29fb2f728397c78146c962" + integrity sha512-FB9iYlz7rURmRJyXRKEnalYPPdn87H5no108cyuQQyMwlpJ2SJtpIUBI27kdTin956pz+LPypkPVPUTlxOmrsg== dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.5.tgz#fef09f9499b1f1c930da8a0c419db42167d792ca" - integrity sha512-31Bb65aZaUwqCbWMnZPduIZxCBngHFlzyN6Dq6KAJjtx+lx6ohKHubc61OomYi7XwVD4Ol0XCVz4h+pYFR048g== +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.22.15.tgz#2aeb91d337d4e1a1e7ce85b76a37f5301781200f" + integrity sha512-Hyph9LseGvAeeXzikV88bczhsrLrIZqDPxO+sSmAunMPaGrBGhfMWzCPYTtiW9t+HzSE2wtV8e5cc5P6r1xMDQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" - "@babel/plugin-transform-optional-chaining" "^7.22.5" + "@babel/plugin-transform-optional-chaining" "^7.22.15" "@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": version "7.21.0-placeholder-for-preset-env.2" @@ -438,10 +438,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-async-generator-functions@^7.22.11": - version "7.22.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.11.tgz#dbe3b1ff5a52e2e5edc4b19a60d325a675ed2649" - integrity sha512-0pAlmeRJn6wU84zzZsEOx1JV1Jf8fqO9ok7wofIJwUnplYo247dcd24P+cMJht7ts9xkzdtB0EPHmOb7F+KzXw== +"@babel/plugin-transform-async-generator-functions@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.22.15.tgz#3b153af4a6b779f340d5b80d3f634f55820aefa3" + integrity sha512-jBm1Es25Y+tVoTi5rfd5t1KLmL8ogLKpXszboWOTTtGFGz2RKnQe2yn7HbZ+kb/B8N0FVSGQo874NSlOU1T4+w== dependencies: "@babel/helper-environment-visitor" "^7.22.5" "@babel/helper-plugin-utils" "^7.22.5" @@ -464,10 +464,10 @@ dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-block-scoping@^7.22.10": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.10.tgz#88a1dccc3383899eb5e660534a76a22ecee64faa" - integrity sha512-1+kVpGAOOI1Albt6Vse7c8pHzcZQdQKW+wJH+g8mCaszOdDVwRXa/slHPqIw+oJAJANTKDMuM2cBdV0Dg618Vg== +"@babel/plugin-transform-block-scoping@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.22.15.tgz#494eb82b87b5f8b1d8f6f28ea74078ec0a10a841" + integrity sha512-G1czpdJBZCtngoK1sJgloLiOHUnkb/bLZwqVZD8kXmq0ZnVfTTWUcs9OWtp0mBtYJ+4LQY1fllqBkOIPhXmFmw== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -488,18 +488,18 @@ "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-class-static-block" "^7.14.5" -"@babel/plugin-transform-classes@^7.22.6": - version "7.22.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.6.tgz#e04d7d804ed5b8501311293d1a0e6d43e94c3363" - integrity sha512-58EgM6nuPNG6Py4Z3zSuu0xWu2VfodiMi72Jt5Kj2FECmaYk1RrTXA45z6KBFsu9tRgwQDwIiY4FXTt+YsSFAQ== +"@babel/plugin-transform-classes@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.22.15.tgz#aaf4753aee262a232bbc95451b4bdf9599c65a0b" + integrity sha512-VbbC3PGjBdE0wAWDdHM9G8Gm977pnYI0XpqMd6LrKISj8/DJXEsWqgRuTYaNE9Bv0JGhTZUzHDlMk18IpOuoqw== dependencies: "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-compilation-targets" "^7.22.6" + "@babel/helper-compilation-targets" "^7.22.15" "@babel/helper-environment-visitor" "^7.22.5" "@babel/helper-function-name" "^7.22.5" "@babel/helper-optimise-call-expression" "^7.22.5" "@babel/helper-plugin-utils" "^7.22.5" - "@babel/helper-replace-supers" "^7.22.5" + "@babel/helper-replace-supers" "^7.22.9" "@babel/helper-split-export-declaration" "^7.22.6" globals "^11.1.0" @@ -511,10 +511,10 @@ "@babel/helper-plugin-utils" "^7.22.5" "@babel/template" "^7.22.5" -"@babel/plugin-transform-destructuring@^7.22.10": - version "7.22.10" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.10.tgz#38e2273814a58c810b6c34ea293be4973c4eb5e2" - integrity sha512-dPJrL0VOyxqLM9sritNbMSGx/teueHF/htMKrPT7DNxccXxRDPYqlgPFFdr8u+F+qUZOkZoXue/6rL5O5GduEw== +"@babel/plugin-transform-destructuring@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.22.15.tgz#e7404ea5bb3387073b9754be654eecb578324694" + integrity sha512-HzG8sFl1ZVGTme74Nw+X01XsUTqERVQ6/RLHo3XjGRzm7XD6QTtfS3NJotVgCGy8BzkDqRjRBD8dAyJn5TuvSQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -557,10 +557,10 @@ "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-export-namespace-from" "^7.8.3" -"@babel/plugin-transform-for-of@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.5.tgz#ab1b8a200a8f990137aff9a084f8de4099ab173f" - integrity sha512-3kxQjX1dU9uudwSshyLeEipvrLjBCVthCgeTp6CzE/9JYrlAIaeekVxRpCWsDDfYTfRZRoCeZatCQvwo+wvK8A== +"@babel/plugin-transform-for-of@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.22.15.tgz#f64b4ccc3a4f131a996388fae7680b472b306b29" + integrity sha512-me6VGeHsx30+xh9fbDLLPi0J1HzmeIIyenoOQHuw2D4m2SAU3NrspX5XxJLBpqn5yrLzrlw2Iy3RA//Bx27iOA== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -611,12 +611,12 @@ "@babel/helper-module-transforms" "^7.22.5" "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-transform-modules-commonjs@^7.22.11": - version "7.22.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.11.tgz#d7991d3abad199c03b68ee66a64f216c47ffdfae" - integrity sha512-o2+bg7GDS60cJMgz9jWqRUsWkMzLCxp+jFDeDUT5sjRlAxcJWZ2ylNdI7QQ2+CH5hWu7OnN+Cv3htt7AkSf96g== +"@babel/plugin-transform-modules-commonjs@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.22.15.tgz#b11810117ed4ee7691b29bd29fd9f3f98276034f" + integrity sha512-jWL4eh90w0HQOTKP2MoXXUpVxilxsB2Vl4ji69rSjS3EcZ/v4sBmn+A3NpepuJzBhOaEBbR7udonlHHn5DWidg== dependencies: - "@babel/helper-module-transforms" "^7.22.9" + "@babel/helper-module-transforms" "^7.22.15" "@babel/helper-plugin-utils" "^7.22.5" "@babel/helper-simple-access" "^7.22.5" @@ -669,16 +669,16 @@ "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-numeric-separator" "^7.10.4" -"@babel/plugin-transform-object-rest-spread@^7.22.11": - version "7.22.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.11.tgz#dbbb06ce783cd994a8f430d8cefa553e9b42ca62" - integrity sha512-nX8cPFa6+UmbepISvlf5jhQyaC7ASs/7UxHmMkuJ/k5xSHvDPPaibMo+v3TXwU/Pjqhep/nFNpd3zn4YR59pnw== +"@babel/plugin-transform-object-rest-spread@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.22.15.tgz#21a95db166be59b91cde48775310c0df6e1da56f" + integrity sha512-fEB+I1+gAmfAyxZcX1+ZUwLeAuuf8VIg67CTznZE0MqVFumWkh8xWtn58I4dxdVf080wn7gzWoF8vndOViJe9Q== dependencies: "@babel/compat-data" "^7.22.9" - "@babel/helper-compilation-targets" "^7.22.10" + "@babel/helper-compilation-targets" "^7.22.15" "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.22.5" + "@babel/plugin-transform-parameters" "^7.22.15" "@babel/plugin-transform-object-super@^7.22.5": version "7.22.5" @@ -696,19 +696,19 @@ "@babel/helper-plugin-utils" "^7.22.5" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" -"@babel/plugin-transform-optional-chaining@^7.22.12", "@babel/plugin-transform-optional-chaining@^7.22.5": - version "7.22.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.12.tgz#d7ebf6a88cd2f4d307b0e000ab630acd8124b333" - integrity sha512-7XXCVqZtyFWqjDsYDY4T45w4mlx1rf7aOgkc/Ww76xkgBiOlmjPkx36PBLHa1k1rwWvVgYMPsbuVnIamx2ZQJw== +"@babel/plugin-transform-optional-chaining@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.22.15.tgz#d7a5996c2f7ca4ad2ad16dbb74444e5c4385b1ba" + integrity sha512-ngQ2tBhq5vvSJw2Q2Z9i7ealNkpDMU0rGWnHPKqRZO0tzZ5tlaoz4hDvhXioOoaE0X2vfNss1djwg0DXlfu30A== dependencies: "@babel/helper-plugin-utils" "^7.22.5" "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" "@babel/plugin-syntax-optional-chaining" "^7.8.3" -"@babel/plugin-transform-parameters@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.5.tgz#c3542dd3c39b42c8069936e48717a8d179d63a18" - integrity sha512-AVkFUBurORBREOmHRKo06FjHYgjrabpdqRSwq6+C7R5iTCZOsM4QbcB27St0a4U6fffyAOqh3s/qEfybAhfivg== +"@babel/plugin-transform-parameters@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.22.15.tgz#719ca82a01d177af358df64a514d64c2e3edb114" + integrity sha512-hjk7qKIqhyzhhUvRT683TYQOFa/4cQKwQy7ALvTpODswN40MljzNDa0YldevS6tGbxwaEKVn502JmY0dP7qEtQ== dependencies: "@babel/helper-plugin-utils" "^7.22.5" @@ -820,16 +820,16 @@ "@babel/helper-plugin-utils" "^7.22.5" "@babel/preset-env@^7.11.0": - version "7.22.14" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.22.14.tgz#1cbb468d899f64fa71c53446f13b7ff8c0005cc1" - integrity sha512-daodMIoVo+ol/g+//c/AH+szBkFj4STQUikvBijRGL72Ph+w+AMTSh55DUETe8KJlPlDT1k/mp7NBfOuiWmoig== + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.22.20.tgz#de9e9b57e1127ce0a2f580831717f7fb677ceedb" + integrity sha512-11MY04gGC4kSzlPHRfvVkNAZhUxOvm7DCJ37hPDnUENwe06npjIRAfInEMTGSb4LZK5ZgDFkv5hw0lGebHeTyg== dependencies: - "@babel/compat-data" "^7.22.9" - "@babel/helper-compilation-targets" "^7.22.10" + "@babel/compat-data" "^7.22.20" + "@babel/helper-compilation-targets" "^7.22.15" "@babel/helper-plugin-utils" "^7.22.5" - "@babel/helper-validator-option" "^7.22.5" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.22.5" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.22.5" + "@babel/helper-validator-option" "^7.22.15" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.22.15" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.22.15" "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-class-properties" "^7.12.13" @@ -850,39 +850,39 @@ "@babel/plugin-syntax-top-level-await" "^7.14.5" "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" "@babel/plugin-transform-arrow-functions" "^7.22.5" - "@babel/plugin-transform-async-generator-functions" "^7.22.11" + "@babel/plugin-transform-async-generator-functions" "^7.22.15" "@babel/plugin-transform-async-to-generator" "^7.22.5" "@babel/plugin-transform-block-scoped-functions" "^7.22.5" - "@babel/plugin-transform-block-scoping" "^7.22.10" + "@babel/plugin-transform-block-scoping" "^7.22.15" "@babel/plugin-transform-class-properties" "^7.22.5" "@babel/plugin-transform-class-static-block" "^7.22.11" - "@babel/plugin-transform-classes" "^7.22.6" + "@babel/plugin-transform-classes" "^7.22.15" "@babel/plugin-transform-computed-properties" "^7.22.5" - "@babel/plugin-transform-destructuring" "^7.22.10" + "@babel/plugin-transform-destructuring" "^7.22.15" "@babel/plugin-transform-dotall-regex" "^7.22.5" "@babel/plugin-transform-duplicate-keys" "^7.22.5" "@babel/plugin-transform-dynamic-import" "^7.22.11" "@babel/plugin-transform-exponentiation-operator" "^7.22.5" "@babel/plugin-transform-export-namespace-from" "^7.22.11" - "@babel/plugin-transform-for-of" "^7.22.5" + "@babel/plugin-transform-for-of" "^7.22.15" "@babel/plugin-transform-function-name" "^7.22.5" "@babel/plugin-transform-json-strings" "^7.22.11" "@babel/plugin-transform-literals" "^7.22.5" "@babel/plugin-transform-logical-assignment-operators" "^7.22.11" "@babel/plugin-transform-member-expression-literals" "^7.22.5" "@babel/plugin-transform-modules-amd" "^7.22.5" - "@babel/plugin-transform-modules-commonjs" "^7.22.11" + "@babel/plugin-transform-modules-commonjs" "^7.22.15" "@babel/plugin-transform-modules-systemjs" "^7.22.11" "@babel/plugin-transform-modules-umd" "^7.22.5" "@babel/plugin-transform-named-capturing-groups-regex" "^7.22.5" "@babel/plugin-transform-new-target" "^7.22.5" "@babel/plugin-transform-nullish-coalescing-operator" "^7.22.11" "@babel/plugin-transform-numeric-separator" "^7.22.11" - "@babel/plugin-transform-object-rest-spread" "^7.22.11" + "@babel/plugin-transform-object-rest-spread" "^7.22.15" "@babel/plugin-transform-object-super" "^7.22.5" "@babel/plugin-transform-optional-catch-binding" "^7.22.11" - "@babel/plugin-transform-optional-chaining" "^7.22.12" - "@babel/plugin-transform-parameters" "^7.22.5" + "@babel/plugin-transform-optional-chaining" "^7.22.15" + "@babel/plugin-transform-parameters" "^7.22.15" "@babel/plugin-transform-private-methods" "^7.22.5" "@babel/plugin-transform-private-property-in-object" "^7.22.11" "@babel/plugin-transform-property-literals" "^7.22.5" @@ -898,7 +898,7 @@ "@babel/plugin-transform-unicode-regex" "^7.22.5" "@babel/plugin-transform-unicode-sets-regex" "^7.22.5" "@babel/preset-modules" "0.1.6-no-external-plugins" - "@babel/types" "^7.22.11" + "@babel/types" "^7.22.19" babel-plugin-polyfill-corejs2 "^0.4.5" babel-plugin-polyfill-corejs3 "^0.8.3" babel-plugin-polyfill-regenerator "^0.5.2" @@ -919,45 +919,45 @@ resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310" integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== -"@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.15.4", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.10", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": - version "7.22.11" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.11.tgz#7a9ba3bbe406ad6f9e8dd4da2ece453eb23a77a4" - integrity sha512-ee7jVNlWN09+KftVOu9n7S8gQzD/Z6hN/I8VBRXW4P1+Xe7kJGXMwu8vds4aGIMHZnNbdpSWCfZZtinytpcAvA== +"@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.15.4", "@babel/runtime@^7.18.3", "@babel/runtime@^7.20.7", "@babel/runtime@^7.21.0", "@babel/runtime@^7.22.15", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.15.tgz#38f46494ccf6cf020bd4eed7124b425e83e523b8" + integrity sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA== dependencies: regenerator-runtime "^0.14.0" -"@babel/template@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec" - integrity sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw== +"@babel/template@^7.22.15", "@babel/template@^7.22.5": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" + integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== dependencies: - "@babel/code-frame" "^7.22.5" - "@babel/parser" "^7.22.5" - "@babel/types" "^7.22.5" + "@babel/code-frame" "^7.22.13" + "@babel/parser" "^7.22.15" + "@babel/types" "^7.22.15" -"@babel/traverse@^7.22.11": - version "7.22.11" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.11.tgz#71ebb3af7a05ff97280b83f05f8865ac94b2027c" - integrity sha512-mzAenteTfomcB7mfPtyi+4oe5BZ6MXxWcn4CX+h4IRJ+OOGXBrWU6jDQavkQI9Vuc5P+donFabBfFCcmWka9lQ== +"@babel/traverse@^7.22.15", "@babel/traverse@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.22.20.tgz#db572d9cb5c79e02d83e5618b82f6991c07584c9" + integrity sha512-eU260mPZbU7mZ0N+X10pxXhQFMGTeLb9eFS0mxehS8HZp9o1uSnFeWQuG1UPrlxgA7QoUzFhOnilHDp0AXCyHw== dependencies: - "@babel/code-frame" "^7.22.10" - "@babel/generator" "^7.22.10" - "@babel/helper-environment-visitor" "^7.22.5" + "@babel/code-frame" "^7.22.13" + "@babel/generator" "^7.22.15" + "@babel/helper-environment-visitor" "^7.22.20" "@babel/helper-function-name" "^7.22.5" "@babel/helper-hoist-variables" "^7.22.5" "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.22.11" - "@babel/types" "^7.22.11" + "@babel/parser" "^7.22.16" + "@babel/types" "^7.22.19" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.22.10", "@babel/types@^7.22.11", "@babel/types@^7.22.5", "@babel/types@^7.4.4": - version "7.22.11" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.11.tgz#0e65a6a1d4d9cbaa892b2213f6159485fe632ea2" - integrity sha512-siazHiGuZRz9aB9NpHy9GOs9xiQPKnMzgdr493iI1M67vRXpnEq8ZOOKzezC5q7zwuQ6sDhdSp4SD9ixKSqKZg== +"@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.4.4": + version "7.22.19" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.22.19.tgz#7425343253556916e440e662bb221a93ddb75684" + integrity sha512-P7LAw/LbojPzkgp5oznjE6tQEIWbp4PkkfrZDINTro9zgBRtI324/EYsiSI7lhPbpIQ+DCeR2NNmMWANGGfZsg== dependencies: "@babel/helper-string-parser" "^7.22.5" - "@babel/helper-validator-identifier" "^7.22.5" + "@babel/helper-validator-identifier" "^7.22.19" to-fast-properties "^2.0.0" "@blueprintjs/colors@^4.2.1": @@ -1304,9 +1304,9 @@ eslint-visitor-keys "^3.3.0" "@eslint-community/regexpp@^4.4.0", "@eslint-community/regexpp@^4.6.1": - version "4.8.0" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.8.0.tgz#11195513186f68d42fbf449f9a7136b2c0c92005" - integrity sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg== + version "4.8.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.8.1.tgz#8c4bb756cc2aa7eaf13cfa5e69c83afb3260c20c" + integrity sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ== "@eslint/eslintrc@^0.4.3": version "0.4.3" @@ -1358,37 +1358,37 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.36.0.tgz#9837f768c03a1e4a30bd304a64fb8844f0e72efe" integrity sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg== -"@eslint/js@8.48.0": - version "8.48.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.48.0.tgz#642633964e217905436033a2bd08bf322849b7fb" - integrity sha512-ZSjtmelB7IJfWD2Fvb7+Z+ChTIKWq6kjda95fLcQKNS5aheVHn4IkfgRQE3sIIzTcSLwLcLZUD9UBt+V7+h+Pw== +"@eslint/js@8.49.0": + version "8.49.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.49.0.tgz#86f79756004a97fa4df866835093f1df3d03c333" + integrity sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w== -"@floating-ui/core@^1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.4.1.tgz#0d633f4b76052668afb932492ac452f7ebe97f17" - integrity sha512-jk3WqquEJRlcyu7997NtR5PibI+y5bi+LS3hPmguVClypenMsCY3CBa3LAQnozRCtCrYWSEtAdiskpamuJRFOQ== +"@floating-ui/core@^1.4.2": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.5.0.tgz#5c05c60d5ae2d05101c3021c1a2a350ddc027f8c" + integrity sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg== dependencies: - "@floating-ui/utils" "^0.1.1" + "@floating-ui/utils" "^0.1.3" "@floating-ui/dom@^1.5.1": - version "1.5.1" - resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.5.1.tgz#88b70defd002fe851f17b4a25efb2d3c04d7a8d7" - integrity sha512-KwvVcPSXg6mQygvA1TjbN/gh///36kKtllIF8SUm0qpFj8+rvYrpvlYdL1JoA71SHpDqgSSdGOSoQ0Mp3uY5aw== + version "1.5.3" + resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.5.3.tgz#54e50efcb432c06c23cd33de2b575102005436fa" + integrity sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA== dependencies: - "@floating-ui/core" "^1.4.1" - "@floating-ui/utils" "^0.1.1" + "@floating-ui/core" "^1.4.2" + "@floating-ui/utils" "^0.1.3" -"@floating-ui/react-dom@^2.0.1": +"@floating-ui/react-dom@^2.0.2": version "2.0.2" resolved "https://registry.yarnpkg.com/@floating-ui/react-dom/-/react-dom-2.0.2.tgz#fab244d64db08e6bed7be4b5fcce65315ef44d20" integrity sha512-5qhlDvjaLmAst/rKb3VdlCinwTF4EYMiVxuuc/HVUjs46W0zgtbMmAZ1UTsDrRTxRmUEzl92mOtWbeeXL26lSQ== dependencies: "@floating-ui/dom" "^1.5.1" -"@floating-ui/utils@^0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.1.tgz#1a5b1959a528e374e8037c4396c3e825d6cf4a83" - integrity sha512-m0G6wlnhm/AX0H12IOWtK8gASEMffnX08RtKkCgTdHb9JpHKGloI7icFfLg9ZmQeavcvR0PKmzxClyuFPSjKWw== +"@floating-ui/utils@^0.1.3": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.1.4.tgz#19654d1026cc410975d46445180e70a5089b3e7d" + integrity sha512-qprfWkn82Iw821mcKofJ5Pk9wgioHicxcQMxx+5zt5GSKoqdWvgG5AxVmpmUUjzTLPVSH5auBrhI93Deayn/DA== "@headlessui/react@^1.7.13", "@headlessui/react@^1.7.3": version "1.7.17" @@ -1402,7 +1402,7 @@ resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-2.0.18.tgz#f80301907c243df03c7e9fd76c0286e95361f7c1" integrity sha512-7TyMjRrZZMBPa+/5Y8lN0iyvUU/01PeMGX2+RE7cQWpEUIcb4QotzUObFkJDejj/HUH4qjP/eQ0gzzKs2f+6Yw== -"@humanwhocodes/config-array@^0.11.10", "@humanwhocodes/config-array@^0.11.8": +"@humanwhocodes/config-array@^0.11.11", "@humanwhocodes/config-array@^0.11.8": version "0.11.11" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844" integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA== @@ -1501,44 +1501,42 @@ resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60" integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA== -"@mui/base@5.0.0-beta.13": - version "5.0.0-beta.13" - resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.13.tgz#3bae94c39752546d84a67d4ca73486b7c4923a89" - integrity sha512-uC0l97pBspfDAp+iz2cJq8YZ8Sd9i73V77+WzUiOAckIVEyCm5dyVDZCCO2/phmzckVEeZCGcytybkjMQuhPQw== +"@mui/base@5.0.0-beta.16": + version "5.0.0-beta.16" + resolved "https://registry.yarnpkg.com/@mui/base/-/base-5.0.0-beta.16.tgz#5869b8cc83ea5da0083bb11790bda007c2384564" + integrity sha512-OYxhC81c9bO0wobGcM8rrY5bRwpCXAI21BL0P2wz/2vTv4ek7ALz9+U5M8wgdmtRNUhmCmAB4L2WRwFRf5Cd8Q== dependencies: - "@babel/runtime" "^7.22.10" - "@emotion/is-prop-valid" "^1.2.1" - "@floating-ui/react-dom" "^2.0.1" + "@babel/runtime" "^7.22.15" + "@floating-ui/react-dom" "^2.0.2" "@mui/types" "^7.2.4" - "@mui/utils" "^5.14.7" + "@mui/utils" "^5.14.10" "@popperjs/core" "^2.11.8" clsx "^2.0.0" prop-types "^15.8.1" - react-is "^18.2.0" -"@mui/core-downloads-tracker@^5.14.7": - version "5.14.7" - resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.7.tgz#95bed2487bf59632125a13b8eb8f4c21e460afec" - integrity sha512-sCWTUNElBPgB30iLvWe3PU7SIlTKZNf6/E/sko85iHVeHCM6WPkDw+y89CrZYjhFNmPqt2fIQM/pZu+rP2lFLA== +"@mui/core-downloads-tracker@^5.14.10": + version "5.14.10" + resolved "https://registry.yarnpkg.com/@mui/core-downloads-tracker/-/core-downloads-tracker-5.14.10.tgz#32a8581be98344bbda5ed31fc7b41788bd2e3bc5" + integrity sha512-kPHu/NhZq1k+vSZR5wq3AyUfD4bnfWAeuKpps0+8PS7ZHQ2Lyv1cXJh+PlFdCIOa0PK98rk3JPwMzS8BMhdHwQ== "@mui/icons-material@^5.14.1": - version "5.14.7" - resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.14.7.tgz#d7f6bd188fe38adf35c89d9343b8a529c2306383" - integrity sha512-mWp4DwMa8c1Gx9yOEtPgxM4b+e6hAbtZyzfSubdBwrnEE6G5D2rbAJ5MB+If6kfI48JaYaJ5j8+zAdmZLuZc0A== + version "5.14.9" + resolved "https://registry.yarnpkg.com/@mui/icons-material/-/icons-material-5.14.9.tgz#433cf03c214ce38e1b7a6f684769491fd99c5ef5" + integrity sha512-xTRQbDsogsJo7tY5Og8R9zbuG2q+KIPVIM6JQoKxtJlz9DPOw1u0T2fGrvwD+XAOVifQf6epNMcGCDLfJAz4Nw== dependencies: - "@babel/runtime" "^7.22.10" + "@babel/runtime" "^7.22.15" "@mui/material@^5.14.1": - version "5.14.7" - resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.14.7.tgz#6c2c0de8a625562f789e1bb33cb4cfc8cf20bdb0" - integrity sha512-jIZj9F7zMv6IlyaYDVv5M2Kp20jIX8c0kzuwteySHS/A0IvPVyomQEPtWc51MCbpDNCqzwoZUp3rQtA2lI8k7A== - dependencies: - "@babel/runtime" "^7.22.10" - "@mui/base" "5.0.0-beta.13" - "@mui/core-downloads-tracker" "^5.14.7" - "@mui/system" "^5.14.7" + version "5.14.10" + resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.14.10.tgz#b8c6ba17c25c0df54053cb0f1bb35083bc91dace" + integrity sha512-ejFMppnO+lzBXpzju+N4SSz0Mhmi5sihXUGcr5FxpgB6bfUP0Lpe32O0Sw/3s8xlmLEvG1fqVT0rRyAVMlCA+A== + dependencies: + "@babel/runtime" "^7.22.15" + "@mui/base" "5.0.0-beta.16" + "@mui/core-downloads-tracker" "^5.14.10" + "@mui/system" "^5.14.10" "@mui/types" "^7.2.4" - "@mui/utils" "^5.14.7" + "@mui/utils" "^5.14.10" "@types/react-transition-group" "^4.4.6" clsx "^2.0.0" csstype "^3.1.2" @@ -1546,35 +1544,35 @@ react-is "^18.2.0" react-transition-group "^4.4.5" -"@mui/private-theming@^5.14.7": - version "5.14.7" - resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.14.7.tgz#c9fec31e59bf66b12959e724b0e8ec3bb4a3d923" - integrity sha512-Y86+hmDnJab2Ka42PgxKpK3oL7EiacbeeX3X/lG9LGO0wSc45wZjHeTfIlVSkkUCkexiMKEJp5NlSjZhr27NRQ== +"@mui/private-theming@^5.14.10": + version "5.14.10" + resolved "https://registry.yarnpkg.com/@mui/private-theming/-/private-theming-5.14.10.tgz#42b176b27435931aff40d50833413d10150ac007" + integrity sha512-f67xOj3H06wWDT9xBg7hVL/HSKNF+HG1Kx0Pm23skkbEqD2Ef2Lif64e5nPdmWVv+7cISCYtSuE2aeuzrZe78w== dependencies: - "@babel/runtime" "^7.22.10" - "@mui/utils" "^5.14.7" + "@babel/runtime" "^7.22.15" + "@mui/utils" "^5.14.10" prop-types "^15.8.1" -"@mui/styled-engine@^5.14.7": - version "5.14.7" - resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.14.7.tgz#aaacec6c87bcc9a180b2da062c613213af10f2e3" - integrity sha512-hKBETEDsIAkL8/mBwPiQj/vw28OeIhMXC3Tvj4J2bb9snxAKpiZioR1PwqP+6P41twsC/GKBd0Vr9oaWYaHuMg== +"@mui/styled-engine@^5.14.10": + version "5.14.10" + resolved "https://registry.yarnpkg.com/@mui/styled-engine/-/styled-engine-5.14.10.tgz#2ec443031e48425cd6fda63be498cfa262c1d3a0" + integrity sha512-EJckxmQHrsBvDbFu1trJkvjNw/1R7jfNarnqPSnL+jEQawCkQIqVELWLrlOa611TFtxSJGkdUfCFXeJC203HVg== dependencies: - "@babel/runtime" "^7.22.10" + "@babel/runtime" "^7.22.15" "@emotion/cache" "^11.11.0" csstype "^3.1.2" prop-types "^15.8.1" -"@mui/system@^5.14.7": - version "5.14.7" - resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.14.7.tgz#b08e23f9151d38186ab12dd618906abd4d73d203" - integrity sha512-jeZtHglc+Pi6qjGoopT6O4RqYXVBMqHVOsjMGP0hxGSSPm1T4gsAu7jU8eqGx9YwwjvvJ0eotTjFqw7iJ6qE2Q== +"@mui/system@^5.14.10": + version "5.14.10" + resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.14.10.tgz#b125f8370c1c92af04f1839c40e034d4edc4ad29" + integrity sha512-QQmtTG/R4gjmLiL5ECQ7kRxLKDm8aKKD7seGZfbINtRVJDyFhKChA1a+K2bfqIAaBo1EMDv+6FWNT1Q5cRKjFA== dependencies: - "@babel/runtime" "^7.22.10" - "@mui/private-theming" "^5.14.7" - "@mui/styled-engine" "^5.14.7" + "@babel/runtime" "^7.22.15" + "@mui/private-theming" "^5.14.10" + "@mui/styled-engine" "^5.14.10" "@mui/types" "^7.2.4" - "@mui/utils" "^5.14.7" + "@mui/utils" "^5.14.10" clsx "^2.0.0" csstype "^3.1.2" prop-types "^15.8.1" @@ -1584,14 +1582,13 @@ resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.4.tgz#b6fade19323b754c5c6de679a38f068fd50b9328" integrity sha512-LBcwa8rN84bKF+f5sDyku42w1NTxaPgPyYKODsh01U1fVstTClbUoSA96oyRBnSNyEiAVjKm6Gwx9vjR+xyqHA== -"@mui/utils@^5.14.7": - version "5.14.7" - resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.14.7.tgz#3677bcabe032f1185e151f57d8c1a166df3ae0a1" - integrity sha512-RtheP/aBoPogVdi8vj8Vo2IFnRa4mZVmnD0RGlVZ49yF60rZs+xP4/KbpIrTr83xVs34QmHQ2aQ+IX7I0a0dDw== +"@mui/utils@^5.14.10": + version "5.14.10" + resolved "https://registry.yarnpkg.com/@mui/utils/-/utils-5.14.10.tgz#4b0a2a26f1ee12323010daa9d7aecf3384acfc3c" + integrity sha512-Rn+vYQX7FxkcW0riDX/clNUwKuOJFH45HiULxwmpgnzQoQr3A0lb+QYwaZ+FAkZrR7qLoHKmLQlcItu6LT0y/Q== dependencies: - "@babel/runtime" "^7.22.10" + "@babel/runtime" "^7.22.15" "@types/prop-types" "^15.7.5" - "@types/react-is" "^18.2.1" prop-types "^15.8.1" react-is "^18.2.0" @@ -2159,9 +2156,9 @@ picomatch "^2.3.1" "@rushstack/eslint-patch@^1.1.3": - version "1.3.3" - resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.3.3.tgz#16ab6c727d8c2020a5b6e4a176a243ecd88d8d69" - integrity sha512-0xd7qez0AQ+MbHatZTlI1gu5vkG8r7MYRUJAHPAHJBmGLs16zpkrpAVLvjQKQOqaXPDUBwOiJzNc00znHSCVBw== + version "1.4.0" + resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.4.0.tgz#77e948b9760bd22736a5d26e335a690f76fda37b" + integrity sha512-cEjvTPU32OM9lUFegJagO0mRnIn+rbqrG89vV8/xLnLFX0DoR0r1oy5IlTga71Q7uT3Qus7qm7wgeiMT/+Irlg== "@scena/dragscroll@^1.4.0": version "1.4.0" @@ -2185,26 +2182,26 @@ dependencies: "@daybrush/utils" "^1.4.0" -"@sentry-internal/tracing@7.66.0": - version "7.66.0" - resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.66.0.tgz#45ea607917d55a5bcaa3229341387ff6ed9b3a2b" - integrity sha512-3vCgC2hC3T45pn53yTDVcRpHoJTBxelDPPZVsipAbZnoOVPkj7n6dNfDhj3I3kwWCBPahPkXmE+R4xViR8VqJg== +"@sentry-internal/tracing@7.69.0": + version "7.69.0" + resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.69.0.tgz#8d8eb740b72967b6ba3fdc0a5173aa55331b7d35" + integrity sha512-4BgeWZUj9MO6IgfO93C9ocP3+AdngqujF/+zB2rFdUe+y9S6koDyUC7jr9Knds/0Ta72N/0D6PwhgSCpHK8s0Q== dependencies: - "@sentry/core" "7.66.0" - "@sentry/types" "7.66.0" - "@sentry/utils" "7.66.0" + "@sentry/core" "7.69.0" + "@sentry/types" "7.69.0" + "@sentry/utils" "7.69.0" tslib "^2.4.1 || ^1.9.3" -"@sentry/browser@7.66.0": - version "7.66.0" - resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.66.0.tgz#9aa3078f8914d2f8acb4ad9fc7b2011c80e357f5" - integrity sha512-rW037rf8jkhyykG38+HUdwkRCKHJEMM5NkCqPIO5zuuxfLKukKdI2rbvgJ93s3/9UfsTuDFcKFL1u43mCn6sDw== +"@sentry/browser@7.69.0": + version "7.69.0" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.69.0.tgz#65427c90fb71c1775e2c1e38431efb7f4aec1e34" + integrity sha512-5ls+zu2PrMhHCIIhclKQsWX5u6WH0Ez5/GgrCMZTtZ1d70ukGSRUvpZG9qGf5Cw1ezS1LY+1HCc3whf8x8lyPw== dependencies: - "@sentry-internal/tracing" "7.66.0" - "@sentry/core" "7.66.0" - "@sentry/replay" "7.66.0" - "@sentry/types" "7.66.0" - "@sentry/utils" "7.66.0" + "@sentry-internal/tracing" "7.69.0" + "@sentry/core" "7.69.0" + "@sentry/replay" "7.69.0" + "@sentry/types" "7.69.0" + "@sentry/utils" "7.69.0" tslib "^2.4.1 || ^1.9.3" "@sentry/cli@^1.74.6": @@ -2219,88 +2216,88 @@ proxy-from-env "^1.1.0" which "^2.0.2" -"@sentry/core@7.66.0": - version "7.66.0" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.66.0.tgz#8968f2a9e641d33e3750a8e24d1d39953680c4f2" - integrity sha512-WMAEPN86NeCJ1IT48Lqiz4MS5gdDjBwP4M63XP4msZn9aujSf2Qb6My5uT87AJr9zBtgk8MyJsuHr35F0P3q1w== +"@sentry/core@7.69.0": + version "7.69.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.69.0.tgz#ebbe01df573f438f8613107020a4e18eb9adca4d" + integrity sha512-V6jvK2lS8bhqZDMFUtvwe2XvNstFQf5A+2LMKCNBOV/NN6eSAAd6THwEpginabjet9dHsNRmMk7WNKvrUfQhZw== dependencies: - "@sentry/types" "7.66.0" - "@sentry/utils" "7.66.0" + "@sentry/types" "7.69.0" + "@sentry/utils" "7.69.0" tslib "^2.4.1 || ^1.9.3" -"@sentry/integrations@7.66.0": - version "7.66.0" - resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.66.0.tgz#297d13fd2f567b0eba7faaa3727301db586b398a" - integrity sha512-2PNEnihG9e9Rjbz205+A4BYtFcS2XdgwsN6obAU6Yir7VIbskwZXxx87lKZuz6S53sOWPHleC7uvUBjL+Q6vYg== +"@sentry/integrations@7.69.0": + version "7.69.0" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.69.0.tgz#04c0206d9436ec7b79971e3bde5d6e1e9194595f" + integrity sha512-FEFtFqXuCo9+L7bENZxFpEAlIODwHl6FyW/DwLfniy9jOXHU7BhP/oICLrFE5J7rh1gNY7N/8VlaiQr3hCnS/g== dependencies: - "@sentry/types" "7.66.0" - "@sentry/utils" "7.66.0" + "@sentry/types" "7.69.0" + "@sentry/utils" "7.69.0" localforage "^1.8.1" tslib "^2.4.1 || ^1.9.3" "@sentry/nextjs@^7.36.0": - version "7.66.0" - resolved "https://registry.yarnpkg.com/@sentry/nextjs/-/nextjs-7.66.0.tgz#4ee5a8dc99ed930d2957ac7e287918ff3ba31e87" - integrity sha512-CJwl3/rIJRR1isqWjGEE8CYiNUndvRksp7l0/75tfe4JoKTk+XS3tXcXVZyyXh34GU5San1c46ctiyodaGGIeg== + version "7.69.0" + resolved "https://registry.yarnpkg.com/@sentry/nextjs/-/nextjs-7.69.0.tgz#371db2b66de43873e185f6e813567a6e635dfc42" + integrity sha512-PLgVL07pJafRZZ1parTK6g1GKfdZU/afN/6hs5HrdLeovcpSunEwj3guoHHrewFEbDjj021+0JaG16qnNeAPgQ== dependencies: "@rollup/plugin-commonjs" "24.0.0" - "@sentry/core" "7.66.0" - "@sentry/integrations" "7.66.0" - "@sentry/node" "7.66.0" - "@sentry/react" "7.66.0" - "@sentry/types" "7.66.0" - "@sentry/utils" "7.66.0" + "@sentry/core" "7.69.0" + "@sentry/integrations" "7.69.0" + "@sentry/node" "7.69.0" + "@sentry/react" "7.69.0" + "@sentry/types" "7.69.0" + "@sentry/utils" "7.69.0" "@sentry/webpack-plugin" "1.20.0" chalk "3.0.0" rollup "2.78.0" stacktrace-parser "^0.1.10" tslib "^2.4.1 || ^1.9.3" -"@sentry/node@7.66.0": - version "7.66.0" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.66.0.tgz#d3e08471e1ecae28d3cd0ba3c18487ecb2449881" - integrity sha512-PxqIqLr4Sh5xcDfECiBQ4PuZ7v8yTgLhaRkruWrZPYxQrcJFPkwbFkw/IskzVnhT2VwXUmeWEIlRMQKBJ0t83A== +"@sentry/node@7.69.0": + version "7.69.0" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-7.69.0.tgz#938200095a17f41a2445fec168df293db7c24836" + integrity sha512-T0NgPcmDQvEuz5hy6aEhXghTHHTWsiP3IWoeEAakDBHAXmtpT6lYFQZgb5AiEOt9F5KO/G/1yH3YYdpDAnKhPw== dependencies: - "@sentry-internal/tracing" "7.66.0" - "@sentry/core" "7.66.0" - "@sentry/types" "7.66.0" - "@sentry/utils" "7.66.0" + "@sentry-internal/tracing" "7.69.0" + "@sentry/core" "7.69.0" + "@sentry/types" "7.69.0" + "@sentry/utils" "7.69.0" cookie "^0.4.1" https-proxy-agent "^5.0.0" lru_map "^0.3.3" tslib "^2.4.1 || ^1.9.3" -"@sentry/react@7.66.0": - version "7.66.0" - resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.66.0.tgz#5f4d52a47b97e4daad0a2729ec6c88c0b29f0186" - integrity sha512-TC7kCkLoo+Klp9uywdV6tg8DDyn1CrTdndJghO6PoGz6sCa9k+t7K+z4E7MlgDoh3wiZwS2G2zhkT/xVeDRvJA== +"@sentry/react@7.69.0": + version "7.69.0" + resolved "https://registry.yarnpkg.com/@sentry/react/-/react-7.69.0.tgz#b9931ac590d8dad3390a9a03a516f1b1bd75615e" + integrity sha512-J+DciRRVuruf1nMmBOi2VeJkOLGeCb4vTOFmHzWTvRJNByZ0flyo8E/fyROL7+23kBq1YbcVY6IloUlH73hneQ== dependencies: - "@sentry/browser" "7.66.0" - "@sentry/types" "7.66.0" - "@sentry/utils" "7.66.0" + "@sentry/browser" "7.69.0" + "@sentry/types" "7.69.0" + "@sentry/utils" "7.69.0" hoist-non-react-statics "^3.3.2" tslib "^2.4.1 || ^1.9.3" -"@sentry/replay@7.66.0": - version "7.66.0" - resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.66.0.tgz#5469144192824e7688c475ed29586a8cce6606f6" - integrity sha512-5Y2SlVTOFTo3uIycv0mRneBakQtLgWkOnsJaC5LB0Ip0TqVKiMCbQ578vvXp+yvRj4LcS1gNd98xTTNojBoQNg== +"@sentry/replay@7.69.0": + version "7.69.0" + resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.69.0.tgz#d727f96292d2b7c25df022fa53764fd39910fcda" + integrity sha512-oUqWyBPFUgShdVvgJtV65EQH9pVDmoYVQMOu59JI6FHVeL3ald7R5Mvz6GaNLXsirvvhp0yAkcAd2hc5Xi6hDw== dependencies: - "@sentry/core" "7.66.0" - "@sentry/types" "7.66.0" - "@sentry/utils" "7.66.0" + "@sentry/core" "7.69.0" + "@sentry/types" "7.69.0" + "@sentry/utils" "7.69.0" -"@sentry/types@7.66.0": - version "7.66.0" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.66.0.tgz#4ec290cc6a3dd2024a61a0bffb468cedb409f7fb" - integrity sha512-uUMSoSiar6JhuD8p7ON/Ddp4JYvrVd2RpwXJRPH1A4H4Bd4DVt1mKJy1OLG6HdeQv39XyhB1lPZckKJg4tATPw== +"@sentry/types@7.69.0": + version "7.69.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.69.0.tgz#012b8d90d270a473cc2a5cf58a56870542739292" + integrity sha512-zPyCox0mzitzU6SIa1KIbNoJAInYDdUpdiA+PoUmMn2hFMH1llGU/cS7f4w/mAsssTlbtlBi72RMnWUCy578bw== -"@sentry/utils@7.66.0": - version "7.66.0" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.66.0.tgz#2e37c96610f26bc79ac064fca4222ea91fece68d" - integrity sha512-9GYUVgXjK66uXXcLXVMXVzlptqMtq1eJENCuDeezQiEFrNA71KkLDg00wESp+LL+bl3wpVTBApArpbF6UEG5hQ== +"@sentry/utils@7.69.0": + version "7.69.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.69.0.tgz#b7594e4eb2a88b9b25298770b841dd3f81bd2aa4" + integrity sha512-4eBixe5Y+0EGVU95R4NxH3jkkjtkE4/CmSZD4In8SCkWGSauogePtq6hyiLsZuP1QHdpPb9Kt0+zYiBb2LouBA== dependencies: - "@sentry/types" "7.66.0" + "@sentry/types" "7.69.0" tslib "^2.4.1 || ^1.9.3" "@sentry/webpack-plugin@1.20.0": @@ -2338,57 +2335,25 @@ lodash.merge "^4.6.2" postcss-selector-parser "6.0.10" -"@tailwindcss/typography@^0.5.9": - version "0.5.9" - resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.9.tgz#027e4b0674929daaf7c921c900beee80dbad93e8" - integrity sha512-t8Sg3DyynFysV9f4JDOVISGsjazNb48AeIYQwcL+Bsq5uf4RYL75C1giZ43KISjeDGBaTN3Kxh7Xj/vRSMJUUg== - dependencies: - lodash.castarray "^4.4.0" - lodash.isplainobject "^4.0.6" - lodash.merge "^4.6.2" - postcss-selector-parser "6.0.10" - -"@tiptap/core@^2.1.10": +"@tiptap/core@^2.1.10", "@tiptap/core@^2.1.7": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.1.10.tgz#6d8f3c777f1700dcc6c903b1185576754175e366" integrity sha512-yhUKsac6nlqbPQfwQnp+4Jb110EqmzocXKoZacLwzHpM7JVsr2+LXMDu9kahtrvHNJErJljhnQvDHRsrrYeJkQ== -"@tiptap/core@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.1.7.tgz#9823a3712d176849cfd281dd8229ad0719c9eb9e" - integrity sha512-1pqTwlTnwTKQSNQmmTWhs2lwdvd+hFFNFZnrRAfvZhQZA6qPmPmKMNTcYmK38Tn4axKth6mhBamzTJgMZFI7ng== - "@tiptap/extension-blockquote@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.1.10.tgz#dc475bef70dd460fc730a14b3b4cc18f37cd1b2d" integrity sha512-lpBF/a+qgv4Bdf7HYisTkMFdFdGfn2SqspsydvG8UI7N9B/PfnCCrtoMaC3bqTaT6u8ZVxyM3Y3vnq2AxXJvBw== -"@tiptap/extension-blockquote@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.1.7.tgz#fe25ec1dedd1f7e3eb1a851a6ac8738ca4691a17" - integrity sha512-oAsUU1c0DDZKHwK7/uCtYpnTUQt0o3w+SsJSv4S2vlSHidiFl9gCQGozUQ/Alzc7GO1Y95rOscL28DJXgXESQg== - "@tiptap/extension-bold@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.1.10.tgz#fb71c2575087d3d2a9c6d214b3c1587da931cc61" integrity sha512-I43WCwc7pyz5vtKGj24Rjv7HN0EK5S4PlADQPBuhC1qQvfCTFvjrBB6ZmsekUMGmllW0qMOFVLSjtffpckqshA== -"@tiptap/extension-bold@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.1.7.tgz#c5d89284235d75c2e65745b50a5c0681be1cbab6" - integrity sha512-GZV2D91WENkWd1W29vM4kyGWObcxOKQrY8MuCvTdxni1kobEc/LPZzQ1XiQmiNTvXTMcBz5ckLpezdjASV1dNg== - -"@tiptap/extension-bubble-menu@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.1.7.tgz#62616c9ee456c8413ad6c120757978266052a1a0" - integrity sha512-VcwwUgiG17TEDZda1JBbyKCHLIBTu8B2OAzYrnd4ZqeRs5KTVAB279o/TVjsLVgEfC+c7IWwhhaPPMoXn/lJ3g== - dependencies: - tippy.js "^6.3.7" - -"@tiptap/extension-bubble-menu@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.1.8.tgz#26d5f2ebc198553c5339d9ea6d06fcb02b6a938f" - integrity sha512-Na9Maz20jS+3UrHtAGLkfFt3uu+HD9SSK3+3WyNeylkWciJa/qkZKqwhptHrjpin0IHSF2JNche+ZA+hSmnm2Q== +"@tiptap/extension-bubble-menu@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.1.10.tgz#551e93219b98f097331b30865123d36e95c37404" + integrity sha512-XxgJajXkfAj/fChXkIwKBs7/3pd7OxV1uGc6Opx1qW/nSRYx/rr97654Sx/sg6auwIlbpRoqTmyqjbykGX1/yA== dependencies: tippy.js "^6.3.7" @@ -2397,166 +2362,87 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.1.10.tgz#e7d7fb578502da6c6208a4daa3e2fe4249ae6280" integrity sha512-e6aFr29OSOmXsjFZB2zt3p8aeCWOx0C9Ayrpdf4QBUCOUJtt6FQPxxiYc+XZcdrYbLGLznA7QJlulCK9SGv2Fw== -"@tiptap/extension-bullet-list@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.1.7.tgz#3a7356824a931122314a6bd73b5f9d8a8a313791" - integrity sha512-BReix1wkGNH12DSWGnWPKNu4do92Avh98aLkRS1o1V1Y49/+YGMYtfBXB9obq40o0WqKvk4MoM+rhKbfEc44Gg== - "@tiptap/extension-code-block-lowlight@^2.0.4": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.1.7.tgz#713dad4324c9ce25c66768fc4cfdb514ecea21c7" - integrity sha512-GOmpe3bwjlhMC79vFICInkJwaHx5dTiKQCTzdjZ5qRsvKgk/0YTrmWaN+w+JW5BBUaChj8IrgAPy7VZ20l7GKQ== + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.1.10.tgz#22dabaa8c087bd03c160590f7b8bf9b1501752b5" + integrity sha512-HBrsgDX1sMx6FSoKxAhz2On8lwL8S1lqNryMQBTE63PemjOxcyxPNdGWZz+JfQmxyvymQoGhibaW5ImNAK84Zg== "@tiptap/extension-code-block@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.1.10.tgz#a125a12f716728b271a130178c6fc60237ed46f5" integrity sha512-M+s89V9mP3tOoS6p/X2Dzw/Z7Fcg9EF0ZXlsMNifdlpwJlhAIYxI7vjPBmkMAFXTDB5eMZblXyNQaZ7v6V2Yeg== -"@tiptap/extension-code-block@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.1.7.tgz#c087c22c305f3c87645228ad32f32595dde7f2a2" - integrity sha512-uiasfWCIQuk34vGoIENqAJOHf9m3hAkcELnb9T6+uNxA3O7PUZQqBVN/27oEipj7j15pqua50D6C1jql9kFe0g== - "@tiptap/extension-code@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.1.10.tgz#704798f90a32d6166ce96dc65ef4a541f424f895" integrity sha512-1yy/kR0FAeMkDdAt1LW/FH6vlyZLqLZqY6BM+wBCiGrr+XeA5FTXih9iT/4gbTRuIzG0EPqx18nvroG7hUsWBg== -"@tiptap/extension-code@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.1.7.tgz#bad3b1aedc23123a2094f8810801edb0c13acbff" - integrity sha512-g0IA6Q6DFZE0AEOMXAV1mktl/XzIO3s1h/haPIKZ8GNes522qhBr9FYc5OUPQCCbgYjL7soTGzxA/W5Jk3f2AQ== - "@tiptap/extension-color@^2.0.4": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-color/-/extension-color-2.1.7.tgz#7f436aed2f41087d8de6af6a4dd4cb7d964354dd" - integrity sha512-NLspH5taSpZP60rXJjDKu8AP9VDd+dlqz4guxvijtuPEePw87Fzidxx9w6X0uYQfx1O0xdPFq3UodlDz591scA== + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-color/-/extension-color-2.1.10.tgz#5941f40a0418f3bc2bd52f172957be2e4e8ce3d6" + integrity sha512-ZBHi/4+bT3PbC/PtZFF6lc1QbnhUYBLRd4o6AHbtNqBFVcagbRUeiyxJg5xXQa/Ar9eR3NPkG0y5WY/kRxB9Bg== "@tiptap/extension-document@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.1.10.tgz#6d2ab2301c86139d711fa460a311aa2c8bb343f8" integrity sha512-jNlNGQIGg471DvzhADaEoRINa3LNghowrBbKK9d5wGVnbKRykNEPwjCf8zNl+m5NBmCZl3lsdznlwBk5zyh5Bg== -"@tiptap/extension-document@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.1.7.tgz#5e1d56e899fdca8ebfad1b7cb358d5ace664b851" - integrity sha512-tZyoPPmvzti7PEnyulXomEtINd/Oi2S84uOt6gw7DTCnDq5bF5sn1IfN8Icqp9t4jDwyLXy2TL0Zg/sR0a2Ibg== - "@tiptap/extension-dropcursor@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.1.10.tgz#490c9aa82656592c9820c55214381fb9bfea92f2" integrity sha512-GhsWsCq6wLb8HJ32BeAm7ndv4lPyu1F7FFwmnARzEF5q54FV20kWSv2zC+Dv0dTvynXR3quXybdUM92xeNDovw== -"@tiptap/extension-dropcursor@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.1.7.tgz#a3f79b7453579f36f326852b16e421601e881a28" - integrity sha512-hNk2BuLnNSXlGOQphlzdpFKCKo7uHUFjWuBfzF1S9FMAQgcN7eTia+cCClmXABYfVLW4fT14PC1KiuGjxi9MuA== - -"@tiptap/extension-floating-menu@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.1.7.tgz#fe2def740b3136d38101634ae60d2fec5468c57e" - integrity sha512-K0bO7JKHAvgLM5MkhNgoYcD6SB0Z2tNIFhZHs5SCTuhg7dwduMSM3pC6QBrJGUk99DGsKuMPYQn3c2oG7MLbyQ== - dependencies: - tippy.js "^6.3.7" - -"@tiptap/extension-floating-menu@^2.1.8": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.1.8.tgz#49a7f83c3a0769c044d4e83352aae0f86d63f7c5" - integrity sha512-lc8bjHGqWSgXKmoU2HAlBFWzu7wnFKb5Vg0R3PECBrOZ9hXkmNA0mHxrvHglwjLtfe7XOfZf4FLySG/5S+BdeQ== +"@tiptap/extension-floating-menu@^2.1.10": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.1.10.tgz#82914a02e04e019d8b5da5158b32ffb29d4cce80" + integrity sha512-uChrDrY3usnF9wSegqq+YGaqd229p9gmaB5xyOyMERDs972hKj4Ul95rXzBBiMKAWUMw9eM09i7+ijTzz4KDUw== dependencies: tippy.js "^6.3.7" -"@tiptap/extension-gapcursor@^2.1.10": +"@tiptap/extension-gapcursor@^2.1.10", "@tiptap/extension-gapcursor@^2.1.7": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.1.10.tgz#712853ce82642108e50a37014d585ff72af6758d" integrity sha512-WSBT9X7dzg0HyMoMP/Yyxl28QwIJO90YzobI9z5mav86BQv7C5wU0fQSpbpAbsN3s7lxKhPwNrXkwkpnXT4ZCA== -"@tiptap/extension-gapcursor@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.1.7.tgz#5c0303ba37b4c066f3a3c5835fd0b298f0d3e919" - integrity sha512-7eoInzzk1sssoD3RMkwFC86U15Ja4ANve+8wIC+xhN4R3Oe3PY3lFbp1GQxCmaJj8b3rtjNKIQZ2zO0PH58afA== - "@tiptap/extension-hard-break@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.1.10.tgz#e885e83d936b45891bf4dc40c713d042f84eb8c4" integrity sha512-sYrzpPoV5jQri+duGb50nDTs+hOBQDxXTKlJuZNFfZMwgx6epwxb8xICcGAUJFShuuW8UAWCNcB4jG9tMqgvyw== -"@tiptap/extension-hard-break@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.1.7.tgz#1cd783adfe2788d41614f8851b8d7a52ec027cce" - integrity sha512-6gFXXlCGAdXjy27BW29q4yfCQPAEFd18k7zRTnbd4aE/zIWUtLqdiTfI3kotUMab9Tt9/z1BRmCbEUxRsf1Nww== - "@tiptap/extension-heading@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.1.10.tgz#1b32726551466c29987861181966e5675417b28c" integrity sha512-1OgmrRPMcY52WI7I4799xd4eIsEX/bI813B8mZvNYXLzZI75pLW1hmz1mUvBYyMwlcek74zVTGYgPy11o+2JEg== -"@tiptap/extension-heading@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.1.7.tgz#26d16227eab95b1f381e977f7aa1685f493c6fb5" - integrity sha512-jMeTqtq3kbMFtMvUb3SeIt4FFM3W+b6TAw5H4Qd6z3gYsAU3GahRK67MtbJfPmznUkZfimrqW9VCaBezScfrsQ== - -"@tiptap/extension-highlight@^2.0.4": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.1.7.tgz#0f9434eedfdcb95a22ca5b6f601d13f4343a7e5c" - integrity sha512-3EXrnf1BQSdOe/iqzcTIr5Tf0NOhPQ+y1B9nMi/40v3MD8WzRBLaqj0lvpwO7xMAdgxm6IiL/XFYU41n9yFl/Q== - -"@tiptap/extension-highlight@^2.1.7": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.1.8.tgz#b2d2d995344e06dd36cd8a395a72113b87981bd7" - integrity sha512-OCXtFWCbwsgOHq7IP4Qr02EfjwYeRRcuL1ipv0LojGtMcvnkw7OLhQZ8oocrqi4/6QCOtPLSGlcqrQ6pmN7jww== +"@tiptap/extension-highlight@^2.0.4", "@tiptap/extension-highlight@^2.1.7": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.1.10.tgz#8d94db01a2324e0ce380e6e7515fa0bc6004d9b9" + integrity sha512-HPD9T0MPEfrD40aSjcj23OcAYDnpsRLXxwQAYK1jw6Fvk7OtJZn8iaoAb4GcFfcKs3vgkpA9DC6DXlnvN0txYA== "@tiptap/extension-history@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.1.10.tgz#efa60d657a76818361a3af14769660672d4bc227" integrity sha512-tApuN8MIJMzc0dxvkYJPt3t5cea9NuZBGNiuVedJwMMUF6hbFpMZAt20GW2qwjBaZ76rQwbLp1s3KnImFsPe5A== -"@tiptap/extension-history@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.1.7.tgz#baa566875ef1278c5dd8821970362d85348b266c" - integrity sha512-8SIEKSImrIkqJThym1bPD13sC4/76UrG+piQ30xKQU4B7zUFCbutvrwYuQHSRvaEt8BPdTv2LWIK+wBkIgbWVA== - -"@tiptap/extension-horizontal-rule@^2.0.4", "@tiptap/extension-horizontal-rule@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.1.7.tgz#7c21bc4917e4ced9382e81626e0f0068b224bfbb" - integrity sha512-hJupsDxDVmjmKI/Ewl/gtiyUx52Y3wRUhT8dCXNOA5eldmPXN23E2Fa2BC8XB47dyc5pubyNcLuqaLeaZ5hedw== - -"@tiptap/extension-horizontal-rule@^2.1.10": +"@tiptap/extension-horizontal-rule@^2.0.4", "@tiptap/extension-horizontal-rule@^2.1.10", "@tiptap/extension-horizontal-rule@^2.1.7": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.1.10.tgz#cfdb67530be100054fc8511942d4ec3534acf828" integrity sha512-91lGpK2d6WMPhrMDPBURS8z8pEg1CUBYy7GmBenKvvgh+JzVhG+U6MtykfWNfm2R4iRXOl1xLbyUOCiOSUXodQ== -"@tiptap/extension-image@^2.0.4": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.1.7.tgz#597129fb072f6b0014c980892c367a283077f564" - integrity sha512-aWa/NPMc1U9Z6xuV0gk1O1nk4H7BAwQMwqXWdvUQCJhmW5+LJPdEiKvt3P6j+ClIN7sdyokZCgr6eGr817qTLA== - -"@tiptap/extension-image@^2.1.7": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.1.8.tgz#99d78ad1d8c6f513f945beae7de352759f30189f" - integrity sha512-o+vUIYLvYcJHftIMoIukzZZ+fTTfC/gXXvQIYz51p3f1qeYXszD11FbtkaJCgXYj8BcGCO7QuzcCdQg+wyROZw== +"@tiptap/extension-image@^2.0.4", "@tiptap/extension-image@^2.1.7": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.1.10.tgz#6c597ad02285f1f3508fd4aa21e30213657cbd7c" + integrity sha512-d7+d4J2TJ99+phFbVTpsFhi208jAgcrfbdwUDkkwjdF+PQhax5pounSt/8eZPWdyCXj+EWYjCjx0znwsD6+SCA== "@tiptap/extension-italic@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.1.10.tgz#7183119c8c61beb2ac635ca3c2066624530b4a56" integrity sha512-ebw5m+rWx6K5UoBVXSkz3fpvDJh/wScfYmwl6pkbjc2jNbZiln2LSiLHYc2eIYJ2aTsVxcw/n0Azfk5Lb19InA== -"@tiptap/extension-italic@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.1.7.tgz#d077683597d4282ae272c48b313d768d71985b67" - integrity sha512-7e37f+OFqisdY19nWIthbSNHMJy4+4dec06rUICPrkiuFaADj5HjUQr0dyWpL/LkZh92Wf/rWgp4V/lEwon3jA== - -"@tiptap/extension-link@^2.0.4": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.1.7.tgz#2705c212d105ccf411d505e334ece4a723971ee4" - integrity sha512-NDfoMCkThng1B530pMg5y69+eWoghZXK2uCntrJH7Rs8jNeGMyt9wGIOd7N8ZYz0oJ2ZYKzZjS0RANdBDS17DA== - dependencies: - linkifyjs "^4.1.0" - -"@tiptap/extension-link@^2.1.7": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.1.8.tgz#644229c309ef9a91db329126df23cba083ec3c61" - integrity sha512-f3yPNbbo3rNuusEX+Xh/oKUWkq/P1yyVip6ZmtUJVrrG4PFeq/w+f1vEVnlC+uZk3qoC4o8J1DTAOrlrZehx/g== +"@tiptap/extension-link@^2.0.4", "@tiptap/extension-link@^2.1.7": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.1.10.tgz#c2a33fdf33dd2d97f29381ae2163c10318dc371f" + integrity sha512-dXxPTWzJzpbDRAewM4P8jN/n9h8uUH83lOLwweuODYCqHRdjQL/uGkQworFFrgqmRHs+9JjHZ4DETILZVawJ+Q== dependencies: linkifyjs "^4.1.0" @@ -2565,125 +2451,80 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.1.10.tgz#0615e4fb68161e6457e6041e195f454bfd537d44" integrity sha512-rRRyB14vOcSjTMAh8Y+50TRC/jO469CelGwFjOLrK1ZSEag5wmLDaqpWOOb52BFYnvCHuIm1HqZtdL5bTI/J1w== -"@tiptap/extension-list-item@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.1.7.tgz#dc24045e445d0f91baec9b113f711dc90c6682ac" - integrity sha512-hd/E4qQopBXWa6kdFY19qFVgqj4fzdPgAnzdXJ2XW7bC6O2CusmHphRRZ5FBsuspYTN/6/fv0i0jK9rSGlsEyA== - "@tiptap/extension-ordered-list@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.1.10.tgz#ef5d5ba68baf86e9b66c1b2c1cec458aa111ad44" integrity sha512-jouo3RHUMxU4dPzZcfZdUzmsLVp1KHrLIAD2YAxBuqArACrBNfJpIhtkTKuGLlaFhKqGr+EmNdNQnK8JOBhLtQ== -"@tiptap/extension-ordered-list@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.1.7.tgz#72d9ddc432ecf0fd19c8acd3c6b44f5358d8e0d0" - integrity sha512-3XIXqbZmYkNzF+8PQ2jcCOCj0lpC3y9HGM/+joPIunhiUiktrIgpbUDv2E1Gq5lJHYqthIeujniI2dB85tkwJQ== - "@tiptap/extension-paragraph@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.1.10.tgz#ee1238d2d6e9460b2a929b05a5fd43cfb58a6017" integrity sha512-kzuHbrxcxpWkha5P+JFzCKT54pNqb4IBKMU5qT9YGhZSdNTtU63ncdCHM+Ad1ukLuvXAv95zh1IQC5j+Z1Qk4A== -"@tiptap/extension-paragraph@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.1.7.tgz#76408706f0037a510a384b86780bd50c6e8ffeea" - integrity sha512-cLqX27hNrXrwZCKrIW8OC3rW2+MT8hhS37+cdqOxZo5hUqQ9EF/puwS0w8uUZ7B3awX9Jm1QZDMjjERLkcmobw== - "@tiptap/extension-placeholder@2.0.3": version "2.0.3" resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.0.3.tgz#69575353f09fc7524c9cdbfbf16c04f73c29d154" integrity sha512-Z42jo0termRAf0S0L8oxrts94IWX5waU4isS2CUw8xCUigYyCFslkhQXkWATO1qRbjNFLKN2C9qvCgGf4UeBrw== "@tiptap/extension-placeholder@^2.0.4": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.1.7.tgz#8477cf5116c89f0f75e8e2e3b8528e146a7f0f24" - integrity sha512-IiBoItYYNS7hb/zmPitw3w6Cylmp9qX+zW+QKe3lDkCNPeKxyQr86AnVLcQYOuXg62cLV9dp+4azZzHoz9SOcg== + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.1.10.tgz#bdb03dac209444276f25d76f3929bb2bc1facfe8" + integrity sha512-lwtNmMZpxvQBGP72/zrdPFOmn/3QNZAKpkrfrK95Ri4TU6LPeDDwPsP81s9mkAFZPuDQ1i8SPakl+RivWa6qtA== "@tiptap/extension-strike@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.1.10.tgz#ec311395d16af15345b63d2dac2d459b9ad5fa9e" integrity sha512-KW63lZLPFIir5AIeh2I7UK6Tx1O3jetD7JIPUzEqp1I1BfJlHGHVQxV8VXAmJl0hTOzjQBsHW42PmBxSC97NUg== -"@tiptap/extension-strike@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.1.7.tgz#b7b7f49254f1de22416b1415ca88a2a20edd0627" - integrity sha512-ONLXYnuZGM2EoGcxkyvJSDMBeAp7K6l83UXkK9TSj+VpEEDdeV7m8mJs8/vACJjJxD5HMN61+EPgU7VTEukQCA== - "@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== + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-table-cell/-/extension-table-cell-2.1.10.tgz#e594b55622435c43a95edf6f2adfaca402f5cbed" + integrity sha512-NQOTKjPOTJrkI7VaR9wFF3UKB9N2THD8zJZJDcECKQxLR740udF6/6jWm1uwkTwdkBekVKHBMQvKKK9W1bOBiw== "@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== + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-table-header/-/extension-table-header-2.1.10.tgz#6250676a26946e5b7186198a06990ea70f578a87" + integrity sha512-NSC0Y10kXDvPGiJckJY/QU8VA7HHU0tI20Dj7/r1oD9itBWSnWP0zAOXzHVlQt9GpThhFNo2nu3fAaVQNfKoTg== "@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== + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-table-row/-/extension-table-row-2.1.10.tgz#e7a1ca8342b623a400848b437c82d57680e551e3" + integrity sha512-yMOnAaXE7vK7MwULuVUO8v6AYZu6wxTfHAWQe/FqPeMf9tG0HL6+gyt1audremw0xBFMGPx6v4t8vlqPXW9p2g== "@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.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-2.1.7.tgz#384a55308f3524f36388560486a2508a4b3c5413" - integrity sha512-4wFLZmhYqr87SEI/Qgk3FiH+qfp6IOmuYVhpL5zGLa6p+ytUdmPH3+zOaD1rthn5JiRU9KwYWFvTo2f+/O0NAg== - -"@tiptap/extension-task-item@^2.1.7": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-2.1.8.tgz#2036360be6702ab753cbc77b60ab24fb33ff20a6" - integrity sha512-PoY2PDiYEQC44qDQLubzDuhZ3f6OL7sui89960M1HUQR2URnPvToOBaa5veNY8VyACdAolm+LwTpseBKKkcpmw== - -"@tiptap/extension-task-list@^2.0.4": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-task-list/-/extension-task-list-2.1.7.tgz#abaad3a7b964e58dac6b96b08000a50a06a071b4" - integrity sha512-eerV8pbGuYoFji6arWk+LBsIfURXPWNSLi1ZCuPfXP6N8sAV3fNT+VDm6RlGQwadQNae7rnibNClk67+55h9Zg== - -"@tiptap/extension-task-list@^2.1.7": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-task-list/-/extension-task-list-2.1.8.tgz#993c415d85d414039baf7379df7c3b19b1d342d9" - integrity sha512-PmEPJHTOgy0AveE6YoxY6w09+bh5OqkrMI/sluY88291cnSPPEf9sFWmBHOrONNj54Ti6ua37arudUY5mqxOCA== - -"@tiptap/extension-text-style@^2.0.4": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-text-style/-/extension-text-style-2.1.7.tgz#57f5dc5b223a855e782f24e09dc7fc53d9bd4b00" - integrity sha512-0QhEMDiDqMpyBGRt6o4GvbN9cUibZe4LT9e0ujarT6ElSe2fbtwGPnXSXApUtgHDDwHw95M5ZVxX/H5cjyjw1g== - -"@tiptap/extension-text-style@^2.1.7": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-text-style/-/extension-text-style-2.1.8.tgz#42e9fa179f76d4e88f73f2c66aee3b06162e659b" - integrity sha512-xnx/Pq5ttt2/gOQPmqVQIBz/jo3MErtYdYk22fUaOyu1xT36X4BDJYsrLyWhcs3aWR/tv1/XylbNOFvhrDOHoQ== + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-table/-/extension-table-2.1.10.tgz#5654426366b547631c647ffc5dacf040e65307e1" + integrity sha512-fsf0c6qA+R6NzbFx+tm1l5POZsgadHjREsedvq5q1i8rCq1Gt1AK+lR7WQsaXlSeIRsWtg4RT0eUjAYNCmKkug== + +"@tiptap/extension-task-item@^2.0.4", "@tiptap/extension-task-item@^2.1.7": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-2.1.10.tgz#8eb0d3e8b1234fa44205dd91619f3f1937ca3254" + integrity sha512-jiH37e8c41T/UKWXzznOg325huAkAiFtjNkvfQfS23a7UDfIM90IJ+VjvFt/5EEgJ2mozBweQan4yIzlC6uWaQ== + +"@tiptap/extension-task-list@^2.0.4", "@tiptap/extension-task-list@^2.1.7": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-task-list/-/extension-task-list-2.1.10.tgz#faf2d520c5f5b7b5084a0804b8e65f69fea361be" + integrity sha512-1nLI81lQ/HYrcxVRSv3EyG8kcWygtaQcOZ9p6PeQjwN+z5D5PoQVHK4+8zOO1Lpz4BDR3mc4nolA7q/Li0ilOw== + +"@tiptap/extension-text-style@^2.0.4", "@tiptap/extension-text-style@^2.1.7": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-text-style/-/extension-text-style-2.1.10.tgz#7d12e4d42da61ea5b4a675f31fea16482326c37b" + integrity sha512-ptgCZQfpy/8aQHHzktVMMAy30uMvC0XkPbJPmD0nYJqt/m+3QFHHWiGyaKXmYhqyg/TjPvTTMHjcvTvk5k4Sug== "@tiptap/extension-text@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.1.10.tgz#db297fb5d2ee50ef7a14650539e3d335f772f755" integrity sha512-ubU/WQwNB0MVKyMAHr8ka3Nu3jCR03HARGKUwNRzppZYtRXWyXHNlAaJdplNb1NMGb8hd0ElBJmwFlVqmh8haQ== -"@tiptap/extension-text@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.1.7.tgz#071053ab0a8804a3bce36d1488a603b7446dff4e" - integrity sha512-3xaMMMNydLgoS+o+yOvaZF04ui9spJwJZl8VyYgcJKVGGLGRlWHrireXN5/OqXG2jLb/jWqXVx5idppQjX+PMA== - -"@tiptap/extension-underline@^2.0.4": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-2.1.7.tgz#ab815645770f7d2013ac69327975837b4937c8df" - integrity sha512-mL95afyEJvg+C2yrTVn7QltfyE9ja1+94+OUkRBbB8PN3N6HvfSL4K/QSqecOLQ38bSQm/6ZGPkBLDkDGhGPdw== - -"@tiptap/extension-underline@^2.1.7": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-2.1.8.tgz#a2f0904805f57e118c2f0b165929abe41b5c1fbf" - integrity sha512-vsmdyR8z40xNPZzTSNGLcCMaIf8Tgm9OzsZb1qWILe+PYuv/mIM1LogBbfouEzVpG5sPoxwFTDgxnC+M3Ohgzg== +"@tiptap/extension-underline@^2.0.4", "@tiptap/extension-underline@^2.1.7": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-2.1.10.tgz#d7a3ac39c2363da94651a960abe3a16bb24de398" + integrity sha512-f+rJKviGNqORGv4/1pTLZuVTb9VsKMZMLucL8423M6s8TdrH//sBB8QeU92JSnO9PjAGwxWjS1f23/KtufxP8g== -"@tiptap/pm@^2.0.4": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.1.7.tgz#91e1b87d4ddbddca3cfe46e3c052b0072e4e1d97" - integrity sha512-RBVb/k9OjmClwdVl7fpekFgUsLAm1U+5I4w1qA2tj7L/hSPOuPzaEHwCqDYe0b2PR5dd8h0nylS9qXuXVlfwfQ== +"@tiptap/pm@^2.0.4", "@tiptap/pm@^2.1.7": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.1.10.tgz#84d5ae574568dca00ee62698559523d77e980620" + integrity sha512-Y+AqizKnjQpx4pSaA6m/cCD5QHQRPtALhO4ZO4YFZV1idYmsJA3/S5lgJI3ZL5eAHKHcGk6Vv3/8Y+eej5YIPw== dependencies: prosemirror-changeset "^2.2.0" prosemirror-collab "^1.3.0" @@ -2704,72 +2545,15 @@ prosemirror-transform "^1.7.0" prosemirror-view "^1.28.2" -"@tiptap/pm@^2.1.7": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.1.8.tgz#9108af0365fd653d64d620d45016e7079961bebc" - integrity sha512-H3NGAu5xdH1PpXa6OQlvecaWJIZR/9tVkc1mdpLanvG7mW85DuY+5fC36Xnv9SPMVcO3zWXS6Ii4os6HbdP6bQ== +"@tiptap/react@^2.0.4", "@tiptap/react@^2.1.7": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-2.1.10.tgz#51cd96462e61f6fffa0ca4eb359d8d7d15ebf422" + integrity sha512-kzCWzbV2dnD5NmHjN8GiS+k0GOmoEhKnMuMzuuU6FjtOALhJzPTrIXITzWDpU3jL+r/4eeXYhAt64Wp7PVwscg== dependencies: - prosemirror-changeset "^2.2.0" - prosemirror-collab "^1.3.0" - prosemirror-commands "^1.3.1" - prosemirror-dropcursor "^1.5.0" - prosemirror-gapcursor "^1.3.1" - prosemirror-history "^1.3.0" - prosemirror-inputrules "^1.2.0" - prosemirror-keymap "^1.2.0" - prosemirror-markdown "^1.10.1" - prosemirror-menu "^1.2.1" - prosemirror-model "^1.18.1" - prosemirror-schema-basic "^1.2.0" - prosemirror-schema-list "^1.2.2" - prosemirror-state "^1.4.1" - prosemirror-tables "^1.3.0" - prosemirror-trailing-node "^2.0.2" - prosemirror-transform "^1.7.0" - prosemirror-view "^1.28.2" + "@tiptap/extension-bubble-menu" "^2.1.10" + "@tiptap/extension-floating-menu" "^2.1.10" -"@tiptap/react@^2.0.4": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-2.1.7.tgz#0c5a5407bcb398ff75234dd9c7a3f8878d943088" - integrity sha512-jCs5z/rXZ7mEOTPcJ+r/OSTtLOGBahS7D3xDu3pRX4P0wtWHlprsdptxxlWjkBHLav01XXJ+OtGZTfhWBio1QQ== - dependencies: - "@tiptap/extension-bubble-menu" "^2.1.7" - "@tiptap/extension-floating-menu" "^2.1.7" - -"@tiptap/react@^2.1.7": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-2.1.8.tgz#50a834a9b76b36eebb33e71dcb765aa9cb80f276" - integrity sha512-yTjlin4tOfYNwBdpX4+2CmNxybq2Ms50rX0RIRLABbnCTqhBIKko/eBLFq7DCot/Dwdw6c5Y098/fayKywfJWg== - dependencies: - "@tiptap/extension-bubble-menu" "^2.1.8" - "@tiptap/extension-floating-menu" "^2.1.8" - -"@tiptap/starter-kit@^2.0.4": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.1.7.tgz#a33a7928b7051ac9cd89d1798745f9855b7b72d9" - integrity sha512-z2cmJRSC7ImaTGWrHv+xws9y1wIG0OCPosBYpmpwlEfA3JG3axWFmVRJlWnsQV4eSMi3QY3vaPgBAnrR4IxRhQ== - dependencies: - "@tiptap/core" "^2.1.7" - "@tiptap/extension-blockquote" "^2.1.7" - "@tiptap/extension-bold" "^2.1.7" - "@tiptap/extension-bullet-list" "^2.1.7" - "@tiptap/extension-code" "^2.1.7" - "@tiptap/extension-code-block" "^2.1.7" - "@tiptap/extension-document" "^2.1.7" - "@tiptap/extension-dropcursor" "^2.1.7" - "@tiptap/extension-gapcursor" "^2.1.7" - "@tiptap/extension-hard-break" "^2.1.7" - "@tiptap/extension-heading" "^2.1.7" - "@tiptap/extension-history" "^2.1.7" - "@tiptap/extension-horizontal-rule" "^2.1.7" - "@tiptap/extension-italic" "^2.1.7" - "@tiptap/extension-list-item" "^2.1.7" - "@tiptap/extension-ordered-list" "^2.1.7" - "@tiptap/extension-paragraph" "^2.1.7" - "@tiptap/extension-strike" "^2.1.7" - "@tiptap/extension-text" "^2.1.7" - -"@tiptap/starter-kit@^2.1.10": +"@tiptap/starter-kit@^2.0.4", "@tiptap/starter-kit@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.1.10.tgz#5f19c199c79d90ef5e3b8990ca3aa76ce625d68c" integrity sha512-h5mH1qv7SDFXWZPbOWC8zpGZ62EnDizRNtM45Gani0HYWJXcbPFpgN1qJmESP/jP+v+0hxtnVEkgfpiy3LRm6A== @@ -2794,15 +2578,10 @@ "@tiptap/extension-strike" "^2.1.10" "@tiptap/extension-text" "^2.1.10" -"@tiptap/suggestion@^2.0.4": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.1.7.tgz#ac88deef2ade8d836ca9084c276cc9d64c6e604a" - integrity sha512-FKlXFMWf9rCnNJQsUfeX6WpS2VUs2O98ENkyhfV8ehCB7X5+57mkkxJxl/88SMbjZL+FbWPBKLaiOvsXfIUoww== - -"@tiptap/suggestion@^2.1.7": - version "2.1.8" - resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.1.8.tgz#ffd61c13aa11c4b51e50a9c83f0813f71ab0881b" - integrity sha512-3QypKFCeZSRrjgSz0n0JE5SimisolaxDZn45GGtkXuJWmKGCmsJw9UsXeH3S9ZuP3pvPImL0P9uAHlhRReRw1w== +"@tiptap/suggestion@^2.0.4", "@tiptap/suggestion@^2.1.7": + version "2.1.10" + resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.1.10.tgz#fe6dd160ea93f8135c0831ae4accc7a708bac019" + integrity sha512-k9WTTWT81UkHaxZksjp+wE31E85QL0jyLd0ZEKAs+btW148Pon1KwBeLnODNHILcdQaRPxRvb28a47cRHEKTiw== "@types/debug@^4.0.0": version "4.1.8" @@ -2835,29 +2614,29 @@ "@types/node" "*" "@types/hast@^2.0.0": - version "2.3.5" - resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.5.tgz#08caac88b44d0fdd04dc17a19142355f43bd8a7a" - integrity sha512-SvQi0L/lNpThgPoleH53cdjB3y9zpLlVjRbqB3rH8hx1jiRSBGAhyjV3H+URFjNVRqt2EdYNrbZE5IsGlNfpRg== + version "2.3.6" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.6.tgz#bb8b05602112a26d22868acb70c4b20984ec7086" + integrity sha512-47rJE80oqPmFdVDCD7IheXBrVdwuBgsYwoczFvKmwfo2Mzsnt+V9OONsYauFmICb6lQPpCuXYJWejBNs4pDJRg== dependencies: "@types/unist" "^2" "@types/hoist-non-react-statics@^3.3.0": - version "3.3.1" - resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" - integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== + version "3.3.2" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#dc1e9ded53375d37603c479cc12c693b0878aa2a" + integrity sha512-YIQtIg4PKr7ZyqNPZObpxfHsHEmuB8dXCxd6qVcGuQVDK2bpsF7bYNnBJ4Nn7giuACZg+WewExgrtAJ3XnA4Xw== dependencies: "@types/react" "*" hoist-non-react-statics "^3.3.0" "@types/js-cookie@^3.0.2", "@types/js-cookie@^3.0.3": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-3.0.3.tgz#d6bfbbdd0c187354ca555213d1962f6d0691ff4e" - integrity sha512-Xe7IImK09HP1sv2M/aI+48a20VX+TdRJucfq4vfRVy6nWN8PYPOEnlMRSgxJAgYQIXJVL8dZ4/ilAM7dWNaOww== + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-3.0.4.tgz#23475b6d3b03acc84192e7c24da88eb38c1039ef" + integrity sha512-vMMnFF+H5KYqdd/myCzq6wLDlPpteJK+jGFgBus3Da7lw+YsDmx2C8feGTzY2M3Fo823yON+HC2CL240j4OV+w== "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": - version "7.0.12" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.12.tgz#d70faba7039d5fca54c83c7dbab41051d2b6f6cb" - integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== + version "7.0.13" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.13.tgz#02c24f4363176d2d18fc8b70b9f3c54aba178a85" + integrity sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ== "@types/json5@^0.0.29": version "0.0.29" @@ -2877,9 +2656,9 @@ "@types/lodash" "*" "@types/lodash@*": - version "4.14.197" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.197.tgz#e95c5ddcc814ec3e84c891910a01e0c8a378c54b" - integrity sha512-BMVOiWs0uNxHVlHBgzTIqJYmj+PgCo4euloGF+5m4okL3rEYzM2EEv78mw8zWSMM57dM7kVIgJ2QDvwHSoCI5g== + version "4.14.198" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.198.tgz#4d27465257011aedc741a809f1269941fa2c5d4c" + integrity sha512-trNJ/vtMZYMLhfN45uLq4ShQSw0/S7xCTLLVM+WM1rmFpba/VS42jVUgaO3w/NOLiWR/09lnYk0yMaA/atdIsg== "@types/markdown-it@^12.2.3": version "12.2.3" @@ -2912,9 +2691,9 @@ integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== "@types/node@*": - version "20.5.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.5.8.tgz#fb171fd22d37ca6e2ea97fde88e6a13ee14bc327" - integrity sha512-eajsR9aeljqNhK028VG0Wuw+OaY5LLxYmxeoXynIoE6jannr9/Ucd1LL0hSSoafk5LTYG+FfqsyGt81Q6Zkybw== + version "20.6.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.6.3.tgz#5b763b321cd3b80f6b8dde7a37e1a77ff9358dd9" + integrity sha512-HksnYH4Ljr4VQgEy2lTStbCKv/P590tmPe5HqOnv9Gprffgv5WXAY+Y5Gqniu0GGqeTCUdBnzC3QSrzPkBkAMA== "@types/node@18.0.6": version "18.0.6" @@ -2937,9 +2716,9 @@ integrity sha512-1cYJrqq9GezNFPsWTZpFut/d4CjpZqA0vhqDUPFWYKF1oIyBz5qnoYMzR+0C/T96t3ebLAC1SSnwrVOm5/j74A== "@types/object.omit@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/object.omit/-/object.omit-3.0.0.tgz#0d31e1208eac8fe2ad5c9499a1016a8273bbfafc" - integrity sha512-I27IoPpH250TUzc9FzXd0P1BV/BMJuzqD3jOz98ehf9dQqGkxlq+hO1bIqZGWqCg5bVOy0g4AUVJtnxe0klDmw== + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/object.omit/-/object.omit-3.0.1.tgz#1b9de058cf94344b9284308a41b17e3a356ed18e" + integrity sha512-24XD34UeRWw505TsMNBrQ4bES2s8IxiFC59mmNUFhTz9IX2hAtA7gQ8wVww1i17QmhBYILg5iqYP2y7aqA3pwQ== "@types/object.pick@^1.3.2": version "1.3.2" @@ -2952,9 +2731,9 @@ integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== "@types/prop-types@*", "@types/prop-types@^15.0.0", "@types/prop-types@^15.7.5": - version "15.7.5" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.5.tgz#5f19d2b85a98e9558036f6a3cacc8819420f05cf" - integrity sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w== + version "15.7.6" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.6.tgz#bbf819813d6be21011b8f5801058498bec555572" + integrity sha512-RK/kBbYOQQHLYj9Z95eh7S6t7gq4Ojt/NT8HTk8bWVhA5DaF+5SMnxHKkP4gPNN3wAZkKP+VjAf0ebtYzf+fxg== "@types/react-beautiful-dnd@^13.1.2": version "13.1.4" @@ -3002,13 +2781,6 @@ dependencies: "@types/react" "*" -"@types/react-is@^18.2.1": - version "18.2.1" - resolved "https://registry.yarnpkg.com/@types/react-is/-/react-is-18.2.1.tgz#61d01c2a6fc089a53520c0b66996d458fdc46863" - integrity sha512-wyUkmaaSZEzFZivD8F2ftSyAfk6L+DfFliVj/mYdOXbVjRcS87fQJLTnhk6dRZPuJjI+9g6RZJO4PNCngUrmyw== - dependencies: - "@types/react" "*" - "@types/react-redux@^7.1.20": version "7.1.26" resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.26.tgz#84149f5614e40274bb70fcbe8f7cae6267d548b1" @@ -3027,9 +2799,9 @@ "@types/react" "*" "@types/react@*", "@types/react@^18.0.17": - version "18.2.21" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.21.tgz#774c37fd01b522d0b91aed04811b58e4e0514ed9" - integrity sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA== + version "18.2.22" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.22.tgz#abe778a1c95a07fa70df40a52d7300a40b949ccb" + integrity sha512-60fLTOLqzarLED2O3UQImc/lsNRgG0jE/a1mPW9KjMemY0LMITWEsbS4VvZ4p6rorEHd5YKxxmMKSDK505GHpA== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" @@ -3073,9 +2845,9 @@ integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ== "@types/semver@^7.3.12": - version "7.5.1" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.1.tgz#0480eeb7221eb9bc398ad7432c9d7e14b1a5a367" - integrity sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg== + version "7.5.2" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.2.tgz#31f6eec1ed7ec23f4f05608d3a2d381df041f564" + integrity sha512-7aqorHYgdNO4DM36stTiGO3DvKoex9TQRwsJU6vMaFGyqpBA1MNZkz+PG3gaNUPpTAOYhT1WR7M1JyA3fbS9Cw== "@types/throttle-debounce@^2.1.0": version "2.1.0" @@ -3083,9 +2855,9 @@ integrity sha512-5eQEtSCoESnh2FsiLTxE121IiE60hnMqcb435fShf4bpLRjEu1Eoekht23y6zXS9Ts3l+Szu3TARnTsA0GkOkQ== "@types/trusted-types@^2.0.2": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.3.tgz#a136f83b0758698df454e328759dbd3d44555311" - integrity sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g== + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.4.tgz#2b38784cd16957d3782e8e2b31c03bc1d13b4d65" + integrity sha512-IDaobHimLQhjwsQ/NMwRVfa/yL7L/wriQPMhw1ZJall0KX6E1oxk29XMDeilW5qTIg5aoiqf5Udy8U/51aNoQQ== "@types/unist@^2", "@types/unist@^2.0.0": version "2.0.8" @@ -3098,9 +2870,9 @@ integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== "@types/uuid@^9.0.1": - version "9.0.3" - resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.3.tgz#6cdd939b4316b4f81625de9f06028d848c4a1533" - integrity sha512-taHQQH/3ZyI3zP8M/puluDEIEvtQHVYcC6y3N8ijFtAd28+Ey/G4sg1u2gB01S8MwybLOKAp9/yCMu/uR5l3Ug== + version "9.0.4" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.4.tgz#e884a59338da907bda8d2ed03e01c5c49d036f1c" + integrity sha512-zAuJWQflfx6dYJM62vna+Sn5aeSWhh3OB+wfUEACNcqUSc0AGc5JKl+ycL1vrH7frGTXhJchYjE1Hak8L819dA== "@typescript-eslint/eslint-plugin@^5.48.2", "@typescript-eslint/eslint-plugin@^5.51.0": version "5.62.0" @@ -3310,14 +3082,14 @@ array-buffer-byte-length@^1.0.0: is-array-buffer "^3.0.1" array-includes@^3.1.5, array-includes@^3.1.6: - version "3.1.6" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f" - integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== + version "3.1.7" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.7.tgz#8cd2e01b26f7a3086cbc87271593fe921c62abda" + integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== dependencies: call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - get-intrinsic "^1.1.3" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" is-string "^1.0.7" array-union@^1.0.1: @@ -3349,44 +3121,45 @@ array.prototype.findlastindex@^1.2.2: get-intrinsic "^1.2.1" array.prototype.flat@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz#ffc6576a7ca3efc2f46a143b9d1dda9b4b3cf5e2" - integrity sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA== + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" + integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== dependencies: call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + define-properties "^1.2.0" + es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" array.prototype.flatmap@^1.3.0, array.prototype.flatmap@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.1.tgz#1aae7903c2100433cb8261cd4ed310aab5c4a183" - integrity sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ== + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" + integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== dependencies: call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + define-properties "^1.2.0" + es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" array.prototype.tosorted@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.1.tgz#ccf44738aa2b5ac56578ffda97c03fd3e23dd532" - integrity sha512-pZYPXPRl2PqWcsUs6LOMn+1f1532nEoPTYowBtqLwAW+W8vSVhkIGnmOX1t/UQjD6YGI0vcD2B1U7ZFGQH9jnQ== + version "1.1.2" + resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.2.tgz#620eff7442503d66c799d95503f82b475745cefd" + integrity sha512-HuQCHOlk1Weat5jzStICBCd83NxiIMwqDg/dHEsoefabn/hJRj5pVdWcPUSpRrwhwxZOsQassMpgN/xRYFBMIg== dependencies: call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + define-properties "^1.2.0" + es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" - get-intrinsic "^1.1.3" + get-intrinsic "^1.2.1" -arraybuffer.prototype.slice@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.1.tgz#9b5ea3868a6eebc30273da577eb888381c0044bb" - integrity sha512-09x0ZWFEjj4WD8PDbykUwo3t9arLn8NIzmmYEJFpYekOAQjpkGSyrQhNoRTcwwcFRu+ycWF78QZ63oWTqSjBcw== +arraybuffer.prototype.slice@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz#98bd561953e3e74bb34938e77647179dfe6e9f12" + integrity sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw== dependencies: array-buffer-byte-length "^1.0.0" call-bind "^1.0.2" define-properties "^1.2.0" + es-abstract "^1.22.1" get-intrinsic "^1.2.1" is-array-buffer "^3.0.2" is-shared-array-buffer "^1.0.2" @@ -3428,7 +3201,7 @@ attr-accept@^2.2.2: resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b" integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== -autoprefixer@^10.4.14, autoprefixer@^10.4.15: +autoprefixer@^10.4.15: version "10.4.15" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.15.tgz#a1230f4aeb3636b89120b34a1f513e2f6834d530" integrity sha512-KCuPB8ZCIqFdA4HwKXsvz7j6gvSDNhDP7WnUjBleRkKjPdvCmHFuQ77ocavI8FT6NdvlBnE2UFr2H4Mycn8Vew== @@ -3446,9 +3219,9 @@ available-typed-arrays@^1.0.5: integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== axe-core@^4.6.2: - version "4.7.2" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.2.tgz#040a7342b20765cb18bb50b628394c21bccc17a0" - integrity sha512-zIURGIS1E1Q4pcrMjp+nnEh+16G56eG/MUllJH8yEvw7asDo7Ac9uhC9KIH5jzpITueEZolfYglnCGIuSBz39g== + version "4.8.1" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.8.1.tgz#6948854183ee7e7eae336b9877c5bafa027998ea" + integrity sha512-9l850jDDPnKq48nbad8SiEelCv4OrUWrKab/cPj0GScVg6cb6NbCCt/Ulk26QEq5jP9NnGr04Bit1BHyV6r5CQ== axios@^1.1.3, axios@^1.3.4: version "1.5.0" @@ -3637,9 +3410,9 @@ camelcase-css@^2.0.1: integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001517, caniuse-lite@^1.0.30001520: - version "1.0.30001525" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001525.tgz#d2e8fdec6116ffa36284ca2c33ef6d53612fe1c8" - integrity sha512-/3z+wB4icFt3r0USMwxujAqRvaD/B7rvGTsKhbhSQErVrJvkZCLhgNLJxU8MevahQVH6hCU9FsHdNUFbiwmE7Q== + version "1.0.30001538" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001538.tgz#9dbc6b9af1ff06b5eb12350c2012b3af56744f3f" + integrity sha512-HWJnhnID+0YMtGlzcp3T9drmBJUVDchPJ08tpUGFLs9CYlwWPH2uLgpHn8fND5pCgXVtnGS3H4QR9XLMHVNkHw== capital-case@^1.0.4: version "1.0.4" @@ -3865,9 +3638,9 @@ cookie@^0.5.0: integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== core-js-compat@^3.31.0: - version "3.32.1" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.32.1.tgz#55f9a7d297c0761a8eb1d31b593e0f5b6ffae964" - integrity sha512-GSvKDv4wE0bPnQtjklV101juQ85g6H3rm5PDP20mqlS5j0kXF3pP97YvAu5hl+uFHqMictp3b2VxOHljWMAtuA== + version "3.32.2" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.32.2.tgz#8047d1a8b3ac4e639f0d4f66d4431aa3b16e004c" + integrity sha512-+GjlguTDINOijtVRUxrQOv3kfu9rl+qPNdX2LTbJ/ZyVTuxK+ksVSAGX1nHstu4hrv1En/uPTtWgq2gI5wt4AQ== dependencies: browserslist "^4.21.10" @@ -4091,11 +3864,21 @@ deepmerge@^4.2.2, deepmerge@^4.3.1: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== -define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" - integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== +define-data-property@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.0.tgz#0db13540704e1d8d479a0656cf781267531b9451" + integrity sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g== + dependencies: + get-intrinsic "^1.2.1" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + +define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== dependencies: + define-data-property "^1.0.1" has-property-descriptors "^1.0.0" object-keys "^1.1.1" @@ -4212,9 +3995,9 @@ ejs@^3.1.6: jake "^10.8.5" electron-to-chromium@^1.4.477: - version "1.4.508" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.508.tgz#5641ff2f5ba11df4bd960fe6a2f9f70aa8b9af96" - integrity sha512-FFa8QKjQK/A5QuFr2167myhMesGrhlOBD+3cYNxO9/S4XzHEXesyTD/1/xF644gC8buFPz3ca6G1LOQD0tZrrg== + version "1.4.525" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.525.tgz#614284f33901fbecd3e90176c0d60590cd939700" + integrity sha512-GIZ620hDK4YmIqAWkscG4W6RwY6gOx1y5J6f4JUQwctiJrqH2oxZYU4mXHi35oV32tr630UcepBzSBGJ/WYcZA== emoji-regex@^8.0.0: version "8.0.0" @@ -4266,18 +4049,18 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.20.4, es-abstract@^1.22.1: - version "1.22.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.1.tgz#8b4e5fc5cefd7f1660f0f8e1a52900dfbc9d9ccc" - integrity sha512-ioRRcXMO6OFyRpyzV3kE1IIBd4WG5/kltnzdxSCqoP8CMGs/Li+M1uF5o7lOkZVFjDs+NLesthnF66Pg/0q0Lw== +es-abstract@^1.22.1: + version "1.22.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.2.tgz#90f7282d91d0ad577f505e423e52d4c1d93c1b8a" + integrity sha512-YoxfFcDmhjOgWPWsV13+2RNjq1F6UQnfs+8TftwNqtzlmFzEXvlUwdrNrYeaizfjQzRMxkZ6ElWMOJIFKdVqwA== dependencies: array-buffer-byte-length "^1.0.0" - arraybuffer.prototype.slice "^1.0.1" + arraybuffer.prototype.slice "^1.0.2" available-typed-arrays "^1.0.5" call-bind "^1.0.2" es-set-tostringtag "^2.0.1" es-to-primitive "^1.2.1" - function.prototype.name "^1.1.5" + function.prototype.name "^1.1.6" get-intrinsic "^1.2.1" get-symbol-description "^1.0.0" globalthis "^1.0.3" @@ -4293,32 +4076,32 @@ es-abstract@^1.20.4, es-abstract@^1.22.1: is-regex "^1.1.4" is-shared-array-buffer "^1.0.2" is-string "^1.0.7" - is-typed-array "^1.1.10" + is-typed-array "^1.1.12" is-weakref "^1.0.2" object-inspect "^1.12.3" object-keys "^1.1.1" object.assign "^4.1.4" - regexp.prototype.flags "^1.5.0" - safe-array-concat "^1.0.0" + regexp.prototype.flags "^1.5.1" + safe-array-concat "^1.0.1" safe-regex-test "^1.0.0" - string.prototype.trim "^1.2.7" - string.prototype.trimend "^1.0.6" - string.prototype.trimstart "^1.0.6" + string.prototype.trim "^1.2.8" + string.prototype.trimend "^1.0.7" + string.prototype.trimstart "^1.0.7" typed-array-buffer "^1.0.0" typed-array-byte-length "^1.0.0" typed-array-byte-offset "^1.0.0" typed-array-length "^1.0.4" unbox-primitive "^1.0.2" - which-typed-array "^1.1.10" + which-typed-array "^1.1.11" es-iterator-helpers@^1.0.12: - version "1.0.14" - resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.14.tgz#19cd7903697d97e21198f3293b55e8985791c365" - integrity sha512-JgtVnwiuoRuzLvqelrvN3Xu7H9bu2ap/kQ2CrM62iidP8SKuD99rWU3CJy++s7IVL2qb/AjXPGR/E7i9ngd/Cw== + version "1.0.15" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.0.15.tgz#bd81d275ac766431d19305923707c3efd9f1ae40" + integrity sha512-GhoY8uYqd6iwUl2kgjTm4CZAf6oo5mHK7BPqx3rKgx893YSsy0LGHV6gfqqQvZt/8xM8xeOnfXBCfqclMKkJ5g== dependencies: asynciterator.prototype "^1.0.0" call-bind "^1.0.2" - define-properties "^1.2.0" + define-properties "^1.2.1" es-abstract "^1.22.1" es-set-tostringtag "^2.0.1" function-bind "^1.1.1" @@ -4328,8 +4111,8 @@ es-iterator-helpers@^1.0.12: has-proto "^1.0.1" has-symbols "^1.0.3" internal-slot "^1.0.5" - iterator.prototype "^1.1.0" - safe-array-concat "^1.0.0" + iterator.prototype "^1.1.2" + safe-array-concat "^1.0.1" es-set-tostringtag@^2.0.1: version "2.0.1" @@ -4465,11 +4248,11 @@ eslint-config-prettier@^8.3.0: integrity sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg== eslint-config-turbo@latest: - version "1.10.13" - resolved "https://registry.yarnpkg.com/eslint-config-turbo/-/eslint-config-turbo-1.10.13.tgz#3743def3c76e27c3969c16222137f5bd913a10e2" - integrity sha512-Ffa0SxkRCPMtfUX/HDanEqsWoLwZTQTAXO9W4IsOtycb2MzJDrVcLmoFW5sMwCrg7gjqbrC4ZJoD+1SPPzIVqg== + version "1.10.14" + resolved "https://registry.yarnpkg.com/eslint-config-turbo/-/eslint-config-turbo-1.10.14.tgz#5e0c5ef1942783a2f7ffb631f4f322906a52663d" + integrity sha512-ZeB+IcuFXy1OICkLuAplVa0euoYbhK+bMEQd0nH9+Lns18lgZRm33mVz/iSoH9VdUzl/1ZmFmoK+RpZc+8R80A== dependencies: - eslint-plugin-turbo "1.10.13" + eslint-plugin-turbo "1.10.14" eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.7: version "0.3.9" @@ -4603,10 +4386,10 @@ eslint-plugin-react@^7.29.4, eslint-plugin-react@^7.31.7: semver "^6.3.1" string.prototype.matchall "^4.0.8" -eslint-plugin-turbo@1.10.13: - version "1.10.13" - resolved "https://registry.yarnpkg.com/eslint-plugin-turbo/-/eslint-plugin-turbo-1.10.13.tgz#d2c14c7e733ee1462c94d79dce29d75f42ced275" - integrity sha512-el4AAmn0zXmvHEyp1h0IQMfse10Vy8g5Vbg4IU3+vD9CSj5sDbX07iFVt8sCKg7og9Q5FAa9mXzlCf7t4vYgzg== +eslint-plugin-turbo@1.10.14: + version "1.10.14" + resolved "https://registry.yarnpkg.com/eslint-plugin-turbo/-/eslint-plugin-turbo-1.10.14.tgz#b9b7ffc2faef52cb158088e00f9ef6fe39966bd9" + integrity sha512-sBdBDnYr9AjT1g4lR3PBkZDonTrMnR4TvuGv5W0OiF7z9az1rI68yj2UHJZvjkwwcGu5mazWA1AfB0oaagpmfg== dependencies: dotenv "16.0.3" @@ -4793,15 +4576,15 @@ eslint@^7.23.0, eslint@^7.32.0: v8-compile-cache "^2.0.3" eslint@^8.31.0: - version "8.48.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.48.0.tgz#bf9998ba520063907ba7bfe4c480dc8be03c2155" - integrity sha512-sb6DLeIuRXxeM1YljSe1KEx9/YYeZFQWcV8Rq9HfigmdDEugjLEVEa1ozDjL6YDjBpQHPJxJzze+alxi4T3OLg== + version "8.49.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.49.0.tgz#09d80a89bdb4edee2efcf6964623af1054bf6d42" + integrity sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ== dependencies: "@eslint-community/eslint-utils" "^4.2.0" "@eslint-community/regexpp" "^4.6.1" "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "8.48.0" - "@humanwhocodes/config-array" "^0.11.10" + "@eslint/js" "8.49.0" + "@humanwhocodes/config-array" "^0.11.11" "@humanwhocodes/module-importer" "^1.0.1" "@nodelib/fs.walk" "^1.2.8" ajv "^6.12.4" @@ -5048,14 +4831,14 @@ flat-cache@^3.0.4: rimraf "^3.0.2" flatted@^3.2.7: - version "3.2.7" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" - integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + version "3.2.9" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.9.tgz#7eb4c67ca1ba34232ca9d2d93e9886e611ad7daf" + integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== follow-redirects@^1.15.0: - version "1.15.2" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.2.tgz#b460864144ba63f2681096f274c4e57026da2c13" - integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + version "1.15.3" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a" + integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q== for-each@^0.3.3: version "0.3.3" @@ -5118,7 +4901,7 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== -function.prototype.name@^1.1.5: +function.prototype.name@^1.1.5, function.prototype.name@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== @@ -5729,7 +5512,7 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typed-array@^1.1.10, is-typed-array@^1.1.9: +is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.9: version "1.1.12" resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== @@ -5771,15 +5554,16 @@ isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== -iterator.prototype@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.1.tgz#ab5b790e23ec00658f5974e032a2b05188bd3a5c" - integrity sha512-9E+nePc8C9cnQldmNl6bgpTY6zI4OPRZd97fhJ/iVZ1GifIUDVV5F6x1nEDqpe8KaMEZGT4xgrwKQDxXnjOIZQ== +iterator.prototype@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.2.tgz#5e29c8924f01916cb9335f1ff80619dcff22b0c0" + integrity sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w== dependencies: - define-properties "^1.2.0" + define-properties "^1.2.1" get-intrinsic "^1.2.1" has-symbols "^1.0.3" - reflect.getprototypeof "^1.0.3" + reflect.getprototypeof "^1.0.4" + set-function-name "^2.0.1" jake@^10.8.5: version "10.8.7" @@ -5810,9 +5594,9 @@ jest-worker@^27.4.5: supports-color "^8.0.0" jiti@^1.18.2: - version "1.19.3" - resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.19.3.tgz#ef554f76465b3c2b222dc077834a71f0d4a37569" - integrity sha512-5eEbBDQT/jF1xg6l36P+mWGGoH9Spuy0PCdSr2dtWRDGC6ph/w9ZCL4lmESW8f8F7MwT3XKescfP0wnZWAKL9w== + version "1.20.0" + resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.20.0.tgz#2d823b5852ee8963585c8dd8b7992ffc1ae83b42" + integrity sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA== joycon@^3.0.1: version "3.1.1" @@ -7028,10 +6812,10 @@ postcss@8.4.14: picocolors "^1.0.0" source-map-js "^1.0.2" -postcss@^8.4.21, postcss@^8.4.23, postcss@^8.4.29: - version "8.4.29" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.29.tgz#33bc121cf3b3688d4ddef50be869b2a54185a1dd" - integrity sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw== +postcss@^8.4.23, postcss@^8.4.29: + version "8.4.30" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.30.tgz#0e0648d551a606ef2192a26da4cabafcc09c1aa7" + integrity sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g== dependencies: nanoid "^3.3.6" picocolors "^1.0.0" @@ -7060,17 +6844,12 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier-plugin-tailwindcss@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.3.0.tgz#8299b307c7f6467f52732265579ed9375be6c818" - integrity sha512-009/Xqdy7UmkcTBpwlq7jsViDqXAYSOMLDrHAdTMlVZOrKfM2o9Ci7EMWTMZ7SkKBFTG04UM9F9iM2+4i6boDA== - prettier-plugin-tailwindcss@^0.5.4: version "0.5.4" resolved "https://registry.yarnpkg.com/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.5.4.tgz#ebfacbcb90e2ca1df671ffe4083e99f81d72040d" integrity sha512-QZzzB1bID6qPsKHTeA9qPo1APmmxfFrA5DD3LQ+vbTmAnY40eJI7t9Q1ocqel2EKMWNPLJqdTDWZj1hKYgqSgg== -prettier@^2.8.7, prettier@^2.8.8: +prettier@^2.8.7: version "2.8.8" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== @@ -7190,14 +6969,7 @@ prosemirror-menu@^1.2.1: prosemirror-history "^1.0.0" prosemirror-state "^1.0.0" -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: +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: 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== @@ -7257,9 +7029,9 @@ prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transfor prosemirror-model "^1.0.0" prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3, prosemirror-view@^1.27.0, prosemirror-view@^1.28.2, prosemirror-view@^1.31.0: - version "1.31.7" - resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.31.7.tgz#dccb2879314e1e1a24d48044c15374754e50ef00" - integrity sha512-Pr7w93yOYmxQwzGIRSaNLZ/1uM6YjnenASzN2H6fO6kGekuzRbgZ/4bHbBTd1u4sIQmL33/TcGmzxxidyPwCjg== + version "1.31.8" + resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.31.8.tgz#01c566a1c26c5a082ca4c04c017b832e1ea45b1f" + integrity sha512-VQrEIdiPJ4YV65Ifj2kWISwaiqocMHy7cpUKVQYt19C/87FepoqnwVW3kMKRpeY/nQzED8L+vyOaYDBn0WqT7w== dependencies: prosemirror-model "^1.16.0" prosemirror-state "^1.0.0" @@ -7350,15 +7122,15 @@ react-css-styled@^1.1.9: framework-utils "^1.1.0" react-datepicker@^4.8.0: - version "4.16.0" - resolved "https://registry.yarnpkg.com/react-datepicker/-/react-datepicker-4.16.0.tgz#b9dd389bb5611a1acc514bba1dd944be21dd877f" - integrity sha512-hNQ0PAg/LQoVbDUO/RWAdm/RYmPhN3cz7LuQ3hqbs24OSp69QCiKOJRrQ4jk1gv1jNR5oYu8SjjgfDh8q6Q1yw== + version "4.18.0" + resolved "https://registry.yarnpkg.com/react-datepicker/-/react-datepicker-4.18.0.tgz#d66301acc47833d31fa6f46f98781b084106da0e" + integrity sha512-0MYt3HmLbHVk1sw4v+RCbLAVg5TA3jWP7RyjZbo53PC+SEi+pjdgc92lB53ai/ENZaTOhbXmgni9GzvMrorMAw== dependencies: "@popperjs/core" "^2.11.8" classnames "^2.2.6" date-fns "^2.30.0" prop-types "^15.7.2" - react-onclickoutside "^6.12.2" + react-onclickoutside "^6.13.0" react-popper "^2.3.0" react-dom@18.2.0, react-dom@^18.2.0: @@ -7384,9 +7156,9 @@ react-fast-compare@^3.0.1: integrity sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ== react-hook-form@^7.38.0: - version "7.45.4" - resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.45.4.tgz#73d228b704026ae95d7e5f7b207a681b173ec62a" - integrity sha512-HGDV1JOOBPZj10LB3+OZgfDBTn+IeEsNOKiq/cxbQAIbKaiJUe/KV8DBUzsx0Gx/7IG/orWqRRm736JwOfUSWQ== + version "7.46.1" + resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.46.1.tgz#39347dbff19d980cb41087ac32a57abdc6045bb3" + integrity sha512-0GfI31LRTBd5tqbXMGXT1Rdsv3rnvy0FjEk8Gn9/4tp6+s77T7DPZuGEpBRXOauL+NhyGT5iaXzdIM2R6F/E+w== react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" @@ -7430,9 +7202,9 @@ react-markdown@^8.0.7: vfile "^5.0.0" react-moveable@^0.54.1: - version "0.54.1" - resolved "https://registry.yarnpkg.com/react-moveable/-/react-moveable-0.54.1.tgz#3c69748c444184700e6999501b0da953c934205e" - integrity sha512-Kj2ifw9nk3LZvu7ezhst8Z5WBPRr+yVv9oROwrBirFlHmwGHHZXUGk5Gaezu+JGqqNRsQJncVMW5Uf68KSSOvg== + version "0.54.2" + resolved "https://registry.yarnpkg.com/react-moveable/-/react-moveable-0.54.2.tgz#87ce9af3499dc1c8218bce7e174b10264c1bbecf" + integrity sha512-NGaVLbn0i9pb3+BWSKGWFqI/Mgm4+WMeWHxXXQ4Qi1tHxWCXrUrbGvpxEpt69G/hR7dez+/m68ex+fabjnvcUg== dependencies: "@daybrush/utils" "^1.13.0" "@egjs/agent" "^2.2.1" @@ -7448,7 +7220,7 @@ react-moveable@^0.54.1: react-css-styled "^1.1.9" react-selecto "^1.25.0" -react-onclickoutside@^6.12.2: +react-onclickoutside@^6.13.0: version "6.13.0" resolved "https://registry.yarnpkg.com/react-onclickoutside/-/react-onclickoutside-6.13.0.tgz#e165ea4e5157f3da94f4376a3ab3e22a565f4ffc" integrity sha512-ty8So6tcUpIb+ZE+1HAhbLROvAIJYyJe/1vRrrcmW+jLsaM+/powDRqxzo6hSh9CuRZGSL1Q8mvcF5WRD93a0A== @@ -7575,7 +7347,7 @@ redux@^4.0.0, redux@^4.0.4: dependencies: "@babel/runtime" "^7.9.2" -reflect.getprototypeof@^1.0.3: +reflect.getprototypeof@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz#aaccbf41aca3821b87bb71d9dcbc7ad0ba50a3f3" integrity sha512-ECkTw8TmJwW60lOTR+ZkODISW6RQ8+2CL3COqtiJKLd6MmB45hN51HprHFziKLGkAuTGQhBb91V8cy+KHlaCjw== @@ -7588,9 +7360,9 @@ reflect.getprototypeof@^1.0.3: which-builtin-type "^1.1.3" regenerate-unicode-properties@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.0.tgz#7c3192cab6dd24e21cb4461e5ddd7dd24fa8374c" - integrity sha512-d1VudCLoIGitcU/hEg2QqvyGZQmdC0Lf8BqdOMXGFSvJP4bNV1+XqbPQeHHLD51Jh4QJJ225dlIFvY4Ly6MXmQ== + version "10.1.1" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz#6b0e05489d9076b04c436f318d9b067bba459480" + integrity sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q== dependencies: regenerate "^1.4.2" @@ -7611,14 +7383,14 @@ regenerator-transform@^0.15.2: dependencies: "@babel/runtime" "^7.8.4" -regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb" - integrity sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA== +regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.5.0, regexp.prototype.flags@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" + integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== dependencies: call-bind "^1.0.2" define-properties "^1.2.0" - functions-have-names "^1.2.3" + set-function-name "^2.0.0" regexpp@^3.1.0, regexpp@^3.2.0: version "3.2.0" @@ -7684,9 +7456,9 @@ resolve-pkg-maps@^1.0.0: integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== resolve@^1.1.7, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.22.0, resolve@^1.22.2, resolve@^1.22.4: - version "1.22.4" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.4.tgz#1dc40df46554cdaf8948a486a10f6ba1e2026c34" - integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg== + version "1.22.6" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.6.tgz#dd209739eca3aef739c626fea1b4f3c506195362" + integrity sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw== dependencies: is-core-module "^2.13.0" path-parse "^1.0.7" @@ -7745,9 +7517,9 @@ rollup@^2.43.1: fsevents "~2.3.2" rollup@^3.2.5: - version "3.29.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.0.tgz#1b40e64818afc979c7e5bef93de675829288986b" - integrity sha512-nszM8DINnx1vSS+TpbWKMkxem0CDWk3cSit/WWCBVs9/JZ1I/XLwOsiUglYuYReaeWWSsW9kge5zE5NZtf/a4w== + version "3.29.2" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-3.29.2.tgz#cbc76cd5b03b9f9e93be991d23a1dff9c6d5b740" + integrity sha512-CJouHoZ27v6siztc21eEQGo0kIcE5D1gVPA571ez0mMYb25LGYGKnVNXpEj5MGlepmDWGXNjDB5q7uNiPHC11A== optionalDependencies: fsevents "~2.3.2" @@ -7770,13 +7542,13 @@ sade@^1.7.3: dependencies: mri "^1.1.0" -safe-array-concat@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.0.tgz#2064223cba3c08d2ee05148eedbc563cd6d84060" - integrity sha512-9dVEFruWIsnie89yym+xWTAYASdpw3CJV7Li/6zBewGf9z2i1j31rP6jnY0pHEO4QZh6N0K11bFjWmdR8UGdPQ== +safe-array-concat@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz#91686a63ce3adbea14d61b14c99572a8ff84754c" + integrity sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q== dependencies: call-bind "^1.0.2" - get-intrinsic "^1.2.0" + get-intrinsic "^1.2.1" has-symbols "^1.0.3" isarray "^2.0.5" @@ -7870,10 +7642,19 @@ serialize-javascript@^6.0.1: dependencies: randombytes "^2.1.0" +set-function-name@^2.0.0, set-function-name@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.1.tgz#12ce38b7954310b9f61faa12701620a0c882793a" + integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== + dependencies: + define-data-property "^1.0.1" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.0" + sharp@^0.32.1: - version "0.32.5" - resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.32.5.tgz#9ddc78ead6446094f51e50355a2d4ec6e7220cd4" - integrity sha512-0dap3iysgDkNaPOaOL4X/0akdu0ma62GcdC2NBQ+93eqpePdDdr2/LM0sFdDSMmN7yS+odyZtPsb7tx/cYBKnQ== + version "0.32.6" + resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.32.6.tgz#6ad30c0b7cd910df65d5f355f774aa4fce45732a" + integrity sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w== dependencies: color "^4.2.3" detect-libc "^2.0.2" @@ -8033,9 +7814,9 @@ string-width@^4.2.3: strip-ansi "^6.0.1" string.prototype.matchall@^4.0.6, string.prototype.matchall@^4.0.7, string.prototype.matchall@^4.0.8: - version "4.0.9" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.9.tgz#148779de0f75d36b13b15885fec5cadde994520d" - integrity sha512-6i5hL3MqG/K2G43mWXWgP+qizFW/QH/7kCNN13JrJS5q48FN5IKksLDscexKP3dnmB6cdm9jlNgAsWNLpSykmA== + version "4.0.10" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.10.tgz#a1553eb532221d4180c51581d6072cd65d1ee100" + integrity sha512-rGXbGmOEosIQi6Qva94HUjgPs9vKW+dkG7Y8Q5O2OYkWL6wFaTRZO8zM4mhP94uX55wgyrXzfS2aGtGzUL7EJQ== dependencies: call-bind "^1.0.2" define-properties "^1.2.0" @@ -8044,34 +7825,35 @@ string.prototype.matchall@^4.0.6, string.prototype.matchall@^4.0.7, string.proto has-symbols "^1.0.3" internal-slot "^1.0.5" regexp.prototype.flags "^1.5.0" + set-function-name "^2.0.0" side-channel "^1.0.4" -string.prototype.trim@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" - integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== +string.prototype.trim@^1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" + integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== dependencies: call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + define-properties "^1.2.0" + es-abstract "^1.22.1" -string.prototype.trimend@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz#c4a27fa026d979d79c04f17397f250a462944533" - integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== +string.prototype.trimend@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" + integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== dependencies: call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + define-properties "^1.2.0" + es-abstract "^1.22.1" -string.prototype.trimstart@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz#e90ab66aa8e4007d92ef591bbf3cd422c56bdcf4" - integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== +string.prototype.trimstart@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" + integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== dependencies: call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + define-properties "^1.2.0" + es-abstract "^1.22.1" string_decoder@^1.1.1: version "1.3.0" @@ -8201,12 +7983,12 @@ tailwind-merge@^1.14.0: resolved "https://registry.yarnpkg.com/tailwind-merge/-/tailwind-merge-1.14.0.tgz#e677f55d864edc6794562c63f5001f45093cdb8b" integrity sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ== -tailwindcss-animate@^1.0.6, tailwindcss-animate@^1.0.7: +tailwindcss-animate@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz#318b692c4c42676cc9e67b19b78775742388bef4" integrity sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA== -tailwindcss@^3.2.7, tailwindcss@^3.3.3: +tailwindcss@^3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.3.tgz#90da807393a2859189e48e9e7000e6880a736daf" integrity sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w== @@ -8305,9 +8087,9 @@ terser-webpack-plugin@^5.3.3: terser "^5.16.8" terser@^5.0.0, terser@^5.16.8: - version "5.19.3" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.19.3.tgz#359baeba615aef13db4b8c4d77a2aa0d8814aa9e" - integrity sha512-pQzJ9UJzM0IgmT4FAtYI6+VqFf0lj/to58AV0Xfgg0Up37RyPG7Al+1cepC6/BVuAxR9oNb41/DL4DEoHJvTdg== + version "5.19.4" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.19.4.tgz#941426fa482bf9b40a0308ab2b3cd0cf7c775ebd" + integrity sha512-6p1DjHeuluwxDXcuT9VR8p64klWJKo1ILiy19s6C9+0Bh2+NWTX6nD9EPppiER4ICkHDVB1RkVpin/YW2nQn/g== dependencies: "@jridgewell/source-map" "^0.3.3" acorn "^8.8.2" @@ -8473,47 +8255,47 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" -turbo-darwin-64@1.10.13: - version "1.10.13" - resolved "https://registry.yarnpkg.com/turbo-darwin-64/-/turbo-darwin-64-1.10.13.tgz#7abc33838bf74c7e7ba2955cb6acc40342d6964c" - integrity sha512-vmngGfa2dlYvX7UFVncsNDMuT4X2KPyPJ2Jj+xvf5nvQnZR/3IeDEGleGVuMi/hRzdinoxwXqgk9flEmAYp0Xw== +turbo-darwin-64@1.10.14: + version "1.10.14" + resolved "https://registry.yarnpkg.com/turbo-darwin-64/-/turbo-darwin-64-1.10.14.tgz#9e8061bc0d706a69bc61d88fbfa7690fa2a897fc" + integrity sha512-I8RtFk1b9UILAExPdG/XRgGQz95nmXPE7OiGb6ytjtNIR5/UZBS/xVX/7HYpCdmfriKdVwBKhalCoV4oDvAGEg== -turbo-darwin-arm64@1.10.13: - version "1.10.13" - resolved "https://registry.yarnpkg.com/turbo-darwin-arm64/-/turbo-darwin-arm64-1.10.13.tgz#89f2d14a28789e5eaf276a17fecd4116d61fd16d" - integrity sha512-eMoJC+k7gIS4i2qL6rKmrIQGP6Wr9nN4odzzgHFngLTMimok2cGLK3qbJs5O5F/XAtEeRAmuxeRnzQwTl/iuAw== +turbo-darwin-arm64@1.10.14: + version "1.10.14" + resolved "https://registry.yarnpkg.com/turbo-darwin-arm64/-/turbo-darwin-arm64-1.10.14.tgz#2589aeb814257601c979dd40ff8a6cace6c9e4e5" + integrity sha512-KAdUWryJi/XX7OD0alOuOa0aJ5TLyd4DNIYkHPHYcM6/d7YAovYvxRNwmx9iv6Vx6IkzTnLeTiUB8zy69QkG9Q== -turbo-linux-64@1.10.13: - version "1.10.13" - resolved "https://registry.yarnpkg.com/turbo-linux-64/-/turbo-linux-64-1.10.13.tgz#803e2b351984ec81034dc4b6935cdfb0a7d7d572" - integrity sha512-0CyYmnKTs6kcx7+JRH3nPEqCnzWduM0hj8GP/aodhaIkLNSAGAa+RiYZz6C7IXN+xUVh5rrWTnU2f1SkIy7Gdg== +turbo-linux-64@1.10.14: + version "1.10.14" + resolved "https://registry.yarnpkg.com/turbo-linux-64/-/turbo-linux-64-1.10.14.tgz#c01d26f62f6c47701026dea083054918fe8caf47" + integrity sha512-BOBzoREC2u4Vgpap/WDxM6wETVqVMRcM8OZw4hWzqCj2bqbQ6L0wxs1LCLWVrghQf93JBQtIGAdFFLyCSBXjWQ== -turbo-linux-arm64@1.10.13: - version "1.10.13" - resolved "https://registry.yarnpkg.com/turbo-linux-arm64/-/turbo-linux-arm64-1.10.13.tgz#92439a927ec98801be1be266016736be5730e40c" - integrity sha512-0iBKviSGQQlh2OjZgBsGjkPXoxvRIxrrLLbLObwJo3sOjIH0loGmVIimGS5E323soMfi/o+sidjk2wU1kFfD7Q== +turbo-linux-arm64@1.10.14: + version "1.10.14" + resolved "https://registry.yarnpkg.com/turbo-linux-arm64/-/turbo-linux-arm64-1.10.14.tgz#7cbcb091995a09134342a57e0672501115b46df2" + integrity sha512-D8T6XxoTdN5D4V5qE2VZG+/lbZX/89BkAEHzXcsSUTRjrwfMepT3d2z8aT6hxv4yu8EDdooZq/2Bn/vjMI32xw== -turbo-windows-64@1.10.13: - version "1.10.13" - resolved "https://registry.yarnpkg.com/turbo-windows-64/-/turbo-windows-64-1.10.13.tgz#870815cdcb20f2480296c208778f9127be61eec6" - integrity sha512-S5XySRfW2AmnTeY1IT+Jdr6Goq7mxWganVFfrmqU+qqq3Om/nr0GkcUX+KTIo9mPrN0D3p5QViBRzulwB5iuUQ== +turbo-windows-64@1.10.14: + version "1.10.14" + resolved "https://registry.yarnpkg.com/turbo-windows-64/-/turbo-windows-64-1.10.14.tgz#935d2d1da7fb1f9a941fb3aa122fd9a70b61c416" + integrity sha512-zKNS3c1w4i6432N0cexZ20r/aIhV62g69opUn82FLVs/zk3Ie0GVkSB6h0rqIvMalCp7enIR87LkPSDGz9K4UA== -turbo-windows-arm64@1.10.13: - version "1.10.13" - resolved "https://registry.yarnpkg.com/turbo-windows-arm64/-/turbo-windows-arm64-1.10.13.tgz#2da38b71b1716732541dfc5bd7475dc0903921f8" - integrity sha512-nKol6+CyiExJIuoIc3exUQPIBjP9nIq5SkMJgJuxsot2hkgGrafAg/izVDRDrRduQcXj2s8LdtxJHvvnbI8hEQ== +turbo-windows-arm64@1.10.14: + version "1.10.14" + resolved "https://registry.yarnpkg.com/turbo-windows-arm64/-/turbo-windows-arm64-1.10.14.tgz#cb3a55d30a75aa76258991e929e92f207cac872f" + integrity sha512-rkBwrTPTxNSOUF7of8eVvvM+BkfkhA2OvpHM94if8tVsU+khrjglilp8MTVPHlyS9byfemPAmFN90oRIPB05BA== turbo@latest: - version "1.10.13" - resolved "https://registry.yarnpkg.com/turbo/-/turbo-1.10.13.tgz#8050bcd09f8a20d5a626f41e86cd8760e49a0df6" - integrity sha512-vOF5IPytgQPIsgGtT0n2uGZizR2N3kKuPIn4b5p5DdeLoI0BV7uNiydT7eSzdkPRpdXNnO8UwS658VaI4+YSzQ== + version "1.10.14" + resolved "https://registry.yarnpkg.com/turbo/-/turbo-1.10.14.tgz#31f3bb3017218191e0de64728da199678a50aa7d" + integrity sha512-hr9wDNYcsee+vLkCDIm8qTtwhJ6+UAMJc3nIY6+PNgUTtXcQgHxCq8BGoL7gbABvNWv76CNbK5qL4Lp9G3ZYRA== optionalDependencies: - turbo-darwin-64 "1.10.13" - turbo-darwin-arm64 "1.10.13" - turbo-linux-64 "1.10.13" - turbo-linux-arm64 "1.10.13" - turbo-windows-64 "1.10.13" - turbo-windows-arm64 "1.10.13" + turbo-darwin-64 "1.10.14" + turbo-darwin-arm64 "1.10.14" + turbo-linux-64 "1.10.14" + turbo-linux-arm64 "1.10.14" + turbo-windows-64 "1.10.14" + turbo-windows-arm64 "1.10.14" type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" @@ -8781,9 +8563,9 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2: integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== uuid@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" - integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== uvu@^0.5.0: version "0.5.6" @@ -8909,7 +8691,7 @@ which-collection@^1.0.1: is-weakmap "^2.0.1" is-weakset "^2.0.1" -which-typed-array@^1.1.10, which-typed-array@^1.1.11, which-typed-array@^1.1.9: +which-typed-array@^1.1.11, which-typed-array@^1.1.9: version "1.1.11" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.11.tgz#99d691f23c72aab6768680805a271b69761ed61a" integrity sha512-qe9UWWpkeG5yzZ0tNYxDmd7vo58HDBc39mZ0xWWpolAGADdFOzkfamWLDxkOWcvHQKVmdTyQdLD4NOfjLWTKew== From 8e71ce0c50d2ceb7175b4645168c84583eb7e1a7 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Wed, 20 Sep 2023 19:03:06 +0530 Subject: [PATCH 09/57] finally fixed import errors --- packages/editor/package.json | 26 +++++++++------------- packages/editor/tsconfig.json | 16 +++++++++---- web/components/issues/description-form.tsx | 2 +- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/packages/editor/package.json b/packages/editor/package.json index 49a1c2d2b98..58f191cb47f 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -2,19 +2,22 @@ "name": "@plane/editor", "version": "0.0.1", "description": "Rich Text Editor that powers Plane", - "main": "dist/index.js", + "main": "dist/index", + "types": "dist/index", "source": "src/index.ts", - "module": "dist/index.mjs", - "types": "dist/index.d.mts", "files": [ "dist" ], "exports": { ".": { - "types": "./dist/index.d.mts", - "import": "./dist/index.mjs", - "module": "./dist/index.mjs", - "require": "./dist/index.js" + "import": { + "types": "./dist/index.d.mts", + "default": "./dist/module.mjs" + }, + "require": { + "types": "./dist/index.d.ts", + "default": "./dist/main.js" + } } }, "scripts": { @@ -81,12 +84,5 @@ "markdown", "nextjs", "react" - ], - "typesVersions": { - "*": { - "*": [ - "src/*" - ] - } - } + ] } diff --git a/packages/editor/tsconfig.json b/packages/editor/tsconfig.json index 9799dcdfcd9..bf38514e1f7 100644 --- a/packages/editor/tsconfig.json +++ b/packages/editor/tsconfig.json @@ -1,12 +1,20 @@ { "extends": "tsconfig/react.json", - "include": ["."], - "exclude": ["dist", "build", "node_modules"], - + "include": [ + "src/**/*", + "index.d.ts" + ], + "exclude": [ + "dist", + "build", + "node_modules" + ], "compilerOptions": { "baseUrl": ".", "paths": { - "@/*": ["src/*"] + "@/*": [ + "src/*" + ] } } } diff --git a/web/components/issues/description-form.tsx b/web/components/issues/description-form.tsx index f4ec6c268e3..7606dee9761 100644 --- a/web/components/issues/description-form.tsx +++ b/web/components/issues/description-form.tsx @@ -9,7 +9,7 @@ import { useDebouncedCallback } from "use-debounce"; import { TextArea } from "components/ui"; // types import { IIssue } from "types"; -import { TiptapEditor } from "@plane/editor" +import { TiptapEditor } from "@plane/editor"; import fileService from "services/file.service"; export interface IssueDescriptionFormValues { From 448d433876f85fc5fe86acb4e0d8aaed8f8ebd29 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Thu, 21 Sep 2023 18:04:38 +0530 Subject: [PATCH 10/57] added turbo dependency for tiptap --- packages/editor/package.json | 19 +- packages/editor/src/styles/tailwind.css | 358 ++++++++++++++++++++++++ turbo.json | 20 +- 3 files changed, 382 insertions(+), 15 deletions(-) diff --git a/packages/editor/package.json b/packages/editor/package.json index 58f191cb47f..c87317af66f 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -2,22 +2,17 @@ "name": "@plane/editor", "version": "0.0.1", "description": "Rich Text Editor that powers Plane", - "main": "dist/index", - "types": "dist/index", - "source": "src/index.ts", + "main": "./dist/index.mjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.mts", "files": [ - "dist" + "dist/**/*" ], "exports": { ".": { - "import": { - "types": "./dist/index.d.mts", - "default": "./dist/module.mjs" - }, - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/main.js" - } + "types": "./dist/index.d.mts", + "import": "./dist/index.mjs", + "module": "./dist/index.mjs" } }, "scripts": { diff --git a/packages/editor/src/styles/tailwind.css b/packages/editor/src/styles/tailwind.css index b5c61c95671..3de1e2c571c 100644 --- a/packages/editor/src/styles/tailwind.css +++ b/packages/editor/src/styles/tailwind.css @@ -1,3 +1,361 @@ +@import url("https://fonts.googleapis.com/css2?family=Inter:wght@200;300;400;500;600;700;800&display=swap"); +@import url("https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@48,400,0,0&display=swap"); + @tailwind base; @tailwind components; @tailwind utilities; + +@layer components { + .text-1\.5xl { + font-size: 1.375rem; + line-height: 1.875rem; + } + + .text-2\.5xl { + font-size: 1.75rem; + line-height: 2.25rem; + } +} + +@layer base { + html { + font-family: "Inter", sans-serif; + } + + :root { + color-scheme: light !important; + + --color-primary-10: 236, 241, 255; + --color-primary-20: 217, 228, 255; + --color-primary-30: 197, 214, 255; + --color-primary-40: 178, 200, 255; + --color-primary-50: 159, 187, 255; + --color-primary-60: 140, 173, 255; + --color-primary-70: 121, 159, 255; + --color-primary-80: 101, 145, 255; + --color-primary-90: 82, 132, 255; + --color-primary-100: 63, 118, 255; + --color-primary-200: 57, 106, 230; + --color-primary-300: 50, 94, 204; + --color-primary-400: 44, 83, 179; + --color-primary-500: 38, 71, 153; + --color-primary-600: 32, 59, 128; + --color-primary-700: 25, 47, 102; + --color-primary-800: 19, 35, 76; + --color-primary-900: 13, 24, 51; + + --color-background-100: 255, 255, 255; /* primary bg */ + --color-background-90: 250, 250, 250; /* secondary bg */ + --color-background-80: 245, 245, 245; /* tertiary bg */ + + --color-text-100: 23, 23, 23; /* primary text */ + --color-text-200: 58, 58, 58; /* secondary text */ + --color-text-300: 82, 82, 82; /* tertiary text */ + --color-text-400: 163, 163, 163; /* placeholder text */ + + --color-border-100: 245, 245, 245; /* subtle border= 1 */ + --color-border-200: 229, 229, 229; /* subtle border- 2 */ + --color-border-300: 212, 212, 212; /* strong border- 1 */ + --color-border-400: 185, 185, 185; /* strong border- 2 */ + + --color-shadow-2xs: 0px 0px 1px 0px rgba(23, 23, 23, 0.06), + 0px 1px 2px 0px rgba(23, 23, 23, 0.06), 0px 1px 2px 0px rgba(23, 23, 23, 0.14); + --color-shadow-xs: 0px 1px 2px 0px rgba(0, 0, 0, 0.16), 0px 2px 4px 0px rgba(16, 24, 40, 0.12), + 0px 1px 8px -1px rgba(16, 24, 40, 0.1); + --color-shadow-sm: 0px 1px 4px 0px rgba(0, 0, 0, 0.01), 0px 4px 8px 0px rgba(0, 0, 0, 0.02), + 0px 1px 12px 0px rgba(0, 0, 0, 0.12); + --color-shadow-rg: 0px 3px 6px 0px rgba(0, 0, 0, 0.1), 0px 4px 4px 0px rgba(16, 24, 40, 0.08), + 0px 1px 12px 0px rgba(16, 24, 40, 0.04); + --color-shadow-md: 0px 4px 8px 0px rgba(0, 0, 0, 0.12), 0px 6px 12px 0px rgba(16, 24, 40, 0.12), + 0px 1px 16px 0px rgba(16, 24, 40, 0.12); + --color-shadow-lg: 0px 6px 12px 0px rgba(0, 0, 0, 0.12), 0px 8px 16px 0px rgba(0, 0, 0, 0.12), + 0px 1px 24px 0px rgba(16, 24, 40, 0.12); + --color-shadow-xl: 0px 0px 18px 0px rgba(0, 0, 0, 0.16), 0px 0px 24px 0px rgba(16, 24, 40, 0.16), + 0px 0px 52px 0px rgba(16, 24, 40, 0.16); + --color-shadow-2xl: 0px 8px 16px 0px rgba(0, 0, 0, 0.12), + 0px 12px 24px 0px rgba(16, 24, 40, 0.12), 0px 1px 32px 0px rgba(16, 24, 40, 0.12); + --color-shadow-3xl: 0px 12px 24px 0px rgba(0, 0, 0, 0.12), 0px 16px 32px 0px rgba(0, 0, 0, 0.12), + 0px 1px 48px 0px rgba(16, 24, 40, 0.12); + + --color-sidebar-background-100: var(--color-background-100); /* primary sidebar bg */ + --color-sidebar-background-90: var(--color-background-90); /* secondary sidebar bg */ + --color-sidebar-background-80: var(--color-background-80); /* tertiary sidebar bg */ + + --color-sidebar-text-100: var(--color-text-100); /* primary sidebar text */ + --color-sidebar-text-200: var(--color-text-200); /* secondary sidebar text */ + --color-sidebar-text-300: var(--color-text-300); /* tertiary sidebar text */ + --color-sidebar-text-400: var(--color-text-400); /* sidebar placeholder text */ + + --color-sidebar-border-100: var(--color-border-100); /* subtle sidebar border= 1 */ + --color-sidebar-border-200: var(--color-border-100); /* subtle sidebar border- 2 */ + --color-sidebar-border-300: var(--color-border-100); /* strong sidebar border- 1 */ + --color-sidebar-border-400: var(--color-border-100); /* strong sidebar border- 2 */ + + --color-sidebar-shadow-2xs: var(--color-shadow-2xs); + --color-sidebar-shadow-xs: var(--color-shadow-xs); + --color-sidebar-shadow-sm: var(--color-shadow-sm); + --color-sidebar-shadow-rg: var(--color-shadow-rg); + --color-sidebar-shadow-md: var(--color-shadow-md); + --color-sidebar-shadow-lg: var(--color-shadow-lg); + --color-sidebar-shadow-xl: var(--color-shadow-xl); + --color-sidebar-shadow-2xl: var(--color-shadow-2xl); + --color-sidebar-shadow-3xl: var(--color-shadow-3xl); + } + + [data-theme="light"], + [data-theme="light-contrast"] { + color-scheme: light !important; + + --color-background-100: 255, 255, 255; /* primary bg */ + --color-background-90: 250, 250, 250; /* secondary bg */ + --color-background-80: 245, 245, 245; /* tertiary bg */ + } + + [data-theme="light"] { + --color-text-100: 23, 23, 23; /* primary text */ + --color-text-200: 58, 58, 58; /* secondary text */ + --color-text-300: 82, 82, 82; /* tertiary text */ + --color-text-400: 163, 163, 163; /* placeholder text */ + + --color-border-100: 245, 245, 245; /* subtle border= 1 */ + --color-border-200: 229, 229, 229; /* subtle border- 2 */ + --color-border-300: 212, 212, 212; /* strong border- 1 */ + --color-border-400: 185, 185, 185; /* strong border- 2 */ + } + + [data-theme="light-contrast"] { + --color-text-100: 11, 11, 11; /* primary text */ + --color-text-200: 38, 38, 38; /* secondary text */ + --color-text-300: 58, 58, 58; /* tertiary text */ + --color-text-400: 115, 115, 115; /* placeholder text */ + + --color-border-100: 34, 34, 34; /* subtle border= 1 */ + --color-border-200: 38, 38, 38; /* subtle border- 2 */ + --color-border-300: 46, 46, 46; /* strong border- 1 */ + --color-border-400: 58, 58, 58; /* strong border- 2 */ + } + + [data-theme="dark"], + [data-theme="dark-contrast"] { + color-scheme: dark !important; + + --color-background-100: 7, 7, 7; /* primary bg */ + --color-background-90: 11, 11, 11; /* secondary bg */ + --color-background-80: 23, 23, 23; /* tertiary bg */ + + --color-shadow-2xs: 0px 0px 1px 0px rgba(0, 0, 0, 0.15), 0px 1px 3px 0px rgba(0, 0, 0, 0.5); + --color-shadow-xs: 0px 0px 2px 0px rgba(0, 0, 0, 0.2), 0px 2px 4px 0px rgba(0, 0, 0, 0.5); + --color-shadow-sm: 0px 0px 4px 0px rgba(0, 0, 0, 0.2), 0px 2px 6px 0px rgba(0, 0, 0, 0.5); + --color-shadow-rg: 0px 0px 6px 0px rgba(0, 0, 0, 0.2), 0px 4px 6px 0px rgba(0, 0, 0, 0.5); + --color-shadow-md: 0px 2px 8px 0px rgba(0, 0, 0, 0.2), 0px 4px 8px 0px rgba(0, 0, 0, 0.5); + --color-shadow-lg: 0px 4px 12px 0px rgba(0, 0, 0, 0.25), 0px 4px 10px 0px rgba(0, 0, 0, 0.55); + --color-shadow-xl: 0px 0px 14px 0px rgba(0, 0, 0, 0.25), 0px 6px 10px 0px rgba(0, 0, 0, 0.55); + --color-shadow-2xl: 0px 0px 18px 0px rgba(0, 0, 0, 0.25), 0px 8px 12px 0px rgba(0, 0, 0, 0.6); + --color-shadow-3xl: 0px 4px 24px 0px rgba(0, 0, 0, 0.3), 0px 12px 40px 0px rgba(0, 0, 0, 0.65); + } + + [data-theme="dark"] { + --color-text-100: 229, 229, 229; /* primary text */ + --color-text-200: 163, 163, 163; /* secondary text */ + --color-text-300: 115, 115, 115; /* tertiary text */ + --color-text-400: 82, 82, 82; /* placeholder text */ + + --color-border-100: 34, 34, 34; /* subtle border= 1 */ + --color-border-200: 38, 38, 38; /* subtle border- 2 */ + --color-border-300: 46, 46, 46; /* strong border- 1 */ + --color-border-400: 58, 58, 58; /* strong border- 2 */ + } + + [data-theme="dark-contrast"] { + --color-text-100: 250, 250, 250; /* primary text */ + --color-text-200: 241, 241, 241; /* secondary text */ + --color-text-300: 212, 212, 212; /* tertiary text */ + --color-text-400: 115, 115, 115; /* placeholder text */ + + --color-border-100: 245, 245, 245; /* subtle border= 1 */ + --color-border-200: 229, 229, 229; /* subtle border- 2 */ + --color-border-300: 212, 212, 212; /* strong border- 1 */ + --color-border-400: 185, 185, 185; /* strong border- 2 */ + } + + [data-theme="light"], + [data-theme="dark"], + [data-theme="light-contrast"], + [data-theme="dark-contrast"] { + --color-primary-10: 236, 241, 255; + --color-primary-20: 217, 228, 255; + --color-primary-30: 197, 214, 255; + --color-primary-40: 178, 200, 255; + --color-primary-50: 159, 187, 255; + --color-primary-60: 140, 173, 255; + --color-primary-70: 121, 159, 255; + --color-primary-80: 101, 145, 255; + --color-primary-90: 82, 132, 255; + --color-primary-100: 63, 118, 255; + --color-primary-200: 57, 106, 230; + --color-primary-300: 50, 94, 204; + --color-primary-400: 44, 83, 179; + --color-primary-500: 38, 71, 153; + --color-primary-600: 32, 59, 128; + --color-primary-700: 25, 47, 102; + --color-primary-800: 19, 35, 76; + --color-primary-900: 13, 24, 51; + + --color-sidebar-background-100: var(--color-background-100); /* primary sidebar bg */ + --color-sidebar-background-90: var(--color-background-90); /* secondary sidebar bg */ + --color-sidebar-background-80: var(--color-background-80); /* tertiary sidebar bg */ + + --color-sidebar-text-100: var(--color-text-100); /* primary sidebar text */ + --color-sidebar-text-200: var(--color-text-200); /* secondary sidebar text */ + --color-sidebar-text-300: var(--color-text-300); /* tertiary sidebar text */ + --color-sidebar-text-400: var(--color-text-400); /* sidebar placeholder text */ + + --color-sidebar-border-100: var(--color-border-100); /* subtle sidebar border= 1 */ + --color-sidebar-border-200: var(--color-border-100); /* subtle sidebar border- 2 */ + --color-sidebar-border-300: var(--color-border-100); /* strong sidebar border- 1 */ + --color-sidebar-border-400: var(--color-border-100); /* strong sidebar border- 2 */ + } +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; + font-variant-ligatures: none; + -webkit-font-variant-ligatures: none; + text-rendering: optimizeLegibility; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; +} + +body { + color: rgba(var(--color-text-100)); +} + +/* scrollbar style */ +::-webkit-scrollbar { + display: none; +} + +.horizontal-scroll-enable { + overflow-x: scroll; +} + +.horizontal-scroll-enable::-webkit-scrollbar { + display: block; + height: 7px; + width: 0; +} + +.horizontal-scroll-enable::-webkit-scrollbar-track { + height: 7px; + background-color: rgba(var(--color-background-100)); +} + +.horizontal-scroll-enable::-webkit-scrollbar-thumb { + border-radius: 5px; + background-color: rgba(var(--color-background-80)); +} + +.vertical-scroll-enable::-webkit-scrollbar { + display: block; + width: 5px; +} + +.vertical-scroll-enable::-webkit-scrollbar-track { + width: 5px; +} + +.vertical-scroll-enable::-webkit-scrollbar-thumb { + border-radius: 5px; + background-color: rgba(var(--color-background-90)); +} +/* end scrollbar style */ + +.tags-input-container { + border: 2px solid #000; + padding: 0.5em; + border-radius: 3px; + width: min(80vw, 600px); + margin-top: 1em; + display: flex; + align-items: center; + flex-wrap: wrap; + gap: 0.5em; +} + +.tag-item { + background-color: rgb(218, 216, 216); + display: inline-block; + padding: 0.5em 0.75em; + border-radius: 20px; +} +.tag-item .close { + height: 20px; + width: 20px; + background-color: rgb(48, 48, 48); + color: #fff; + border-radius: 50%; + display: inline-flex; + justify-content: center; + align-items: center; + margin-left: 0.5em; + font-size: 18px; + cursor: pointer; +} + +.tags-input { + flex-grow: 1; + padding: 0.5em 0; + border: none; + outline: none; +} + +/* emoji icon picker */ +.conical-gradient { + background: conic-gradient( + from 180deg at 50% 50%, + #ff6b00 0deg, + #f7ae59 70.5deg, + #3f76ff 151.12deg, + #05c3ff 213deg, + #18914f 289.87deg, + #f6f172 329.25deg, + #ff6b00 360deg + ); +} + +/* progress bar */ +.progress-bar { + fill: currentColor; + color: rgba(var(--color-sidebar-background-100)); +} + +/* lineclamp */ +.lineclamp { + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 1; +} + +/* popover2 styling */ +.bp4-popover2-transition-container { + z-index: 1 !important; +} + +::-webkit-input-placeholder, +::placeholder, +:-ms-input-placeholder { + color: rgb(var(--color-text-400)); +} + +.bp4-overlay-content { + z-index: 555 !important; +} + +.disable-scroll { + overflow: hidden !important; +} diff --git a/turbo.json b/turbo.json index 59bbe741f85..a1c240d9a22 100644 --- a/turbo.json +++ b/turbo.json @@ -32,11 +32,25 @@ ], "pipeline": { "build": { - "dependsOn": ["^build"], - "outputs": [".next/**", "dist/**"] + "dependsOn": [ + "^build" + ], + "outputs": [ + ".next/**", + "dist/**" + ] + }, + "web#dev": { + "cache": false, + "persistent": true, + "dependsOn": [ + "@plane/editor#build" + ] }, "test": { - "dependsOn": ["^build"], + "dependsOn": [ + "^build" + ], "outputs": [] }, "lint": { From f0e246ccfd186455849c0f57895fab2d53bc95ee Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Fri, 22 Sep 2023 13:54:52 +0530 Subject: [PATCH 11/57] reverted back types and fixed tailwind --- packages/editor/src/styles/tailwind.css | 358 ------------------ .../custom-analytics/graph/index.tsx | 1 - web/components/core/activity.tsx | 44 ++- .../core/views/board-view/all-boards.tsx | 2 +- web/components/issues/delete-issue-modal.tsx | 4 +- web/components/issues/description-form.tsx | 8 +- web/components/issues/index.ts | 1 - web/components/issues/main-content.tsx | 4 +- web/components/issues/sub-issues-list.tsx | 251 ------------ web/components/issues/sub-issues/index.ts | 1 + web/components/issues/sub-issues/issue.tsx | 171 +++++++++ .../issues/sub-issues/issues-list.tsx | 84 ++++ .../issues/sub-issues/progressbar.tsx | 25 ++ .../issues/sub-issues/properties.tsx | 204 ++++++++++ web/components/issues/sub-issues/root.tsx | 283 ++++++++++++++ .../profile/profile-issues-view.tsx | 1 - web/components/project/members-select.tsx | 2 +- web/components/ui/product-updates-modal.tsx | 108 +++--- web/components/web-view/add-comment.tsx | 17 +- web/contexts/profile-issues-context.tsx | 7 +- web/helpers/array.helper.ts | 7 +- .../[workspaceSlug]/me/profile/activity.tsx | 8 +- 22 files changed, 888 insertions(+), 703 deletions(-) delete mode 100644 web/components/issues/sub-issues-list.tsx create mode 100644 web/components/issues/sub-issues/index.ts create mode 100644 web/components/issues/sub-issues/issue.tsx create mode 100644 web/components/issues/sub-issues/issues-list.tsx create mode 100644 web/components/issues/sub-issues/progressbar.tsx create mode 100644 web/components/issues/sub-issues/properties.tsx create mode 100644 web/components/issues/sub-issues/root.tsx diff --git a/packages/editor/src/styles/tailwind.css b/packages/editor/src/styles/tailwind.css index 3de1e2c571c..b5c61c95671 100644 --- a/packages/editor/src/styles/tailwind.css +++ b/packages/editor/src/styles/tailwind.css @@ -1,361 +1,3 @@ -@import url("https://fonts.googleapis.com/css2?family=Inter:wght@200;300;400;500;600;700;800&display=swap"); -@import url("https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@48,400,0,0&display=swap"); - @tailwind base; @tailwind components; @tailwind utilities; - -@layer components { - .text-1\.5xl { - font-size: 1.375rem; - line-height: 1.875rem; - } - - .text-2\.5xl { - font-size: 1.75rem; - line-height: 2.25rem; - } -} - -@layer base { - html { - font-family: "Inter", sans-serif; - } - - :root { - color-scheme: light !important; - - --color-primary-10: 236, 241, 255; - --color-primary-20: 217, 228, 255; - --color-primary-30: 197, 214, 255; - --color-primary-40: 178, 200, 255; - --color-primary-50: 159, 187, 255; - --color-primary-60: 140, 173, 255; - --color-primary-70: 121, 159, 255; - --color-primary-80: 101, 145, 255; - --color-primary-90: 82, 132, 255; - --color-primary-100: 63, 118, 255; - --color-primary-200: 57, 106, 230; - --color-primary-300: 50, 94, 204; - --color-primary-400: 44, 83, 179; - --color-primary-500: 38, 71, 153; - --color-primary-600: 32, 59, 128; - --color-primary-700: 25, 47, 102; - --color-primary-800: 19, 35, 76; - --color-primary-900: 13, 24, 51; - - --color-background-100: 255, 255, 255; /* primary bg */ - --color-background-90: 250, 250, 250; /* secondary bg */ - --color-background-80: 245, 245, 245; /* tertiary bg */ - - --color-text-100: 23, 23, 23; /* primary text */ - --color-text-200: 58, 58, 58; /* secondary text */ - --color-text-300: 82, 82, 82; /* tertiary text */ - --color-text-400: 163, 163, 163; /* placeholder text */ - - --color-border-100: 245, 245, 245; /* subtle border= 1 */ - --color-border-200: 229, 229, 229; /* subtle border- 2 */ - --color-border-300: 212, 212, 212; /* strong border- 1 */ - --color-border-400: 185, 185, 185; /* strong border- 2 */ - - --color-shadow-2xs: 0px 0px 1px 0px rgba(23, 23, 23, 0.06), - 0px 1px 2px 0px rgba(23, 23, 23, 0.06), 0px 1px 2px 0px rgba(23, 23, 23, 0.14); - --color-shadow-xs: 0px 1px 2px 0px rgba(0, 0, 0, 0.16), 0px 2px 4px 0px rgba(16, 24, 40, 0.12), - 0px 1px 8px -1px rgba(16, 24, 40, 0.1); - --color-shadow-sm: 0px 1px 4px 0px rgba(0, 0, 0, 0.01), 0px 4px 8px 0px rgba(0, 0, 0, 0.02), - 0px 1px 12px 0px rgba(0, 0, 0, 0.12); - --color-shadow-rg: 0px 3px 6px 0px rgba(0, 0, 0, 0.1), 0px 4px 4px 0px rgba(16, 24, 40, 0.08), - 0px 1px 12px 0px rgba(16, 24, 40, 0.04); - --color-shadow-md: 0px 4px 8px 0px rgba(0, 0, 0, 0.12), 0px 6px 12px 0px rgba(16, 24, 40, 0.12), - 0px 1px 16px 0px rgba(16, 24, 40, 0.12); - --color-shadow-lg: 0px 6px 12px 0px rgba(0, 0, 0, 0.12), 0px 8px 16px 0px rgba(0, 0, 0, 0.12), - 0px 1px 24px 0px rgba(16, 24, 40, 0.12); - --color-shadow-xl: 0px 0px 18px 0px rgba(0, 0, 0, 0.16), 0px 0px 24px 0px rgba(16, 24, 40, 0.16), - 0px 0px 52px 0px rgba(16, 24, 40, 0.16); - --color-shadow-2xl: 0px 8px 16px 0px rgba(0, 0, 0, 0.12), - 0px 12px 24px 0px rgba(16, 24, 40, 0.12), 0px 1px 32px 0px rgba(16, 24, 40, 0.12); - --color-shadow-3xl: 0px 12px 24px 0px rgba(0, 0, 0, 0.12), 0px 16px 32px 0px rgba(0, 0, 0, 0.12), - 0px 1px 48px 0px rgba(16, 24, 40, 0.12); - - --color-sidebar-background-100: var(--color-background-100); /* primary sidebar bg */ - --color-sidebar-background-90: var(--color-background-90); /* secondary sidebar bg */ - --color-sidebar-background-80: var(--color-background-80); /* tertiary sidebar bg */ - - --color-sidebar-text-100: var(--color-text-100); /* primary sidebar text */ - --color-sidebar-text-200: var(--color-text-200); /* secondary sidebar text */ - --color-sidebar-text-300: var(--color-text-300); /* tertiary sidebar text */ - --color-sidebar-text-400: var(--color-text-400); /* sidebar placeholder text */ - - --color-sidebar-border-100: var(--color-border-100); /* subtle sidebar border= 1 */ - --color-sidebar-border-200: var(--color-border-100); /* subtle sidebar border- 2 */ - --color-sidebar-border-300: var(--color-border-100); /* strong sidebar border- 1 */ - --color-sidebar-border-400: var(--color-border-100); /* strong sidebar border- 2 */ - - --color-sidebar-shadow-2xs: var(--color-shadow-2xs); - --color-sidebar-shadow-xs: var(--color-shadow-xs); - --color-sidebar-shadow-sm: var(--color-shadow-sm); - --color-sidebar-shadow-rg: var(--color-shadow-rg); - --color-sidebar-shadow-md: var(--color-shadow-md); - --color-sidebar-shadow-lg: var(--color-shadow-lg); - --color-sidebar-shadow-xl: var(--color-shadow-xl); - --color-sidebar-shadow-2xl: var(--color-shadow-2xl); - --color-sidebar-shadow-3xl: var(--color-shadow-3xl); - } - - [data-theme="light"], - [data-theme="light-contrast"] { - color-scheme: light !important; - - --color-background-100: 255, 255, 255; /* primary bg */ - --color-background-90: 250, 250, 250; /* secondary bg */ - --color-background-80: 245, 245, 245; /* tertiary bg */ - } - - [data-theme="light"] { - --color-text-100: 23, 23, 23; /* primary text */ - --color-text-200: 58, 58, 58; /* secondary text */ - --color-text-300: 82, 82, 82; /* tertiary text */ - --color-text-400: 163, 163, 163; /* placeholder text */ - - --color-border-100: 245, 245, 245; /* subtle border= 1 */ - --color-border-200: 229, 229, 229; /* subtle border- 2 */ - --color-border-300: 212, 212, 212; /* strong border- 1 */ - --color-border-400: 185, 185, 185; /* strong border- 2 */ - } - - [data-theme="light-contrast"] { - --color-text-100: 11, 11, 11; /* primary text */ - --color-text-200: 38, 38, 38; /* secondary text */ - --color-text-300: 58, 58, 58; /* tertiary text */ - --color-text-400: 115, 115, 115; /* placeholder text */ - - --color-border-100: 34, 34, 34; /* subtle border= 1 */ - --color-border-200: 38, 38, 38; /* subtle border- 2 */ - --color-border-300: 46, 46, 46; /* strong border- 1 */ - --color-border-400: 58, 58, 58; /* strong border- 2 */ - } - - [data-theme="dark"], - [data-theme="dark-contrast"] { - color-scheme: dark !important; - - --color-background-100: 7, 7, 7; /* primary bg */ - --color-background-90: 11, 11, 11; /* secondary bg */ - --color-background-80: 23, 23, 23; /* tertiary bg */ - - --color-shadow-2xs: 0px 0px 1px 0px rgba(0, 0, 0, 0.15), 0px 1px 3px 0px rgba(0, 0, 0, 0.5); - --color-shadow-xs: 0px 0px 2px 0px rgba(0, 0, 0, 0.2), 0px 2px 4px 0px rgba(0, 0, 0, 0.5); - --color-shadow-sm: 0px 0px 4px 0px rgba(0, 0, 0, 0.2), 0px 2px 6px 0px rgba(0, 0, 0, 0.5); - --color-shadow-rg: 0px 0px 6px 0px rgba(0, 0, 0, 0.2), 0px 4px 6px 0px rgba(0, 0, 0, 0.5); - --color-shadow-md: 0px 2px 8px 0px rgba(0, 0, 0, 0.2), 0px 4px 8px 0px rgba(0, 0, 0, 0.5); - --color-shadow-lg: 0px 4px 12px 0px rgba(0, 0, 0, 0.25), 0px 4px 10px 0px rgba(0, 0, 0, 0.55); - --color-shadow-xl: 0px 0px 14px 0px rgba(0, 0, 0, 0.25), 0px 6px 10px 0px rgba(0, 0, 0, 0.55); - --color-shadow-2xl: 0px 0px 18px 0px rgba(0, 0, 0, 0.25), 0px 8px 12px 0px rgba(0, 0, 0, 0.6); - --color-shadow-3xl: 0px 4px 24px 0px rgba(0, 0, 0, 0.3), 0px 12px 40px 0px rgba(0, 0, 0, 0.65); - } - - [data-theme="dark"] { - --color-text-100: 229, 229, 229; /* primary text */ - --color-text-200: 163, 163, 163; /* secondary text */ - --color-text-300: 115, 115, 115; /* tertiary text */ - --color-text-400: 82, 82, 82; /* placeholder text */ - - --color-border-100: 34, 34, 34; /* subtle border= 1 */ - --color-border-200: 38, 38, 38; /* subtle border- 2 */ - --color-border-300: 46, 46, 46; /* strong border- 1 */ - --color-border-400: 58, 58, 58; /* strong border- 2 */ - } - - [data-theme="dark-contrast"] { - --color-text-100: 250, 250, 250; /* primary text */ - --color-text-200: 241, 241, 241; /* secondary text */ - --color-text-300: 212, 212, 212; /* tertiary text */ - --color-text-400: 115, 115, 115; /* placeholder text */ - - --color-border-100: 245, 245, 245; /* subtle border= 1 */ - --color-border-200: 229, 229, 229; /* subtle border- 2 */ - --color-border-300: 212, 212, 212; /* strong border- 1 */ - --color-border-400: 185, 185, 185; /* strong border- 2 */ - } - - [data-theme="light"], - [data-theme="dark"], - [data-theme="light-contrast"], - [data-theme="dark-contrast"] { - --color-primary-10: 236, 241, 255; - --color-primary-20: 217, 228, 255; - --color-primary-30: 197, 214, 255; - --color-primary-40: 178, 200, 255; - --color-primary-50: 159, 187, 255; - --color-primary-60: 140, 173, 255; - --color-primary-70: 121, 159, 255; - --color-primary-80: 101, 145, 255; - --color-primary-90: 82, 132, 255; - --color-primary-100: 63, 118, 255; - --color-primary-200: 57, 106, 230; - --color-primary-300: 50, 94, 204; - --color-primary-400: 44, 83, 179; - --color-primary-500: 38, 71, 153; - --color-primary-600: 32, 59, 128; - --color-primary-700: 25, 47, 102; - --color-primary-800: 19, 35, 76; - --color-primary-900: 13, 24, 51; - - --color-sidebar-background-100: var(--color-background-100); /* primary sidebar bg */ - --color-sidebar-background-90: var(--color-background-90); /* secondary sidebar bg */ - --color-sidebar-background-80: var(--color-background-80); /* tertiary sidebar bg */ - - --color-sidebar-text-100: var(--color-text-100); /* primary sidebar text */ - --color-sidebar-text-200: var(--color-text-200); /* secondary sidebar text */ - --color-sidebar-text-300: var(--color-text-300); /* tertiary sidebar text */ - --color-sidebar-text-400: var(--color-text-400); /* sidebar placeholder text */ - - --color-sidebar-border-100: var(--color-border-100); /* subtle sidebar border= 1 */ - --color-sidebar-border-200: var(--color-border-100); /* subtle sidebar border- 2 */ - --color-sidebar-border-300: var(--color-border-100); /* strong sidebar border- 1 */ - --color-sidebar-border-400: var(--color-border-100); /* strong sidebar border- 2 */ - } -} - -* { - margin: 0; - padding: 0; - box-sizing: border-box; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; - font-variant-ligatures: none; - -webkit-font-variant-ligatures: none; - text-rendering: optimizeLegibility; - -moz-osx-font-smoothing: grayscale; - -webkit-font-smoothing: antialiased; -} - -body { - color: rgba(var(--color-text-100)); -} - -/* scrollbar style */ -::-webkit-scrollbar { - display: none; -} - -.horizontal-scroll-enable { - overflow-x: scroll; -} - -.horizontal-scroll-enable::-webkit-scrollbar { - display: block; - height: 7px; - width: 0; -} - -.horizontal-scroll-enable::-webkit-scrollbar-track { - height: 7px; - background-color: rgba(var(--color-background-100)); -} - -.horizontal-scroll-enable::-webkit-scrollbar-thumb { - border-radius: 5px; - background-color: rgba(var(--color-background-80)); -} - -.vertical-scroll-enable::-webkit-scrollbar { - display: block; - width: 5px; -} - -.vertical-scroll-enable::-webkit-scrollbar-track { - width: 5px; -} - -.vertical-scroll-enable::-webkit-scrollbar-thumb { - border-radius: 5px; - background-color: rgba(var(--color-background-90)); -} -/* end scrollbar style */ - -.tags-input-container { - border: 2px solid #000; - padding: 0.5em; - border-radius: 3px; - width: min(80vw, 600px); - margin-top: 1em; - display: flex; - align-items: center; - flex-wrap: wrap; - gap: 0.5em; -} - -.tag-item { - background-color: rgb(218, 216, 216); - display: inline-block; - padding: 0.5em 0.75em; - border-radius: 20px; -} -.tag-item .close { - height: 20px; - width: 20px; - background-color: rgb(48, 48, 48); - color: #fff; - border-radius: 50%; - display: inline-flex; - justify-content: center; - align-items: center; - margin-left: 0.5em; - font-size: 18px; - cursor: pointer; -} - -.tags-input { - flex-grow: 1; - padding: 0.5em 0; - border: none; - outline: none; -} - -/* emoji icon picker */ -.conical-gradient { - background: conic-gradient( - from 180deg at 50% 50%, - #ff6b00 0deg, - #f7ae59 70.5deg, - #3f76ff 151.12deg, - #05c3ff 213deg, - #18914f 289.87deg, - #f6f172 329.25deg, - #ff6b00 360deg - ); -} - -/* progress bar */ -.progress-bar { - fill: currentColor; - color: rgba(var(--color-sidebar-background-100)); -} - -/* lineclamp */ -.lineclamp { - overflow: hidden; - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 1; -} - -/* popover2 styling */ -.bp4-popover2-transition-container { - z-index: 1 !important; -} - -::-webkit-input-placeholder, -::placeholder, -:-ms-input-placeholder { - color: rgb(var(--color-text-400)); -} - -.bp4-overlay-content { - z-index: 555 !important; -} - -.disable-scroll { - overflow: hidden !important; -} diff --git a/web/components/analytics/custom-analytics/graph/index.tsx b/web/components/analytics/custom-analytics/graph/index.tsx index 349f9884db0..733d1743729 100644 --- a/web/components/analytics/custom-analytics/graph/index.tsx +++ b/web/components/analytics/custom-analytics/graph/index.tsx @@ -9,7 +9,6 @@ import { findStringWithMostCharacters } from "helpers/array.helper"; import { generateBarColor } from "helpers/analytics.helper"; // types import { IAnalyticsParams, IAnalyticsResponse } from "types"; -// constants type Props = { analytics: IAnalyticsResponse; diff --git a/web/components/core/activity.tsx b/web/components/core/activity.tsx index 7c2798e7a92..c76f1aece86 100644 --- a/web/components/core/activity.tsx +++ b/web/components/core/activity.tsx @@ -1,5 +1,9 @@ import { useRouter } from "next/router"; +import useSWR from "swr"; + +// services +import issuesService from "services/issues.service"; // icons import { Icon, Tooltip } from "components/ui"; import { CopyPlus } from "lucide-react"; @@ -10,6 +14,8 @@ import { renderShortDateWithYearFormat } from "helpers/date-time.helper"; import { capitalizeFirstLetter } from "helpers/string.helper"; // types import { IIssueActivity } from "types"; +// fetch-keys +import { WORKSPACE_LABELS } from "constants/fetch-keys"; const IssueLink = ({ activity }: { activity: IIssueActivity }) => { const router = useRouter(); @@ -52,6 +58,26 @@ const UserLink = ({ activity }: { activity: IIssueActivity }) => { ); }; +const LabelPill = ({ labelId }: { labelId: string }) => { + const router = useRouter(); + const { workspaceSlug } = router.query; + + const { data: labels } = useSWR( + workspaceSlug ? WORKSPACE_LABELS(workspaceSlug.toString()) : null, + workspaceSlug ? () => issuesService.getWorkspaceLabels(workspaceSlug.toString()) : null + ); + + return ( + l.id === labelId)?.color ?? "#000000", + }} + aria-hidden="true" + /> + ); +}; + const activityDetails: { [key: string]: { message: ( @@ -325,14 +351,8 @@ const activityDetails: { return ( <> added a new label{" "} - -
, - 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) => { - editor.chain().focus().deleteRange(range).toggleOrderedList().run(); - }, - }, - { - title: "Quote", - description: "Capture a quote.", - searchTerms: ["blockquote"], - icon: , - command: ({ editor, range }: CommandProps) => - 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, 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, - setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void -) => - Command.configure({ - suggestion: { - items: getSuggestionItems(workspaceSlug, setIsSubmitting), - render: renderItems, - }, - }); - -export default SlashCommand; diff --git a/space/components/tiptap/table-menu/InsertBottomTableIcon.tsx b/space/components/tiptap/table-menu/InsertBottomTableIcon.tsx deleted file mode 100644 index 0e42ba64824..00000000000 --- a/space/components/tiptap/table-menu/InsertBottomTableIcon.tsx +++ /dev/null @@ -1,16 +0,0 @@ -const InsertBottomTableIcon = (props: any) => ( - - - -); - -export default InsertBottomTableIcon; diff --git a/space/components/tiptap/table-menu/InsertLeftTableIcon.tsx b/space/components/tiptap/table-menu/InsertLeftTableIcon.tsx deleted file mode 100644 index 1fd75fe8754..00000000000 --- a/space/components/tiptap/table-menu/InsertLeftTableIcon.tsx +++ /dev/null @@ -1,15 +0,0 @@ -const InsertLeftTableIcon = (props: any) => ( - - - -); -export default InsertLeftTableIcon; diff --git a/space/components/tiptap/table-menu/InsertRightTableIcon.tsx b/space/components/tiptap/table-menu/InsertRightTableIcon.tsx deleted file mode 100644 index 1a65709694b..00000000000 --- a/space/components/tiptap/table-menu/InsertRightTableIcon.tsx +++ /dev/null @@ -1,16 +0,0 @@ -const InsertRightTableIcon = (props: any) => ( - - - -); - -export default InsertRightTableIcon; diff --git a/space/components/tiptap/table-menu/InsertTopTableIcon.tsx b/space/components/tiptap/table-menu/InsertTopTableIcon.tsx deleted file mode 100644 index 8f04f4f6126..00000000000 --- a/space/components/tiptap/table-menu/InsertTopTableIcon.tsx +++ /dev/null @@ -1,15 +0,0 @@ -const InsertTopTableIcon = (props: any) => ( - - - -); -export default InsertTopTableIcon; diff --git a/space/components/tiptap/table-menu/index.tsx b/space/components/tiptap/table-menu/index.tsx deleted file mode 100644 index 94f9c0f8d87..00000000000 --- a/space/components/tiptap/table-menu/index.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import { useState, useEffect } from "react"; -import { Rows, Columns, ToggleRight } from "lucide-react"; -import { cn } from "../utils"; -import { Tooltip } from "components/ui"; -import InsertLeftTableIcon from "./InsertLeftTableIcon"; -import InsertRightTableIcon from "./InsertRightTableIcon"; -import InsertTopTableIcon from "./InsertTopTableIcon"; -import InsertBottomTableIcon from "./InsertBottomTableIcon"; - -interface TableMenuItem { - command: () => void; - icon: any; - key: string; - name: string; -} - -export const findTableAncestor = (node: Node | null): HTMLTableElement | null => { - while (node !== null && node.nodeName !== "TABLE") { - node = node.parentNode; - } - return node as HTMLTableElement; -}; - -export const TableMenu = ({ editor }: { editor: any }) => { - const [tableLocation, setTableLocation] = useState({ bottom: 0, left: 0 }); - const isOpen = editor?.isActive("table"); - - const items: TableMenuItem[] = [ - { - command: () => editor.chain().focus().addColumnBefore().run(), - icon: InsertLeftTableIcon, - key: "insert-column-left", - name: "Insert 1 column left", - }, - { - command: () => editor.chain().focus().addColumnAfter().run(), - icon: InsertRightTableIcon, - key: "insert-column-right", - name: "Insert 1 column right", - }, - { - command: () => editor.chain().focus().addRowBefore().run(), - icon: InsertTopTableIcon, - key: "insert-row-above", - name: "Insert 1 row above", - }, - { - command: () => editor.chain().focus().addRowAfter().run(), - icon: InsertBottomTableIcon, - key: "insert-row-below", - name: "Insert 1 row below", - }, - { - command: () => editor.chain().focus().deleteColumn().run(), - icon: Columns, - key: "delete-column", - name: "Delete column", - }, - { - command: () => editor.chain().focus().deleteRow().run(), - icon: Rows, - key: "delete-row", - name: "Delete row", - }, - { - command: () => editor.chain().focus().toggleHeaderRow().run(), - icon: ToggleRight, - key: "toggle-header-row", - name: "Toggle header row", - }, - ]; - - useEffect(() => { - if (!window) return; - - const handleWindowClick = () => { - const selection: any = window?.getSelection(); - - if (selection.rangeCount !== 0) { - const range = selection.getRangeAt(0); - const tableNode = findTableAncestor(range.startContainer); - - let parent = tableNode?.parentElement; - - if (tableNode) { - const tableRect = tableNode.getBoundingClientRect(); - const tableCenter = tableRect.left + tableRect.width / 2; - const menuWidth = 45; - const menuLeft = tableCenter - menuWidth / 2; - const tableBottom = tableRect.bottom; - - setTableLocation({ bottom: tableBottom, left: menuLeft }); - - while (parent) { - if (!parent.classList.contains("disable-scroll")) - parent.classList.add("disable-scroll"); - parent = parent.parentElement; - } - } else { - const scrollDisabledContainers = document.querySelectorAll(".disable-scroll"); - - scrollDisabledContainers.forEach((container) => { - container.classList.remove("disable-scroll"); - }); - } - } - }; - - window.addEventListener("click", handleWindowClick); - - return () => { - window.removeEventListener("click", handleWindowClick); - }; - }, [tableLocation, editor]); - - return ( -
- {items.map((item, index) => ( - - - - ))} -
- ); -}; diff --git a/space/components/tiptap/utils.ts b/space/components/tiptap/utils.ts deleted file mode 100644 index a5ef193506d..00000000000 --- a/space/components/tiptap/utils.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { clsx, type ClassValue } from "clsx"; -import { twMerge } from "tailwind-merge"; - -export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)); -} diff --git a/space/package.json b/space/package.json index dc625737668..da71526404f 100644 --- a/space/package.json +++ b/space/package.json @@ -17,26 +17,6 @@ "@heroicons/react": "^2.0.12", "@mui/icons-material": "^5.14.1", "@mui/material": "^5.14.1", - "@tiptap/extension-code-block-lowlight": "^2.0.4", - "@tiptap/extension-color": "^2.0.4", - "@tiptap/extension-gapcursor": "^2.1.7", - "@tiptap/extension-highlight": "^2.0.4", - "@tiptap/extension-horizontal-rule": "^2.0.4", - "@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", - "@tiptap/extension-underline": "^2.0.4", - "@tiptap/pm": "^2.0.4", - "@tiptap/react": "^2.0.4", - "@tiptap/starter-kit": "^2.0.4", - "@tiptap/suggestion": "^2.0.4", "axios": "^1.3.4", "clsx": "^2.0.0", "js-cookie": "^3.0.1", @@ -51,12 +31,9 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-hook-form": "^7.38.0", - "react-moveable": "^0.54.1", "swr": "^2.2.2", "tailwind-merge": "^1.14.0", - "tiptap-markdown": "^0.8.2", "typescript": "4.9.5", - "use-debounce": "^9.0.4", "uuid": "^9.0.0", "@plane/editor": "*" }, diff --git a/web/components/tiptap/bubble-menu/index.tsx b/web/components/tiptap/bubble-menu/index.tsx deleted file mode 100644 index 217317ea105..00000000000 --- a/web/components/tiptap/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 "../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/web/components/tiptap/bubble-menu/link-selector.tsx b/web/components/tiptap/bubble-menu/link-selector.tsx deleted file mode 100644 index 559521db66f..00000000000 --- a/web/components/tiptap/bubble-menu/link-selector.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import { Editor } from "@tiptap/core"; -import { Check, Trash } from "lucide-react"; -import { Dispatch, FC, SetStateAction, useCallback, useEffect, useRef } from "react"; -import { cn } from "../utils"; -import isValidHttpUrl from "./utils/link-validator"; -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/web/components/tiptap/bubble-menu/node-selector.tsx b/web/components/tiptap/bubble-menu/node-selector.tsx deleted file mode 100644 index 34d40ec06d5..00000000000 --- a/web/components/tiptap/bubble-menu/node-selector.tsx +++ /dev/null @@ -1,130 +0,0 @@ -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 "."; -import { cn } from "../utils"; - -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/web/components/tiptap/bubble-menu/utils/link-validator.tsx b/web/components/tiptap/bubble-menu/utils/link-validator.tsx deleted file mode 100644 index 9af366c0266..00000000000 --- a/web/components/tiptap/bubble-menu/utils/link-validator.tsx +++ /dev/null @@ -1,11 +0,0 @@ -export default function isValidHttpUrl(string: string): boolean { - let url; - - try { - url = new URL(string); - } catch (_) { - return false; - } - - return url.protocol === "http:" || url.protocol === "https:"; -} diff --git a/web/components/tiptap/extensions/image-resize.tsx b/web/components/tiptap/extensions/image-resize.tsx deleted file mode 100644 index 448b8811cc1..00000000000 --- a/web/components/tiptap/extensions/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/web/components/tiptap/extensions/index.tsx b/web/components/tiptap/extensions/index.tsx deleted file mode 100644 index 8ad4e07b4d5..00000000000 --- a/web/components/tiptap/extensions/index.tsx +++ /dev/null @@ -1,149 +0,0 @@ -import StarterKit from "@tiptap/starter-kit"; -import HorizontalRule from "@tiptap/extension-horizontal-rule"; -import TiptapLink from "@tiptap/extension-link"; -import Placeholder from "@tiptap/extension-placeholder"; -import TiptapUnderline from "@tiptap/extension-underline"; -import TextStyle from "@tiptap/extension-text-style"; -import { Color } from "@tiptap/extension-color"; -import TaskItem from "@tiptap/extension-task-item"; -import TaskList from "@tiptap/extension-task-list"; -import { Markdown } from "tiptap-markdown"; -import Highlight from "@tiptap/extension-highlight"; -import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight"; -import { lowlight } from "lowlight/lib/core"; -import SlashCommand from "../slash-command"; -import { InputRule } from "@tiptap/core"; -import Gapcursor from "@tiptap/extension-gapcursor"; - -import ts from "highlight.js/lib/languages/typescript"; - -import "highlight.js/styles/github-dark.css"; -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); - -export const TiptapExtensions = ( - workspaceSlug: string, - setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void -) => [ - StarterKit.configure({ - bulletList: { - HTMLAttributes: { - class: "list-disc list-outside leading-3 -mt-2", - }, - }, - orderedList: { - HTMLAttributes: { - class: "list-decimal list-outside leading-3 -mt-2", - }, - }, - listItem: { - HTMLAttributes: { - class: "leading-normal -mb-2", - }, - }, - blockquote: { - HTMLAttributes: { - class: "border-l-4 border-custom-border-300", - }, - }, - code: { - HTMLAttributes: { - class: - "rounded-md bg-custom-primary-30 mx-1 px-1 py-1 font-mono font-medium text-custom-text-1000", - spellcheck: "false", - }, - }, - codeBlock: false, - horizontalRule: false, - dropcursor: { - color: "rgba(var(--color-text-100))", - width: 2, - }, - gapcursor: false, - }), - CodeBlockLowlight.configure({ - lowlight, - }), - HorizontalRule.extend({ - addInputRules() { - return [ - new InputRule({ - find: /^(?:---|—-|___\s|\*\*\*\s)$/, - handler: ({ state, range, commands }) => { - commands.splitBlock(); - - const attributes = {}; - const { tr } = state; - const start = range.from; - const end = range.to; - // @ts-ignore - tr.replaceWith(start - 1, end, this.type.create(attributes)); - }, - }), - ]; - }, - }).configure({ - HTMLAttributes: { - class: "mb-6 border-t border-custom-border-300", - }, - }), - Gapcursor, - TiptapLink.configure({ - protocols: ["http", "https"], - validate: (url) => isValidHttpUrl(url), - HTMLAttributes: { - class: - "text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer", - }, - }), - UpdatedImage.configure({ - HTMLAttributes: { - class: "rounded-lg border border-custom-border-300", - }, - }), - Placeholder.configure({ - placeholder: ({ node }) => { - if (node.type.name === "heading") { - return `Heading ${node.attrs.level}`; - } - if (node.type.name === "image" || node.type.name === "table") { - return ""; - } - - return "Press '/' for commands..."; - }, - includeChildren: true, - }), - SlashCommand(workspaceSlug, setIsSubmitting), - TiptapUnderline, - TextStyle, - Color, - Highlight.configure({ - multicolor: true, - }), - TaskList.configure({ - HTMLAttributes: { - class: "not-prose pl-2", - }, - }), - TaskItem.configure({ - HTMLAttributes: { - class: "flex items-start my-4", - }, - nested: true, - }), - Markdown.configure({ - html: true, - transformCopiedText: true, - }), - Table, - TableHeader, - CustomTableCell, - TableRow, - ]; diff --git a/web/components/tiptap/extensions/table/table-cell.ts b/web/components/tiptap/extensions/table/table-cell.ts deleted file mode 100644 index 643cb8c64a7..00000000000 --- a/web/components/tiptap/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/web/components/tiptap/extensions/table/table-header.ts b/web/components/tiptap/extensions/table/table-header.ts deleted file mode 100644 index f23aa93ef55..00000000000 --- a/web/components/tiptap/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/web/components/tiptap/extensions/table/table.ts b/web/components/tiptap/extensions/table/table.ts deleted file mode 100644 index 9b727bb51bd..00000000000 --- a/web/components/tiptap/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/web/components/tiptap/extensions/updated-image.tsx b/web/components/tiptap/extensions/updated-image.tsx deleted file mode 100644 index b620509535e..00000000000 --- a/web/components/tiptap/extensions/updated-image.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import Image from "@tiptap/extension-image"; -import TrackImageDeletionPlugin from "../plugins/delete-image"; -import UploadImagesPlugin from "../plugins/upload-image"; - -const UpdatedImage = Image.extend({ - addProseMirrorPlugins() { - return [UploadImagesPlugin(), TrackImageDeletionPlugin()]; - }, - addAttributes() { - return { - ...this.parent?.(), - width: { - default: "35%", - }, - height: { - default: null, - }, - }; - }, -}); - -export default UpdatedImage; diff --git a/web/components/tiptap/index.tsx b/web/components/tiptap/index.tsx deleted file mode 100644 index 39a4edbb765..00000000000 --- a/web/components/tiptap/index.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import { useImperativeHandle, useRef, forwardRef } from "react"; -import { useEditor, EditorContent, Editor } from "@tiptap/react"; -import { useDebouncedCallback } from "use-debounce"; -// components -import { EditorBubbleMenu } from "./bubble-menu"; -import { TiptapExtensions } from "./extensions"; -import { TiptapEditorProps } from "./props"; -import { ImageResizer } from "./extensions/image-resize"; -import { TableMenu } from "./table-menu"; - -export interface ITipTapRichTextEditor { - value: string; - noBorder?: boolean; - borderOnFocus?: boolean; - customClassName?: string; - editorContentCustomClassNames?: string; - onChange?: (json: any, html: string) => void; - setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void; - setShouldShowAlert?: (showAlert: boolean) => void; - workspaceSlug: string; - editable?: boolean; - forwardedRef?: any; - debouncedUpdatesEnabled?: boolean; -} - -const Tiptap = (props: ITipTapRichTextEditor) => { - const { - onChange, - debouncedUpdatesEnabled, - forwardedRef, - editable, - setIsSubmitting, - setShouldShowAlert, - editorContentCustomClassNames, - value, - noBorder, - workspaceSlug, - borderOnFocus, - customClassName, - } = props; - - const editor = useEditor({ - editable: editable ?? true, - editorProps: TiptapEditorProps(workspaceSlug, setIsSubmitting), - extensions: TiptapExtensions(workspaceSlug, setIsSubmitting), - content: (typeof value === "string" && value.trim() !== "") ? value : "

", - onUpdate: async ({ editor }) => { - // for instant feedback loop - setIsSubmitting?.("submitting"); - setShouldShowAlert?.(true); - if (debouncedUpdatesEnabled) { - debouncedUpdates({ onChange, editor }); - } else { - onChange?.(editor.getJSON(), editor.getHTML()); - } - }, - }); - - const editorRef: React.MutableRefObject = useRef(null); - - useImperativeHandle(forwardedRef, () => ({ - clearEditor: () => { - editorRef.current?.commands.clearContent(); - }, - setEditorValue: (content: string) => { - editorRef.current?.commands.setContent(content); - }, - })); - - const debouncedUpdates = useDebouncedCallback(async ({ onChange, editor }) => { - setTimeout(async () => { - if (onChange) { - onChange(editor.getJSON(), editor.getHTML()); - } - }, 500); - }, 1000); - - const editorClassNames = `relative w-full max-w-full sm:rounded-lg mt-2 p-3 relative focus:outline-none rounded-md - ${noBorder ? "" : "border border-custom-border-200"} ${ - borderOnFocus ? "focus:border border-custom-border-300" : "focus:border-0" - } ${customClassName}`; - - if (!editor) return null; - editorRef.current = editor; - - return ( -
{ - editor?.chain().focus().run(); - }} - className={`tiptap-editor-container cursor-text ${editorClassNames}`} - > - {editor && } -
- - - {editor?.isActive("image") && } -
-
- ); -}; - -const TipTapEditor = forwardRef((props, ref) => ( - -)); - -TipTapEditor.displayName = "TipTapEditor"; - -export { TipTapEditor }; diff --git a/web/components/tiptap/plugins/delete-image.tsx b/web/components/tiptap/plugins/delete-image.tsx deleted file mode 100644 index fdf515ccc99..00000000000 --- a/web/components/tiptap/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 fileService from "services/file.service"; - -const deleteKey = new PluginKey("delete-image"); -const IMAGE_NODE_TYPE = "image"; - -interface ImageNode extends ProseMirrorNode { - attrs: { - src: string; - id: string; - }; -} - -const TrackImageDeletionPlugin = (): 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); - }); - }); - - return null; - }, - }); - -export default TrackImageDeletionPlugin; - -async function onNodeDeleted(src: string): Promise { - try { - const assetUrlWithWorkspaceId = new URL(src).pathname.substring(1); - const resStatus = await fileService.deleteImage(assetUrlWithWorkspaceId); - if (resStatus === 204) { - console.log("Image deleted successfully"); - } - } catch (error) { - console.error("Error deleting image: ", error); - } -} diff --git a/web/components/tiptap/plugins/upload-image.tsx b/web/components/tiptap/plugins/upload-image.tsx deleted file mode 100644 index bc0acdc540d..00000000000 --- a/web/components/tiptap/plugins/upload-image.tsx +++ /dev/null @@ -1,127 +0,0 @@ -import { EditorState, Plugin, PluginKey } from "@tiptap/pm/state"; -import { Decoration, DecorationSet, EditorView } from "@tiptap/pm/view"; -import fileService from "services/file.service"; - -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, - 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); - 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): 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) => { - const imageUrl = await fileService - .uploadFile(workspaceSlug, formData) - .then((response) => response.asset); - - const image = new Image(); - image.src = imageUrl; - image.onload = () => { - resolve(imageUrl); - }; - }); - } catch (error) { - console.log(error); - return Promise.reject(error); - } -}; diff --git a/web/components/tiptap/props.tsx b/web/components/tiptap/props.tsx deleted file mode 100644 index 8233e3ab4ab..00000000000 --- a/web/components/tiptap/props.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { EditorProps } from "@tiptap/pm/view"; -import { startImageUpload } from "./plugins/upload-image"; -import { findTableAncestor } from "./table-menu"; - -export function TiptapEditorProps( - workspaceSlug: string, - 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, 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, setIsSubmitting); - } - return true; - } - return false; - }, - }; -} diff --git a/web/components/tiptap/slash-command/index.tsx b/web/components/tiptap/slash-command/index.tsx deleted file mode 100644 index 46bf5ea5a34..00000000000 --- a/web/components/tiptap/slash-command/index.tsx +++ /dev/null @@ -1,365 +0,0 @@ -import React, { 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 "../plugins/upload-image"; -import { cn } from "../utils"; - -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, - 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) => { - 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) => { - editor.chain().focus().deleteRange(range).toggleOrderedList().run(); - }, - }, - { - title: "Quote", - description: "Capture a quote.", - searchTerms: ["blockquote"], - icon: , - command: ({ editor, range }: CommandProps) => - 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, 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, - setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void -) => - Command.configure({ - suggestion: { - items: getSuggestionItems(workspaceSlug, setIsSubmitting), - render: renderItems, - }, - }); - -export default SlashCommand; diff --git a/web/components/tiptap/table-menu/InsertBottomTableIcon.tsx b/web/components/tiptap/table-menu/InsertBottomTableIcon.tsx deleted file mode 100644 index 0e42ba64824..00000000000 --- a/web/components/tiptap/table-menu/InsertBottomTableIcon.tsx +++ /dev/null @@ -1,16 +0,0 @@ -const InsertBottomTableIcon = (props: any) => ( - - - -); - -export default InsertBottomTableIcon; diff --git a/web/components/tiptap/table-menu/InsertLeftTableIcon.tsx b/web/components/tiptap/table-menu/InsertLeftTableIcon.tsx deleted file mode 100644 index 1fd75fe8754..00000000000 --- a/web/components/tiptap/table-menu/InsertLeftTableIcon.tsx +++ /dev/null @@ -1,15 +0,0 @@ -const InsertLeftTableIcon = (props: any) => ( - - - -); -export default InsertLeftTableIcon; diff --git a/web/components/tiptap/table-menu/InsertRightTableIcon.tsx b/web/components/tiptap/table-menu/InsertRightTableIcon.tsx deleted file mode 100644 index 1a65709694b..00000000000 --- a/web/components/tiptap/table-menu/InsertRightTableIcon.tsx +++ /dev/null @@ -1,16 +0,0 @@ -const InsertRightTableIcon = (props: any) => ( - - - -); - -export default InsertRightTableIcon; diff --git a/web/components/tiptap/table-menu/InsertTopTableIcon.tsx b/web/components/tiptap/table-menu/InsertTopTableIcon.tsx deleted file mode 100644 index 8f04f4f6126..00000000000 --- a/web/components/tiptap/table-menu/InsertTopTableIcon.tsx +++ /dev/null @@ -1,15 +0,0 @@ -const InsertTopTableIcon = (props: any) => ( - - - -); -export default InsertTopTableIcon; diff --git a/web/components/tiptap/table-menu/index.tsx b/web/components/tiptap/table-menu/index.tsx deleted file mode 100644 index 94f9c0f8d87..00000000000 --- a/web/components/tiptap/table-menu/index.tsx +++ /dev/null @@ -1,143 +0,0 @@ -import { useState, useEffect } from "react"; -import { Rows, Columns, ToggleRight } from "lucide-react"; -import { cn } from "../utils"; -import { Tooltip } from "components/ui"; -import InsertLeftTableIcon from "./InsertLeftTableIcon"; -import InsertRightTableIcon from "./InsertRightTableIcon"; -import InsertTopTableIcon from "./InsertTopTableIcon"; -import InsertBottomTableIcon from "./InsertBottomTableIcon"; - -interface TableMenuItem { - command: () => void; - icon: any; - key: string; - name: string; -} - -export const findTableAncestor = (node: Node | null): HTMLTableElement | null => { - while (node !== null && node.nodeName !== "TABLE") { - node = node.parentNode; - } - return node as HTMLTableElement; -}; - -export const TableMenu = ({ editor }: { editor: any }) => { - const [tableLocation, setTableLocation] = useState({ bottom: 0, left: 0 }); - const isOpen = editor?.isActive("table"); - - const items: TableMenuItem[] = [ - { - command: () => editor.chain().focus().addColumnBefore().run(), - icon: InsertLeftTableIcon, - key: "insert-column-left", - name: "Insert 1 column left", - }, - { - command: () => editor.chain().focus().addColumnAfter().run(), - icon: InsertRightTableIcon, - key: "insert-column-right", - name: "Insert 1 column right", - }, - { - command: () => editor.chain().focus().addRowBefore().run(), - icon: InsertTopTableIcon, - key: "insert-row-above", - name: "Insert 1 row above", - }, - { - command: () => editor.chain().focus().addRowAfter().run(), - icon: InsertBottomTableIcon, - key: "insert-row-below", - name: "Insert 1 row below", - }, - { - command: () => editor.chain().focus().deleteColumn().run(), - icon: Columns, - key: "delete-column", - name: "Delete column", - }, - { - command: () => editor.chain().focus().deleteRow().run(), - icon: Rows, - key: "delete-row", - name: "Delete row", - }, - { - command: () => editor.chain().focus().toggleHeaderRow().run(), - icon: ToggleRight, - key: "toggle-header-row", - name: "Toggle header row", - }, - ]; - - useEffect(() => { - if (!window) return; - - const handleWindowClick = () => { - const selection: any = window?.getSelection(); - - if (selection.rangeCount !== 0) { - const range = selection.getRangeAt(0); - const tableNode = findTableAncestor(range.startContainer); - - let parent = tableNode?.parentElement; - - if (tableNode) { - const tableRect = tableNode.getBoundingClientRect(); - const tableCenter = tableRect.left + tableRect.width / 2; - const menuWidth = 45; - const menuLeft = tableCenter - menuWidth / 2; - const tableBottom = tableRect.bottom; - - setTableLocation({ bottom: tableBottom, left: menuLeft }); - - while (parent) { - if (!parent.classList.contains("disable-scroll")) - parent.classList.add("disable-scroll"); - parent = parent.parentElement; - } - } else { - const scrollDisabledContainers = document.querySelectorAll(".disable-scroll"); - - scrollDisabledContainers.forEach((container) => { - container.classList.remove("disable-scroll"); - }); - } - } - }; - - window.addEventListener("click", handleWindowClick); - - return () => { - window.removeEventListener("click", handleWindowClick); - }; - }, [tableLocation, editor]); - - return ( -
- {items.map((item, index) => ( - - - - ))} -
- ); -}; diff --git a/web/components/tiptap/utils.ts b/web/components/tiptap/utils.ts deleted file mode 100644 index a5ef193506d..00000000000 --- a/web/components/tiptap/utils.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { clsx, type ClassValue } from "clsx"; -import { twMerge } from "tailwind-merge"; - -export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)); -} diff --git a/web/package.json b/web/package.json index 4682e0f3daa..eab756c18a6 100644 --- a/web/package.json +++ b/web/package.json @@ -27,26 +27,6 @@ "@nivo/scatterplot": "0.80.0", "@sentry/nextjs": "^7.36.0", "@plane/editor": "*", - "@tiptap/extension-code-block-lowlight": "^2.0.4", - "@tiptap/extension-color": "^2.0.4", - "@tiptap/extension-gapcursor": "^2.1.7", - "@tiptap/extension-highlight": "^2.0.4", - "@tiptap/extension-horizontal-rule": "^2.0.4", - "@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", - "@tiptap/extension-underline": "^2.0.4", - "@tiptap/pm": "^2.0.4", - "@tiptap/react": "^2.0.4", - "@tiptap/starter-kit": "^2.0.4", - "@tiptap/suggestion": "^2.0.4", "@types/lodash.debounce": "^4.0.7", "@types/react-datepicker": "^4.8.0", "axios": "^1.1.3", @@ -74,12 +54,9 @@ "react-markdown": "^8.0.7", "react-moveable": "^0.54.1", "sharp": "^0.32.1", - "sonner": "^0.6.2", "swr": "^2.1.3", "tailwind-merge": "^1.14.0", - "tiptap-markdown": "^0.8.2", "tlds": "^1.238.0", - "use-debounce": "^9.0.4", "uuid": "^9.0.0" }, "devDependencies": { From 9079fa476624a45f8f6db92924478201867cb3cb Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Fri, 22 Sep 2023 17:35:08 +0530 Subject: [PATCH 14/57] improved dev experience to build the tiptap package before starting dev server --- turbo.json | 5 ++++- web/package.json | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/turbo.json b/turbo.json index a1c240d9a22..e7a4a08d590 100644 --- a/turbo.json +++ b/turbo.json @@ -40,7 +40,7 @@ "dist/**" ] }, - "web#dev": { + "web#develop": { "cache": false, "persistent": true, "dependsOn": [ @@ -59,6 +59,9 @@ "dev": { "cache": false }, + "develop": { + "cache": false + }, "start": { "cache": false }, diff --git a/web/package.json b/web/package.json index eab756c18a6..8e4629242e0 100644 --- a/web/package.json +++ b/web/package.json @@ -3,7 +3,8 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "next dev --port 3000", + "dev": "turbo run develop", + "develop": "next dev --port 3000", "build": "next build", "start": "next start", "lint": "next lint" From cbb1c1884f18d8a84262bf3172172fc90cc31c19 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Fri, 22 Sep 2023 18:07:07 +0530 Subject: [PATCH 15/57] resolved lock life and missing deps --- packages/editor/package.json | 3 ++- yarn.lock | 50 +++++++++++++++--------------------- 2 files changed, 22 insertions(+), 31 deletions(-) diff --git a/packages/editor/package.json b/packages/editor/package.json index c87317af66f..990d306aa61 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -27,6 +27,7 @@ "@blueprintjs/popover2": "^2.0.10", "@tiptap/core": "^2.1.7", "@tiptap/extension-code-block-lowlight": "^2.0.4", + "@tiptap/extension-color": "^2.1.11", "@tiptap/extension-highlight": "^2.1.7", "@tiptap/extension-horizontal-rule": "^2.1.7", "@tiptap/extension-image": "^2.1.7", @@ -38,7 +39,7 @@ "@tiptap/extension-table-row": "^2.1.6", "@tiptap/extension-task-item": "^2.1.7", "@tiptap/extension-task-list": "^2.1.7", - "@tiptap/extension-text-style": "^2.1.7", + "@tiptap/extension-text-style": "^2.1.11", "@tiptap/extension-underline": "^2.1.7", "@tiptap/pm": "^2.1.7", "@tiptap/react": "^2.1.7", diff --git a/yarn.lock b/yarn.lock index a6e284a2802..c9f0cef14b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2377,10 +2377,10 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.1.10.tgz#704798f90a32d6166ce96dc65ef4a541f424f895" integrity sha512-1yy/kR0FAeMkDdAt1LW/FH6vlyZLqLZqY6BM+wBCiGrr+XeA5FTXih9iT/4gbTRuIzG0EPqx18nvroG7hUsWBg== -"@tiptap/extension-color@^2.0.4": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-color/-/extension-color-2.1.10.tgz#5941f40a0418f3bc2bd52f172957be2e4e8ce3d6" - integrity sha512-ZBHi/4+bT3PbC/PtZFF6lc1QbnhUYBLRd4o6AHbtNqBFVcagbRUeiyxJg5xXQa/Ar9eR3NPkG0y5WY/kRxB9Bg== +"@tiptap/extension-color@^2.1.11": + version "2.1.11" + resolved "https://registry.yarnpkg.com/@tiptap/extension-color/-/extension-color-2.1.11.tgz#be6989bb2d6630fc8f8e3c81add6fdfe1b77c790" + integrity sha512-xfSfZRnNd40YtFfrXvzpGa2OZsRAZapq0Ce09q7bCEpudhiD7yIIVOjOjggagllOFnafKTwKkFaDLIA0K0eIwg== "@tiptap/extension-document@^2.1.10": version "2.1.10" @@ -2399,7 +2399,7 @@ dependencies: tippy.js "^6.3.7" -"@tiptap/extension-gapcursor@^2.1.10", "@tiptap/extension-gapcursor@^2.1.7": +"@tiptap/extension-gapcursor@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.1.10.tgz#712853ce82642108e50a37014d585ff72af6758d" integrity sha512-WSBT9X7dzg0HyMoMP/Yyxl28QwIJO90YzobI9z5mav86BQv7C5wU0fQSpbpAbsN3s7lxKhPwNrXkwkpnXT4ZCA== @@ -2414,7 +2414,7 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.1.10.tgz#1b32726551466c29987861181966e5675417b28c" integrity sha512-1OgmrRPMcY52WI7I4799xd4eIsEX/bI813B8mZvNYXLzZI75pLW1hmz1mUvBYyMwlcek74zVTGYgPy11o+2JEg== -"@tiptap/extension-highlight@^2.0.4", "@tiptap/extension-highlight@^2.1.7": +"@tiptap/extension-highlight@^2.1.7": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.1.10.tgz#8d94db01a2324e0ce380e6e7515fa0bc6004d9b9" integrity sha512-HPD9T0MPEfrD40aSjcj23OcAYDnpsRLXxwQAYK1jw6Fvk7OtJZn8iaoAb4GcFfcKs3vgkpA9DC6DXlnvN0txYA== @@ -2424,12 +2424,12 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.1.10.tgz#efa60d657a76818361a3af14769660672d4bc227" integrity sha512-tApuN8MIJMzc0dxvkYJPt3t5cea9NuZBGNiuVedJwMMUF6hbFpMZAt20GW2qwjBaZ76rQwbLp1s3KnImFsPe5A== -"@tiptap/extension-horizontal-rule@^2.0.4", "@tiptap/extension-horizontal-rule@^2.1.10", "@tiptap/extension-horizontal-rule@^2.1.7": +"@tiptap/extension-horizontal-rule@^2.1.10", "@tiptap/extension-horizontal-rule@^2.1.7": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.1.10.tgz#cfdb67530be100054fc8511942d4ec3534acf828" integrity sha512-91lGpK2d6WMPhrMDPBURS8z8pEg1CUBYy7GmBenKvvgh+JzVhG+U6MtykfWNfm2R4iRXOl1xLbyUOCiOSUXodQ== -"@tiptap/extension-image@^2.0.4", "@tiptap/extension-image@^2.1.7": +"@tiptap/extension-image@^2.1.7": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.1.10.tgz#6c597ad02285f1f3508fd4aa21e30213657cbd7c" integrity sha512-d7+d4J2TJ99+phFbVTpsFhi208jAgcrfbdwUDkkwjdF+PQhax5pounSt/8eZPWdyCXj+EWYjCjx0znwsD6+SCA== @@ -2439,7 +2439,7 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.1.10.tgz#7183119c8c61beb2ac635ca3c2066624530b4a56" integrity sha512-ebw5m+rWx6K5UoBVXSkz3fpvDJh/wScfYmwl6pkbjc2jNbZiln2LSiLHYc2eIYJ2aTsVxcw/n0Azfk5Lb19InA== -"@tiptap/extension-link@^2.0.4", "@tiptap/extension-link@^2.1.7": +"@tiptap/extension-link@^2.1.7": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.1.10.tgz#c2a33fdf33dd2d97f29381ae2163c10318dc371f" integrity sha512-dXxPTWzJzpbDRAewM4P8jN/n9h8uUH83lOLwweuODYCqHRdjQL/uGkQworFFrgqmRHs+9JjHZ4DETILZVawJ+Q== @@ -2466,11 +2466,6 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.0.3.tgz#69575353f09fc7524c9cdbfbf16c04f73c29d154" integrity sha512-Z42jo0termRAf0S0L8oxrts94IWX5waU4isS2CUw8xCUigYyCFslkhQXkWATO1qRbjNFLKN2C9qvCgGf4UeBrw== -"@tiptap/extension-placeholder@^2.0.4": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.1.10.tgz#bdb03dac209444276f25d76f3929bb2bc1facfe8" - integrity sha512-lwtNmMZpxvQBGP72/zrdPFOmn/3QNZAKpkrfrK95Ri4TU6LPeDDwPsP81s9mkAFZPuDQ1i8SPakl+RivWa6qtA== - "@tiptap/extension-strike@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.1.10.tgz#ec311395d16af15345b63d2dac2d459b9ad5fa9e" @@ -2496,32 +2491,32 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-table/-/extension-table-2.1.10.tgz#5654426366b547631c647ffc5dacf040e65307e1" integrity sha512-fsf0c6qA+R6NzbFx+tm1l5POZsgadHjREsedvq5q1i8rCq1Gt1AK+lR7WQsaXlSeIRsWtg4RT0eUjAYNCmKkug== -"@tiptap/extension-task-item@^2.0.4", "@tiptap/extension-task-item@^2.1.7": +"@tiptap/extension-task-item@^2.1.7": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-2.1.10.tgz#8eb0d3e8b1234fa44205dd91619f3f1937ca3254" integrity sha512-jiH37e8c41T/UKWXzznOg325huAkAiFtjNkvfQfS23a7UDfIM90IJ+VjvFt/5EEgJ2mozBweQan4yIzlC6uWaQ== -"@tiptap/extension-task-list@^2.0.4", "@tiptap/extension-task-list@^2.1.7": +"@tiptap/extension-task-list@^2.1.7": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-task-list/-/extension-task-list-2.1.10.tgz#faf2d520c5f5b7b5084a0804b8e65f69fea361be" integrity sha512-1nLI81lQ/HYrcxVRSv3EyG8kcWygtaQcOZ9p6PeQjwN+z5D5PoQVHK4+8zOO1Lpz4BDR3mc4nolA7q/Li0ilOw== -"@tiptap/extension-text-style@^2.0.4", "@tiptap/extension-text-style@^2.1.7": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-text-style/-/extension-text-style-2.1.10.tgz#7d12e4d42da61ea5b4a675f31fea16482326c37b" - integrity sha512-ptgCZQfpy/8aQHHzktVMMAy30uMvC0XkPbJPmD0nYJqt/m+3QFHHWiGyaKXmYhqyg/TjPvTTMHjcvTvk5k4Sug== +"@tiptap/extension-text-style@^2.1.11": + version "2.1.11" + resolved "https://registry.yarnpkg.com/@tiptap/extension-text-style/-/extension-text-style-2.1.11.tgz#b2fbea4f52b68f339b4941103ea2e03d1ac996a3" + integrity sha512-+JDWmcSUyFKzMDm/1xqlk7e0qPJ1nQ/UKIRuDeRtqgbxTyEw4fNlkV2k7GHCoELXqxUoplzweLID+kM1Vk2OaA== "@tiptap/extension-text@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.1.10.tgz#db297fb5d2ee50ef7a14650539e3d335f772f755" integrity sha512-ubU/WQwNB0MVKyMAHr8ka3Nu3jCR03HARGKUwNRzppZYtRXWyXHNlAaJdplNb1NMGb8hd0ElBJmwFlVqmh8haQ== -"@tiptap/extension-underline@^2.0.4", "@tiptap/extension-underline@^2.1.7": +"@tiptap/extension-underline@^2.1.7": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-underline/-/extension-underline-2.1.10.tgz#d7a3ac39c2363da94651a960abe3a16bb24de398" integrity sha512-f+rJKviGNqORGv4/1pTLZuVTb9VsKMZMLucL8423M6s8TdrH//sBB8QeU92JSnO9PjAGwxWjS1f23/KtufxP8g== -"@tiptap/pm@^2.0.4", "@tiptap/pm@^2.1.7": +"@tiptap/pm@^2.1.7": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.1.10.tgz#84d5ae574568dca00ee62698559523d77e980620" integrity sha512-Y+AqizKnjQpx4pSaA6m/cCD5QHQRPtALhO4ZO4YFZV1idYmsJA3/S5lgJI3ZL5eAHKHcGk6Vv3/8Y+eej5YIPw== @@ -2545,7 +2540,7 @@ prosemirror-transform "^1.7.0" prosemirror-view "^1.28.2" -"@tiptap/react@^2.0.4", "@tiptap/react@^2.1.7": +"@tiptap/react@^2.1.7": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-2.1.10.tgz#51cd96462e61f6fffa0ca4eb359d8d7d15ebf422" integrity sha512-kzCWzbV2dnD5NmHjN8GiS+k0GOmoEhKnMuMzuuU6FjtOALhJzPTrIXITzWDpU3jL+r/4eeXYhAt64Wp7PVwscg== @@ -2553,7 +2548,7 @@ "@tiptap/extension-bubble-menu" "^2.1.10" "@tiptap/extension-floating-menu" "^2.1.10" -"@tiptap/starter-kit@^2.0.4", "@tiptap/starter-kit@^2.1.10": +"@tiptap/starter-kit@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.1.10.tgz#5f19c199c79d90ef5e3b8990ca3aa76ce625d68c" integrity sha512-h5mH1qv7SDFXWZPbOWC8zpGZ62EnDizRNtM45Gani0HYWJXcbPFpgN1qJmESP/jP+v+0hxtnVEkgfpiy3LRm6A== @@ -2578,7 +2573,7 @@ "@tiptap/extension-strike" "^2.1.10" "@tiptap/extension-text" "^2.1.10" -"@tiptap/suggestion@^2.0.4", "@tiptap/suggestion@^2.1.7": +"@tiptap/suggestion@^2.1.7": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/suggestion/-/suggestion-2.1.10.tgz#fe6dd160ea93f8135c0831ae4accc7a708bac019" integrity sha512-k9WTTWT81UkHaxZksjp+wE31E85QL0jyLd0ZEKAs+btW148Pon1KwBeLnODNHILcdQaRPxRvb28a47cRHEKTiw== @@ -7734,11 +7729,6 @@ snake-case@^3.0.4: dot-case "^3.0.4" tslib "^2.0.3" -sonner@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/sonner/-/sonner-0.6.2.tgz#d87420e80d8b25b6d2bd6aabcc28465f03962bdc" - integrity sha512-bh4FWhYoNN481ZIW94W4e0kSLBTMGislYg2YXvDS1px1AJJz4erQe9jHV8s5pS1VMVDgfh3CslNSFLaU6Ldrnw== - source-list-map@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" From bb13f35465c7b4fdc2184b6c848f14556364e0f0 Mon Sep 17 00:00:00 2001 From: PalanikannanM Date: Fri, 22 Sep 2023 16:23:27 +0000 Subject: [PATCH 16/57] fixed dependency issue with react type resolution --- package.json | 3 +++ yarn.lock | 26 ++++---------------------- 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index de09c6ee97a..3c729a234fe 100644 --- a/package.json +++ b/package.json @@ -24,5 +24,8 @@ "tailwindcss": "^3.3.3", "turbo": "latest" }, + "resolutions": { + "@types/react": "18.2.0" + }, "packageManager": "yarn@1.22.19" } diff --git a/yarn.lock b/yarn.lock index c9f0cef14b9..8b7bf7f0a82 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2793,28 +2793,10 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@^18.0.17": - version "18.2.22" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.22.tgz#abe778a1c95a07fa70df40a52d7300a40b949ccb" - integrity sha512-60fLTOLqzarLED2O3UQImc/lsNRgG0jE/a1mPW9KjMemY0LMITWEsbS4VvZ4p6rorEHd5YKxxmMKSDK505GHpA== - dependencies: - "@types/prop-types" "*" - "@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== +"@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== dependencies: "@types/prop-types" "*" "@types/scheduler" "*" From 4981c3dbfe613741fa8296c8382a6f80e21f5912 Mon Sep 17 00:00:00 2001 From: Henit Chobisa Date: Fri, 22 Sep 2023 17:04:56 +0000 Subject: [PATCH 17/57] chore: updated pulls build CI for using turbo builds --- .github/workflows/Build_Test_Pull_Request.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/Build_Test_Pull_Request.yml b/.github/workflows/Build_Test_Pull_Request.yml index 6dc7ae1e5e5..c74975f48ef 100644 --- a/.github/workflows/Build_Test_Pull_Request.yml +++ b/.github/workflows/Build_Test_Pull_Request.yml @@ -36,15 +36,13 @@ jobs: - name: Build Plane's Main App if: steps.changed-files.outputs.web_any_changed == 'true' run: | - cd web yarn - yarn build + yarn build --filter=web - name: Build Plane's Deploy App if: steps.changed-files.outputs.deploy_any_changed == 'true' run: | - cd space yarn - yarn build + yarn build --filter=space From 063f4c774ae67026339c945ab09638f82db83658 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Mon, 25 Sep 2023 14:05:17 +0530 Subject: [PATCH 18/57] comment editor basic version added --- packages/editor/package.json | 2 + packages/editor/src/ui/editor/index.tsx | 17 +- .../src/ui/editor/menus/fixed-menu/index.tsx | 78 ++++ .../extensions/image/image-resize.tsx | 44 +++ .../extensions/image/updated-image.tsx | 23 ++ .../src/ui/light-editor/extensions/index.tsx | 155 ++++++++ .../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/index.tsx | 143 +++++++ .../light-editor/menus/table-menu/tooltip.tsx | 77 ++++ .../ui/light-editor/plugins/delete-image.tsx | 68 ++++ .../ui/light-editor/plugins/upload-image.tsx | 138 +++++++ packages/editor/src/ui/light-editor/props.tsx | 71 ++++ packages/editor/tsup.config.ts | 2 +- web/components/issues/comment/add-comment.tsx | 46 ++- web/components/web-view/add-comment.tsx | 34 +- yarn.lock | 52 ++- 28 files changed, 1727 insertions(+), 53 deletions(-) create mode 100644 packages/editor/src/ui/editor/menus/fixed-menu/index.tsx create mode 100644 packages/editor/src/ui/light-editor/extensions/image/image-resize.tsx create mode 100644 packages/editor/src/ui/light-editor/extensions/image/updated-image.tsx create mode 100644 packages/editor/src/ui/light-editor/extensions/index.tsx create mode 100644 packages/editor/src/ui/light-editor/extensions/slash-command.tsx create mode 100644 packages/editor/src/ui/light-editor/extensions/table/table-cell.ts create mode 100644 packages/editor/src/ui/light-editor/extensions/table/table-header.ts create mode 100644 packages/editor/src/ui/light-editor/extensions/table/table.ts create mode 100644 packages/editor/src/ui/light-editor/index.tsx create mode 100644 packages/editor/src/ui/light-editor/menus/bubble-menu/index.tsx create mode 100644 packages/editor/src/ui/light-editor/menus/bubble-menu/link-selector.tsx create mode 100644 packages/editor/src/ui/light-editor/menus/bubble-menu/node-selector.tsx create mode 100644 packages/editor/src/ui/light-editor/menus/bubble-menu/utils/index.tsx create mode 100644 packages/editor/src/ui/light-editor/menus/table-menu/InsertBottomTableIcon.tsx create mode 100644 packages/editor/src/ui/light-editor/menus/table-menu/InsertLeftTableIcon.tsx create mode 100644 packages/editor/src/ui/light-editor/menus/table-menu/InsertRightTableIcon.tsx create mode 100644 packages/editor/src/ui/light-editor/menus/table-menu/InsertTopTableIcon.tsx create mode 100644 packages/editor/src/ui/light-editor/menus/table-menu/index.tsx create mode 100644 packages/editor/src/ui/light-editor/menus/table-menu/tooltip.tsx create mode 100644 packages/editor/src/ui/light-editor/plugins/delete-image.tsx create mode 100644 packages/editor/src/ui/light-editor/plugins/upload-image.tsx create mode 100644 packages/editor/src/ui/light-editor/props.tsx diff --git a/packages/editor/package.json b/packages/editor/package.json index 990d306aa61..a6a61cffbe4 100644 --- a/packages/editor/package.json +++ b/packages/editor/package.json @@ -25,6 +25,7 @@ }, "dependencies": { "@blueprintjs/popover2": "^2.0.10", + "@radix-ui/react-slot": "^1.0.2", "@tiptap/core": "^2.1.7", "@tiptap/extension-code-block-lowlight": "^2.0.4", "@tiptap/extension-color": "^2.1.11", @@ -48,6 +49,7 @@ "@types/node": "18.15.3", "@types/react": "18.0.28", "@types/react-dom": "18.0.11", + "class-variance-authority": "^0.7.0", "clsx": "^1.2.1", "eslint": "8.36.0", "eslint-config-next": "13.2.4", diff --git a/packages/editor/src/ui/editor/index.tsx b/packages/editor/src/ui/editor/index.tsx index 0952869a7a6..286768f5146 100644 --- a/packages/editor/src/ui/editor/index.tsx +++ b/packages/editor/src/ui/editor/index.tsx @@ -11,6 +11,7 @@ import { TiptapEditorProps } from '@/ui/editor/props'; import { UploadImage } from '@/types/upload-image'; import { DeleteImage } from '@/types/delete-image'; import { cn } from '@/lib/utils'; +import { FixedMenu } from './menus/fixed-menu'; interface ITiptapEditor { value: string; @@ -109,11 +110,17 @@ const TiptapEditor = ({ }} className={`tiptap-editor-container cursor-text ${editorClassNames}`} > - {editor && } -
- - - {editor?.isActive("image") && } +
+
+ + + {editor?.isActive("image") && } +
+ {editor && editable !== false && + (
+ +
) + }
); diff --git a/packages/editor/src/ui/editor/menus/fixed-menu/index.tsx b/packages/editor/src/ui/editor/menus/fixed-menu/index.tsx new file mode 100644 index 00000000000..31a7ad90d2e --- /dev/null +++ b/packages/editor/src/ui/editor/menus/fixed-menu/index.tsx @@ -0,0 +1,78 @@ +import { BubbleMenu, BubbleMenuProps } from "@tiptap/react"; +import { FC, useState } from "react"; +import { BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, CodeIcon } from "lucide-react"; + +import { cn } from "@/lib/utils"; + +export interface BubbleMenuItem { + name: string; + isActive: () => boolean; + command: () => void; + icon: typeof BoldIcon; +} + +type EditorBubbleMenuProps = Omit; + +export const FixedMenu: 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, + }, + ]; + + + return ( +
+
+ {items.map((item, index) => ( + + ))} +
+
+ ); +}; 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 new file mode 100644 index 00000000000..448b8811cc1 --- /dev/null +++ b/packages/editor/src/ui/light-editor/extensions/image/image-resize.tsx @@ -0,0 +1,44 @@ +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/image/updated-image.tsx b/packages/editor/src/ui/light-editor/extensions/image/updated-image.tsx new file mode 100644 index 00000000000..2ba977f575e --- /dev/null +++ b/packages/editor/src/ui/light-editor/extensions/image/updated-image.tsx @@ -0,0 +1,23 @@ +import Image from "@tiptap/extension-image"; +import TrackImageDeletionPlugin from "@/ui/editor/plugins/delete-image"; +import UploadImagesPlugin from "@/ui/editor/plugins/upload-image"; +import { DeleteImage } from "@/types/delete-image"; + +const UpdatedImage = (deleteImage: DeleteImage) => Image.extend({ + addProseMirrorPlugins() { + return [UploadImagesPlugin(), TrackImageDeletionPlugin(deleteImage)]; + }, + addAttributes() { + return { + ...this.parent?.(), + width: { + default: "35%", + }, + height: { + default: null, + }, + }; + }, +}); + +export default UpdatedImage; diff --git a/packages/editor/src/ui/light-editor/extensions/index.tsx b/packages/editor/src/ui/light-editor/extensions/index.tsx new file mode 100644 index 00000000000..5fd7f9ad140 --- /dev/null +++ b/packages/editor/src/ui/light-editor/extensions/index.tsx @@ -0,0 +1,155 @@ +import StarterKit from "@tiptap/starter-kit"; +import HorizontalRule from "@tiptap/extension-horizontal-rule"; +import TiptapLink from "@tiptap/extension-link"; +import Placeholder from "@tiptap/extension-placeholder"; +import TiptapUnderline from "@tiptap/extension-underline"; +import TextStyle from "@tiptap/extension-text-style"; +import { Color } from "@tiptap/extension-color"; +import TaskItem from "@tiptap/extension-task-item"; +import TaskList from "@tiptap/extension-task-list"; +import { Markdown } from "tiptap-markdown"; +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 { TableRow } from "@tiptap/extension-table-row"; +import { CustomTableCell } from "@/ui/editor/extensions/table/table-cell"; + +import UpdatedImage from "@/ui/editor/extensions/image/updated-image"; +import SlashCommand from "@/ui/editor/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 ts from "highlight.js/lib/languages/typescript"; +import { lowlight } from "lowlight/lib/core"; +import "highlight.js/styles/github-dark.css"; + +lowlight.registerLanguage("ts", ts); + +export const TiptapExtensions = ( + workspaceSlug: string, + uploadFile: UploadImage, + deleteFile: DeleteImage, + setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void +) => [ + StarterKit.configure({ + bulletList: { + HTMLAttributes: { + class: "list-disc list-outside leading-3 -mt-2", + }, + }, + orderedList: { + HTMLAttributes: { + class: "list-decimal list-outside leading-3 -mt-2", + }, + }, + listItem: { + HTMLAttributes: { + class: "leading-normal -mb-2", + }, + }, + blockquote: { + HTMLAttributes: { + class: "border-l-4 border-custom-border-300", + }, + }, + code: { + HTMLAttributes: { + class: + "rounded-md bg-custom-primary-30 mx-1 px-1 py-1 font-mono font-medium text-custom-text-1000", + spellcheck: "false", + }, + }, + codeBlock: false, + horizontalRule: false, + dropcursor: { + color: "rgba(var(--color-text-100))", + width: 2, + }, + gapcursor: false, + }), + CodeBlockLowlight.configure({ + lowlight, + }), + HorizontalRule.extend({ + addInputRules() { + return [ + new InputRule({ + find: /^(?:---|—-|___\s|\*\*\*\s)$/, + handler: ({ state, range, commands }) => { + commands.splitBlock(); + + const attributes = {}; + const { tr } = state; + const start = range.from; + const end = range.to; + // @ts-ignore + tr.replaceWith(start - 1, end, this.type.create(attributes)); + }, + }), + ]; + }, + }).configure({ + HTMLAttributes: { + class: "mb-6 border-t border-custom-border-300", + }, + }), + Gapcursor, + TiptapLink.configure({ + protocols: ["http", "https"], + validate: (url) => isValidHttpUrl(url), + HTMLAttributes: { + class: + "text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer", + }, + }), + UpdatedImage(deleteFile).configure({ + HTMLAttributes: { + class: "rounded-lg border border-custom-border-300", + }, + }), + Placeholder.configure({ + placeholder: ({ node }) => { + if (node.type.name === "heading") { + return `Heading ${node.attrs.level}`; + } + if (node.type.name === "image" || node.type.name === "table") { + return ""; + } + + return "Press '/' for commands..."; + }, + includeChildren: true, + }), + SlashCommand(workspaceSlug, uploadFile, setIsSubmitting), + TiptapUnderline, + TextStyle, + Color, + Highlight.configure({ + multicolor: true, + }), + TaskList.configure({ + HTMLAttributes: { + class: "not-prose pl-2", + }, + }), + TaskItem.configure({ + HTMLAttributes: { + class: "flex items-start my-4", + }, + nested: true, + }), + Markdown.configure({ + html: true, + transformCopiedText: true, + }), + Table, + TableHeader, + CustomTableCell, + TableRow, + ]; diff --git a/packages/editor/src/ui/light-editor/extensions/slash-command.tsx b/packages/editor/src/ui/light-editor/extensions/slash-command.tsx new file mode 100644 index 00000000000..4fba7af5ff8 --- /dev/null +++ b/packages/editor/src/ui/light-editor/extensions/slash-command.tsx @@ -0,0 +1,365 @@ +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 new file mode 100644 index 00000000000..643cb8c64a7 --- /dev/null +++ b/packages/editor/src/ui/light-editor/extensions/table/table-cell.ts @@ -0,0 +1,32 @@ +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 new file mode 100644 index 00000000000..f23aa93ef55 --- /dev/null +++ b/packages/editor/src/ui/light-editor/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/packages/editor/src/ui/light-editor/extensions/table/table.ts b/packages/editor/src/ui/light-editor/extensions/table/table.ts new file mode 100644 index 00000000000..9b727bb51bd --- /dev/null +++ b/packages/editor/src/ui/light-editor/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/packages/editor/src/ui/light-editor/index.tsx b/packages/editor/src/ui/light-editor/index.tsx new file mode 100644 index 00000000000..e69de29bb2d 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 new file mode 100644 index 00000000000..9592cf6175f --- /dev/null +++ b/packages/editor/src/ui/light-editor/menus/bubble-menu/index.tsx @@ -0,0 +1,121 @@ +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 new file mode 100644 index 00000000000..4f82845069b --- /dev/null +++ b/packages/editor/src/ui/light-editor/menus/bubble-menu/link-selector.tsx @@ -0,0 +1,93 @@ +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 new file mode 100644 index 00000000000..99918450699 --- /dev/null +++ b/packages/editor/src/ui/light-editor/menus/bubble-menu/node-selector.tsx @@ -0,0 +1,130 @@ +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 new file mode 100644 index 00000000000..b5add3f544e --- /dev/null +++ b/packages/editor/src/ui/light-editor/menus/bubble-menu/utils/index.tsx @@ -0,0 +1,11 @@ +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 new file mode 100644 index 00000000000..0e42ba64824 --- /dev/null +++ b/packages/editor/src/ui/light-editor/menus/table-menu/InsertBottomTableIcon.tsx @@ -0,0 +1,16 @@ +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 new file mode 100644 index 00000000000..1fd75fe8754 --- /dev/null +++ b/packages/editor/src/ui/light-editor/menus/table-menu/InsertLeftTableIcon.tsx @@ -0,0 +1,15 @@ +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 new file mode 100644 index 00000000000..1a65709694b --- /dev/null +++ b/packages/editor/src/ui/light-editor/menus/table-menu/InsertRightTableIcon.tsx @@ -0,0 +1,16 @@ +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 new file mode 100644 index 00000000000..8f04f4f6126 --- /dev/null +++ b/packages/editor/src/ui/light-editor/menus/table-menu/InsertTopTableIcon.tsx @@ -0,0 +1,15 @@ +const InsertTopTableIcon = (props: any) => ( + + + +); +export default InsertTopTableIcon; diff --git a/packages/editor/src/ui/light-editor/menus/table-menu/index.tsx b/packages/editor/src/ui/light-editor/menus/table-menu/index.tsx new file mode 100644 index 00000000000..4b342e6e64d --- /dev/null +++ b/packages/editor/src/ui/light-editor/menus/table-menu/index.tsx @@ -0,0 +1,143 @@ +import { useState, useEffect } from "react"; +import { Rows, Columns, ToggleRight } from "lucide-react"; +import InsertLeftTableIcon from "./InsertLeftTableIcon"; +import InsertRightTableIcon from "./InsertRightTableIcon"; +import InsertTopTableIcon from "./InsertTopTableIcon"; +import InsertBottomTableIcon from "./InsertBottomTableIcon"; +import { cn } from "@/lib/utils"; +import { Tooltip } from "./tooltip"; + +interface TableMenuItem { + command: () => void; + icon: any; + key: string; + name: string; +} + +export const findTableAncestor = (node: Node | null): HTMLTableElement | null => { + while (node !== null && node.nodeName !== "TABLE") { + node = node.parentNode; + } + return node as HTMLTableElement; +}; + +export const TableMenu = ({ editor }: { editor: any }) => { + const [tableLocation, setTableLocation] = useState({ bottom: 0, left: 0 }); + const isOpen = editor?.isActive("table"); + + const items: TableMenuItem[] = [ + { + command: () => editor.chain().focus().addColumnBefore().run(), + icon: InsertLeftTableIcon, + key: "insert-column-left", + name: "Insert 1 column left", + }, + { + command: () => editor.chain().focus().addColumnAfter().run(), + icon: InsertRightTableIcon, + key: "insert-column-right", + name: "Insert 1 column right", + }, + { + command: () => editor.chain().focus().addRowBefore().run(), + icon: InsertTopTableIcon, + key: "insert-row-above", + name: "Insert 1 row above", + }, + { + command: () => editor.chain().focus().addRowAfter().run(), + icon: InsertBottomTableIcon, + key: "insert-row-below", + name: "Insert 1 row below", + }, + { + command: () => editor.chain().focus().deleteColumn().run(), + icon: Columns, + key: "delete-column", + name: "Delete column", + }, + { + command: () => editor.chain().focus().deleteRow().run(), + icon: Rows, + key: "delete-row", + name: "Delete row", + }, + { + command: () => editor.chain().focus().toggleHeaderRow().run(), + icon: ToggleRight, + key: "toggle-header-row", + name: "Toggle header row", + }, + ]; + + useEffect(() => { + if (!window) return; + + const handleWindowClick = () => { + const selection: any = window?.getSelection(); + + if (selection.rangeCount !== 0) { + const range = selection.getRangeAt(0); + const tableNode = findTableAncestor(range.startContainer); + + let parent = tableNode?.parentElement; + + if (tableNode) { + const tableRect = tableNode.getBoundingClientRect(); + const tableCenter = tableRect.left + tableRect.width / 2; + const menuWidth = 45; + const menuLeft = tableCenter - menuWidth / 2; + const tableBottom = tableRect.bottom; + + setTableLocation({ bottom: tableBottom, left: menuLeft }); + + while (parent) { + if (!parent.classList.contains("disable-scroll")) + parent.classList.add("disable-scroll"); + parent = parent.parentElement; + } + } else { + const scrollDisabledContainers = document.querySelectorAll(".disable-scroll"); + + scrollDisabledContainers.forEach((container) => { + container.classList.remove("disable-scroll"); + }); + } + } + }; + + window.addEventListener("click", handleWindowClick); + + return () => { + window.removeEventListener("click", handleWindowClick); + }; + }, [tableLocation, editor]); + + return ( +
+ {items.map((item, index) => ( + + + + ))} +
+ ); +}; 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 new file mode 100644 index 00000000000..f29d8a49177 --- /dev/null +++ b/packages/editor/src/ui/light-editor/menus/table-menu/tooltip.tsx @@ -0,0 +1,77 @@ +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 new file mode 100644 index 00000000000..9204481a8dd --- /dev/null +++ b/packages/editor/src/ui/light-editor/plugins/delete-image.tsx @@ -0,0 +1,68 @@ +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 new file mode 100644 index 00000000000..4c3bbf9a82b --- /dev/null +++ b/packages/editor/src/ui/light-editor/plugins/upload-image.tsx @@ -0,0 +1,138 @@ +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/packages/editor/src/ui/light-editor/props.tsx b/packages/editor/src/ui/light-editor/props.tsx new file mode 100644 index 00000000000..ff5b2f11b25 --- /dev/null +++ b/packages/editor/src/ui/light-editor/props.tsx @@ -0,0 +1,71 @@ +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/tsup.config.ts b/packages/editor/tsup.config.ts index 236e425ed30..5e89e04afad 100644 --- a/packages/editor/tsup.config.ts +++ b/packages/editor/tsup.config.ts @@ -4,7 +4,7 @@ export default defineConfig((options: Options) => ({ entry: ["src/index.ts"], format: ["cjs", "esm"], dts: true, - clean: true, + clean: false, external: ["react"], injectStyle: true, ...options, diff --git a/web/components/issues/comment/add-comment.tsx b/web/components/issues/comment/add-comment.tsx index ef1d4cec74a..78b38e1d356 100644 --- a/web/components/issues/comment/add-comment.tsx +++ b/web/components/issues/comment/add-comment.tsx @@ -66,6 +66,22 @@ 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)} + /> + )} + /> {showAccessSpecifier && (
= ({ @@ -98,22 +112,6 @@ 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)} - /> - )} - />
diff --git a/web/components/web-view/add-comment.tsx b/web/components/web-view/add-comment.tsx index b8e67be2b89..d315c307221 100644 --- a/web/components/web-view/add-comment.tsx +++ b/web/components/web-view/add-comment.tsx @@ -74,8 +74,24 @@ export const AddComment: React.FC = ({ disabled = false, onSubmit }) => { return (
+ ( +

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

" : value} - customClassName="p-3 min-h-[100px] shadow-sm" - debouncedUpdatesEnabled={false} - onChange={(comment_json: Object, comment_html: string) => onChange(comment_html)} - /> - )} - />
diff --git a/yarn.lock b/yarn.lock index 8b7bf7f0a82..9ec69da9105 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1892,6 +1892,13 @@ dependencies: "@babel/runtime" "^7.13.10" +"@radix-ui/react-compose-refs@1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz#7ed868b66946aa6030e580b1ffca386dd4d21989" + integrity sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-context@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.0.0.tgz#f38e30c5859a9fb5e9aa9a9da452ee3ed9e0aee0" @@ -1990,6 +1997,14 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-compose-refs" "1.0.0" +"@radix-ui/react-slot@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab" + integrity sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "1.0.1" + "@radix-ui/react-use-callback-ref@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz#9e7b8b6b4946fe3cbe8f748c82a2cce54e7b6a90" @@ -2793,7 +2808,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@18.0.15", "@types/react@18.0.28", "@types/react@18.2.0", "@types/react@^18.0.17": +"@types/react@*", "@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== @@ -2802,6 +2817,24 @@ "@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" @@ -3473,6 +3506,13 @@ chownr@^1.1.1: resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== +class-variance-authority@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/class-variance-authority/-/class-variance-authority-0.7.0.tgz#1c3134d634d80271b1837452b06d821915954522" + integrity sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A== + dependencies: + clsx "2.0.0" + classnames@^2.2.6, classnames@^2.3.1, classnames@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924" @@ -3490,16 +3530,16 @@ client-only@^0.0.1: resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== +clsx@2.0.0, clsx@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.0.0.tgz#12658f3fd98fafe62075595a5c30e43d18f3d00b" + integrity sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q== + clsx@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== -clsx@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.0.0.tgz#12658f3fd98fafe62075595a5c30e43d18f3d00b" - integrity sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q== - cmdk@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/cmdk/-/cmdk-0.2.0.tgz#53c52d56d8776c8bb8ced1055b5054100c388f7c" 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 19/57] 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 | 66 ++-- yarn.lock | 20 +- 71 files changed, 429 insertions(+), 1649 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 3c729a234fe..23ec38b79eb 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 00000000000..7e137d3c65e --- /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 00000000000..1c985922b92 --- /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 2ba977f575e..9157e890569 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 5fd7f9ad140..f018fab49eb 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 4fba7af5ff8..3813c1defec 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 286768f5146..7eb332a43ae 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 4f82845069b..f3730c4dcf3 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 00000000000..c0006b3f257 --- /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 31a7ad90d2e..7d00b65e626 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 ff5b2f11b25..00000000000 --- 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 448b8811cc1..00000000000 --- 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 4fba7af5ff8..00000000000 --- 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 643cb8c64a7..00000000000 --- 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 f23aa93ef55..00000000000 --- 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 9b727bb51bd..00000000000 --- 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 e69de29bb2d..00000000000 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 9592cf6175f..00000000000 --- 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 4f82845069b..00000000000 --- 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 99918450699..00000000000 --- 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 b5add3f544e..00000000000 --- 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 0e42ba64824..00000000000 --- 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 1fd75fe8754..00000000000 --- 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 1a65709694b..00000000000 --- 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 8f04f4f6126..00000000000 --- 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 f29d8a49177..00000000000 --- 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 9204481a8dd..00000000000 --- 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 4c3bbf9a82b..00000000000 --- 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 78b38e1d356..76a45faa428 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)} - /> - )} - /> - {showAccessSpecifier && ( -
+ render={({ field: { onChange, value } }) => ( ( -
- {commentAccess.map((access) => ( - - - - ))} -
+ render={({ field: { onChange: onCommentChange, value: commentValue } }) => ( +

" : 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} + /> )} /> -
- )} + )} + />
diff --git a/yarn.lock b/yarn.lock index 9ec69da9105..d92d076bfaf 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" From 4298b0500eeadeaa171b8bc0329c5dae4e8b151b Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Thu, 28 Sep 2023 16:05:52 +0530 Subject: [PATCH 20/57] refactored editor to not require workspace slug --- package.json | 5 +- .../editor/core/src/types/upload-image.ts | 2 +- .../editor/core/src/ui/extensions/index.tsx | 3 +- .../core/src/ui/extensions/slash-command.tsx | 6 +- packages/editor/core/src/ui/index.tsx | 6 +- .../core/src/ui/plugins/upload-image.tsx | 18 +----- packages/editor/core/src/ui/props.tsx | 5 +- packages/editor/core/src/useEditor.tsx | 58 +++++++++---------- web/components/issues/description-form.tsx | 3 +- web/services/file.service.ts | 19 +++++- 10 files changed, 63 insertions(+), 62 deletions(-) diff --git a/package.json b/package.json index 23ec38b79eb..a0e58018add 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,10 @@ "web", "space", "packages/editor/*", - "packages/*" + "packages/eslint-config-custom", + "packages/tailwind-config-custom", + "packages/tsconfig", + "packages/ui" ], "scripts": { "build": "turbo run build", diff --git a/packages/editor/core/src/types/upload-image.ts b/packages/editor/core/src/types/upload-image.ts index e9d35ad486b..3cf1408d22b 100644 --- a/packages/editor/core/src/types/upload-image.ts +++ b/packages/editor/core/src/types/upload-image.ts @@ -1 +1 @@ -export type UploadImage = (workspaceSlug: string, formData: FormData) => Promise; +export type UploadImage = (file: File) => Promise; diff --git a/packages/editor/core/src/ui/extensions/index.tsx b/packages/editor/core/src/ui/extensions/index.tsx index f018fab49eb..1c113244483 100644 --- a/packages/editor/core/src/ui/extensions/index.tsx +++ b/packages/editor/core/src/ui/extensions/index.tsx @@ -32,7 +32,6 @@ import "highlight.js/styles/github-dark.css"; lowlight.registerLanguage("ts", ts); export const TiptapExtensions = ( - workspaceSlug: string, uploadFile: UploadImage, deleteFile: DeleteImage, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void @@ -126,7 +125,7 @@ export const TiptapExtensions = ( }, includeChildren: true, }), - SlashCommand(workspaceSlug, uploadFile, setIsSubmitting), + SlashCommand(uploadFile, setIsSubmitting), TiptapUnderline, TextStyle, Color, diff --git a/packages/editor/core/src/ui/extensions/slash-command.tsx b/packages/editor/core/src/ui/extensions/slash-command.tsx index 3813c1defec..844d4c55a58 100644 --- a/packages/editor/core/src/ui/extensions/slash-command.tsx +++ b/packages/editor/core/src/ui/extensions/slash-command.tsx @@ -59,7 +59,6 @@ const Command = Extension.create({ const getSuggestionItems = ( - workspaceSlug: string, uploadFile: UploadImage, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void ) => @@ -185,7 +184,7 @@ const getSuggestionItems = if (input.files?.length) { const file = input.files[0]; const pos = editor.view.state.selection.from; - startImageUpload(file, editor.view, pos, workspaceSlug, uploadFile, setIsSubmitting); + startImageUpload(file, editor.view, pos, uploadFile, setIsSubmitting); } }; input.click(); @@ -351,13 +350,12 @@ const renderItems = () => { }; export const SlashCommand = ( - workspaceSlug: string, uploadFile: UploadImage, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void ) => Command.configure({ suggestion: { - items: getSuggestionItems(workspaceSlug, uploadFile, setIsSubmitting), + items: getSuggestionItems(uploadFile, setIsSubmitting), render: renderItems, }, }); diff --git a/packages/editor/core/src/ui/index.tsx b/packages/editor/core/src/ui/index.tsx index 7eb332a43ae..fc870f30969 100644 --- a/packages/editor/core/src/ui/index.tsx +++ b/packages/editor/core/src/ui/index.tsx @@ -24,7 +24,6 @@ interface ITiptapEditor { onChange?: (json: any, html: string) => void; setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void; setShouldShowAlert?: (showAlert: boolean) => void; - workspaceSlug: string; editable?: boolean; forwardedRef?: any; debouncedUpdatesEnabled?: boolean; @@ -59,7 +58,6 @@ const TiptapEditor = ({ uploadFile, deleteFile, noBorder, - workspaceSlug, borderOnFocus, customClassName, forwardedRef, @@ -69,9 +67,9 @@ const TiptapEditor = ({ }: TiptapProps) => { const editor = useEditor({ editable: editable ?? true, - editorProps: TiptapEditorProps(workspaceSlug, uploadFile, setIsSubmitting), + editorProps: TiptapEditorProps(uploadFile, setIsSubmitting), // @ts-expect-err - extensions: TiptapExtensions(workspaceSlug, uploadFile, deleteFile, setIsSubmitting), + extensions: TiptapExtensions(uploadFile, deleteFile, setIsSubmitting), content: (typeof value === "string" && value.trim() !== "") ? value : "

", onUpdate: async ({ editor }) => { // for instant feedback loop diff --git a/packages/editor/core/src/ui/plugins/upload-image.tsx b/packages/editor/core/src/ui/plugins/upload-image.tsx index 4c3bbf9a82b..976c4968b43 100644 --- a/packages/editor/core/src/ui/plugins/upload-image.tsx +++ b/packages/editor/core/src/ui/plugins/upload-image.tsx @@ -57,7 +57,6 @@ export async function startImageUpload( file: File, view: EditorView, pos: number, - workspaceSlug: string, uploadFile: UploadImage, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void ) { @@ -83,11 +82,8 @@ export async function startImageUpload( view.dispatch(tr); }; - if (!workspaceSlug) { - return; - } setIsSubmitting?.("submitting"); - const src = await UploadImageHandler(file, workspaceSlug, uploadFile); + const src = await UploadImageHandler(file, uploadFile); const { schema } = view.state; pos = findPlaceholder(view.state, id); @@ -101,21 +97,13 @@ export async function startImageUpload( view.dispatch(transaction); } -const UploadImageHandler = (file: File, workspaceSlug: string, +const UploadImageHandler = (file: File, 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 imageUrl = await uploadFile(file) const image = new Image(); image.src = imageUrl; diff --git a/packages/editor/core/src/ui/props.tsx b/packages/editor/core/src/ui/props.tsx index 9dfc8fd0ffd..528f664ea26 100644 --- a/packages/editor/core/src/ui/props.tsx +++ b/packages/editor/core/src/ui/props.tsx @@ -4,7 +4,6 @@ import { startImageUpload } from "@/ui/plugins/upload-image"; import { UploadImage } from "@/types/upload-image"; export function TiptapEditorProps( - workspaceSlug: string, uploadFile: UploadImage, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void ): EditorProps { @@ -37,7 +36,7 @@ export function TiptapEditorProps( event.preventDefault(); const file = event.clipboardData.files[0]; const pos = view.state.selection.from; - startImageUpload(file, view, pos, workspaceSlug, uploadFile, setIsSubmitting); + startImageUpload(file, view, pos, uploadFile, setIsSubmitting); return true; } return false; @@ -61,7 +60,7 @@ export function TiptapEditorProps( }); // 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); + startImageUpload(file, view, coordinates.pos - 1, uploadFile, setIsSubmitting); } return true; } diff --git a/packages/editor/core/src/useEditor.tsx b/packages/editor/core/src/useEditor.tsx index 94559acb0a8..552c0ca2168 100644 --- a/packages/editor/core/src/useEditor.tsx +++ b/packages/editor/core/src/useEditor.tsx @@ -1,35 +1,35 @@ import { - useEditor as useEditorCore, - } from "@tiptap/react"; + useEditor as useEditorCore, +} from "@tiptap/react"; import { findTableAncestor } from "@/lib/utils"; export const useEditor = (props: any) => useEditorCore({ - editorProps: { - 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: () => { - if (typeof window !== "undefined") { - const selection: any = window?.getSelection(); - if (selection.rangeCount !== 0) { - const range = selection.getRangeAt(0); - if (findTableAncestor(range.startContainer)) { - return; - } - } + editorProps: { + 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; } - }, + } }, - ...props, -}); \ No newline at end of file + }, + handlePaste: () => { + if (typeof window !== "undefined") { + const selection: any = window?.getSelection(); + if (selection.rangeCount !== 0) { + const range = selection.getRangeAt(0); + if (findTableAncestor(range.startContainer)) { + return; + } + } + } + }, + }, + ...props, +}); diff --git a/web/components/issues/description-form.tsx b/web/components/issues/description-form.tsx index dc140af1d98..eb26a780578 100644 --- a/web/components/issues/description-form.tsx +++ b/web/components/issues/description-form.tsx @@ -135,10 +135,9 @@ export const IssueDescriptionForm: FC = ({ return ( { - return this.mediaUpload(`/api/workspaces/${workspaceSlug}/file-assets/`, file) + return this.post(`/api/workspaces/${workspaceSlug}/file-assets/`, file, { + headers: { + ...this.getHeaders(), + "Content-Type": "multipart/form-data", + }, + }) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; }); } + getUploadFileFunction(workspaceSlug: string): (file: File) => Promise { + return async (file: File) => { + const formData = new FormData(); + formData.append("asset", file); + formData.append("attributes", JSON.stringify({})); + + const data = await this.uploadFile(workspaceSlug, formData); + return data.asset; + }; + } + async deleteImage(assetUrlWithWorkspaceId: string): Promise { return this.delete(`/api/workspaces/file-assets/${assetUrlWithWorkspaceId}/`) .then((response) => response?.status) @@ -59,6 +75,7 @@ class FileService extends APIService { throw error?.response?.data; }); } + async uploadUserFile(file: FormData): Promise { return this.mediaUpload(`/api/users/file-assets/`, file) .then((response) => response?.data) From efcc7f20ccf63ff16ab9b744af4e3e87d47d42fd Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Thu, 28 Sep 2023 20:25:31 +0530 Subject: [PATCH 21/57] added seperation of extensions and props --- packages/editor/core/src/hooks/useEditor.tsx | 34 ++ packages/editor/core/src/index.ts | 7 + packages/editor/core/src/interfaces/index.ts | 4 + .../core/src/ui/extensions/index-new.tsx | 88 +++++ packages/editor/core/src/ui/index-new.tsx | 150 ++++++++ packages/editor/core/src/ui/index.tsx | 1 - packages/editor/core/src/ui/props.tsx | 1 - .../rich-text-editor/src/extensions.tsx | 66 ++++ .../editor/rich-text-editor/src/index.tsx | 0 .../rich-text-editor/src/slash-command.tsx | 363 ++++++++++++++++++ .../rich-text-editor/src/table/table-cell.ts | 32 ++ .../src/table/table-header.ts | 7 + .../rich-text-editor/src/table/table.ts | 9 + .../src/types/upload-image.ts | 1 + packages/tailwind-config-custom/package.json | 9 +- web/postcss.config.js | 9 +- yarn.lock | 34 +- 17 files changed, 804 insertions(+), 11 deletions(-) create mode 100644 packages/editor/core/src/hooks/useEditor.tsx create mode 100644 packages/editor/core/src/interfaces/index.ts create mode 100644 packages/editor/core/src/ui/extensions/index-new.tsx create mode 100644 packages/editor/core/src/ui/index-new.tsx create mode 100644 packages/editor/rich-text-editor/src/extensions.tsx create mode 100644 packages/editor/rich-text-editor/src/index.tsx create mode 100644 packages/editor/rich-text-editor/src/slash-command.tsx create mode 100644 packages/editor/rich-text-editor/src/table/table-cell.ts create mode 100644 packages/editor/rich-text-editor/src/table/table-header.ts create mode 100644 packages/editor/rich-text-editor/src/table/table.ts create mode 100644 packages/editor/rich-text-editor/src/types/upload-image.ts diff --git a/packages/editor/core/src/hooks/useEditor.tsx b/packages/editor/core/src/hooks/useEditor.tsx new file mode 100644 index 00000000000..9d121fcfffa --- /dev/null +++ b/packages/editor/core/src/hooks/useEditor.tsx @@ -0,0 +1,34 @@ +import { DeleteImage } from "@/types/delete-image"; +import { UploadImage } from "@/types/upload-image"; +import { TiptapExtensions } from "@/ui/extensions"; +import { TiptapEditorProps } from "@/ui/props"; +import { useEditor as useTiptapEditor } from "@tiptap/react"; + +interface ITiptapEditor { + value: string; + uploadFile: UploadImage; + deleteFile: DeleteImage; + onChange?: (json: any, html: string) => void; + setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void; + setShouldShowAlert?: (showAlert: boolean) => void; + editable?: boolean; + debouncedUpdatesEnabled?: boolean; + debouncedUpdates: ({ onChange, editor }: { onChange?: (json: any, html: string) => void; editor: any }) => void; +} + +export const useEditor = ({ uploadFile, debouncedUpdates, setShouldShowAlert, deleteFile, setIsSubmitting, value, onChange, debouncedUpdatesEnabled, editable }: ITiptapEditor) => useTiptapEditor({ + editable: editable ?? true, + editorProps: TiptapEditorProps(uploadFile, setIsSubmitting), + extensions: TiptapExtensions(uploadFile, deleteFile, setIsSubmitting), + content: (typeof value === "string" && value.trim() !== "") ? value : "

", + onUpdate: async ({ editor }) => { + // for instant feedback loop + setIsSubmitting?.("submitting"); + setShouldShowAlert?.(true); + if (debouncedUpdatesEnabled) { + debouncedUpdates({ onChange, editor }); + } else { + onChange?.(editor.getJSON(), editor.getHTML()); + } + }, +}); diff --git a/packages/editor/core/src/index.ts b/packages/editor/core/src/index.ts index 7e137d3c65e..890841cb9e4 100644 --- a/packages/editor/core/src/index.ts +++ b/packages/editor/core/src/index.ts @@ -1,5 +1,12 @@ import "@/styles/tailwind.css"; import "@/styles/editor.css"; +// export { ImageResizer } from "./ui/extensions/image/image-resize"; +// export { TiptapEditorProps } from "./ui/props"; +// export { TableMenu } from "./ui/menus/table-menu"; +// export { TiptapExtensions } from "./ui/extensions"; +// export { cn } from "./lib/utils"; +// export { FixedMenu } from "./ui/menus/fixed-menu"; +// export { EditorBubbleMenu } from "./ui/menus/bubble-menu"; export { TiptapEditor, TiptapEditorWithRef } from "@/ui"; diff --git a/packages/editor/core/src/interfaces/index.ts b/packages/editor/core/src/interfaces/index.ts new file mode 100644 index 00000000000..7f5492df7dd --- /dev/null +++ b/packages/editor/core/src/interfaces/index.ts @@ -0,0 +1,4 @@ +export interface EditorHandle { + clearEditor: () => void; + setEditorValue: (content: string) => void; +} diff --git a/packages/editor/core/src/ui/extensions/index-new.tsx b/packages/editor/core/src/ui/extensions/index-new.tsx new file mode 100644 index 00000000000..27639fe06d4 --- /dev/null +++ b/packages/editor/core/src/ui/extensions/index-new.tsx @@ -0,0 +1,88 @@ +import StarterKit from "@tiptap/starter-kit"; +import TiptapLink from "@tiptap/extension-link"; +import TiptapUnderline from "@tiptap/extension-underline"; +import TextStyle from "@tiptap/extension-text-style"; +import { Color } from "@tiptap/extension-color"; +import TaskItem from "@tiptap/extension-task-item"; +import TaskList from "@tiptap/extension-task-list"; +import { Markdown } from "tiptap-markdown"; +import Gapcursor from "@tiptap/extension-gapcursor"; + +import UpdatedImage from "@/ui/extensions/image/updated-image"; + +import { DeleteImage } from "@/types/delete-image"; + +import isValidHttpUrl from "@/ui/menus/bubble-menu/utils" + +export const TiptapExtensions = ( + deleteFile: DeleteImage, +) => [ + StarterKit.configure({ + bulletList: { + HTMLAttributes: { + class: "list-disc list-outside leading-3 -mt-2", + }, + }, + orderedList: { + HTMLAttributes: { + class: "list-decimal list-outside leading-3 -mt-2", + }, + }, + listItem: { + HTMLAttributes: { + class: "leading-normal -mb-2", + }, + }, + blockquote: { + HTMLAttributes: { + class: "border-l-4 border-custom-border-300", + }, + }, + code: { + HTMLAttributes: { + class: + "rounded-md bg-custom-primary-30 mx-1 px-1 py-1 font-mono font-medium text-custom-text-1000", + spellcheck: "false", + }, + }, + codeBlock: false, + horizontalRule: false, + dropcursor: { + color: "rgba(var(--color-text-100))", + width: 2, + }, + gapcursor: false, + }), + Gapcursor, + TiptapLink.configure({ + protocols: ["http", "https"], + validate: (url) => isValidHttpUrl(url), + HTMLAttributes: { + class: + "text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer", + }, + }), + UpdatedImage(deleteFile).configure({ + HTMLAttributes: { + class: "rounded-lg border border-custom-border-300", + }, + }), + TiptapUnderline, + TextStyle, + Color, + TaskList.configure({ + HTMLAttributes: { + class: "not-prose pl-2", + }, + }), + TaskItem.configure({ + HTMLAttributes: { + class: "flex items-start my-4", + }, + nested: true, + }), + Markdown.configure({ + html: true, + transformCopiedText: true, + }), + ]; diff --git a/packages/editor/core/src/ui/index-new.tsx b/packages/editor/core/src/ui/index-new.tsx new file mode 100644 index 00000000000..b6e42348b84 --- /dev/null +++ b/packages/editor/core/src/ui/index-new.tsx @@ -0,0 +1,150 @@ +"use client" +import * as React from 'react'; +import { useImperativeHandle, useRef, forwardRef } from "react"; +import { useEditor, EditorContent, Editor, Extension } from "@tiptap/react"; +import { useDebouncedCallback } from "use-debounce"; +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'; +import { FixedMenu } from './menus/fixed-menu'; +import { EditorProps } from '@tiptap/pm/view'; + +interface ITiptapEditor { + value: string; + uploadFile: UploadImage; + deleteFile: DeleteImage; + noBorder?: boolean; + borderOnFocus?: boolean; + customClassName?: string; + editorContentCustomClassNames?: string; + onChange?: (json: any, html: string) => void; + setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void; + setShouldShowAlert?: (showAlert: boolean) => void; + editable?: boolean; + forwardedRef?: any; + debouncedUpdatesEnabled?: boolean; + accessValue: string; + onAccessChange: (accessKey: string) => void; + commentAccess: { + icon: string; + key: string; + label: "Private" | "Public"; + }[]; + extensions?: Extension[]; + editorProps?: EditorProps; +} + +interface TiptapProps extends ITiptapEditor { + forwardedRef?: React.Ref; +} + +interface EditorHandle { + clearEditor: () => void; + setEditorValue: (content: string) => void; +} + +const DEBOUNCE_DELAY = 1500; + +const TiptapEditor = ({ + onChange, + debouncedUpdatesEnabled, + editable, + setIsSubmitting, + setShouldShowAlert, + editorContentCustomClassNames, + value, + uploadFile, + extensions = [], + editorProps = {}, + deleteFile, + noBorder, + borderOnFocus, + customClassName, + forwardedRef, + accessValue, + onAccessChange, + commentAccess, +}: TiptapProps) => { + const editor = useEditor({ + editable: editable ?? true, + editorProps: { + ...TiptapEditorProps(uploadFile, setIsSubmitting), + ...editorProps, + }, + extensions: [...TiptapExtensions(uploadFile, deleteFile, setIsSubmitting), ...extensions], + content: (typeof value === "string" && value.trim() !== "") ? value : "

", + onUpdate: async ({ editor }) => { + // for instant feedback loop + setIsSubmitting?.("submitting"); + setShouldShowAlert?.(true); + if (debouncedUpdatesEnabled) { + debouncedUpdates({ onChange, editor }); + } else { + onChange?.(editor.getJSON(), editor.getHTML()); + } + }, + }); + + const editorRef: React.MutableRefObject = useRef(null); + editorRef.current = editor; + + useImperativeHandle(forwardedRef, () => ({ + clearEditor: () => { + editorRef.current?.commands.clearContent(); + }, + setEditorValue: (content: string) => { + editorRef.current?.commands.setContent(content); + }, + })); + + const debouncedUpdates = useDebouncedCallback(async ({ onChange, editor }) => { + if (onChange) { + onChange(editor.getJSON(), editor.getHTML()); + } + }, DEBOUNCE_DELAY); + + const editorClassNames = cn( + 'relative w-full max-w-full sm:rounded-lg mt-2 p-3 relative focus:outline-none rounded-md', + noBorder ? '' : 'border border-custom-border-200', + borderOnFocus ? 'focus:border border-custom-border-300' : 'focus:border-0', + customClassName + ); + + if (!editor) return null; + + return ( +
{ + editor?.chain().focus().run(); + }} + className={`tiptap-editor-container cursor-text ${editorClassNames}`} + > +
+
+ + + {editor?.isActive("image") && } +
+ {editor && editable !== false && + (
+ +
) + } +
+
+ ); +}; + +const TiptapEditorWithRef = forwardRef((props, ref) => ( + +)); + +TiptapEditorWithRef.displayName = "TiptapEditorWithRef"; + +export { TiptapEditor, TiptapEditorWithRef }; diff --git a/packages/editor/core/src/ui/index.tsx b/packages/editor/core/src/ui/index.tsx index fc870f30969..28808f649aa 100644 --- a/packages/editor/core/src/ui/index.tsx +++ b/packages/editor/core/src/ui/index.tsx @@ -68,7 +68,6 @@ const TiptapEditor = ({ const editor = useEditor({ editable: editable ?? true, editorProps: TiptapEditorProps(uploadFile, setIsSubmitting), - // @ts-expect-err extensions: TiptapExtensions(uploadFile, deleteFile, setIsSubmitting), content: (typeof value === "string" && value.trim() !== "") ? value : "

", onUpdate: async ({ editor }) => { diff --git a/packages/editor/core/src/ui/props.tsx b/packages/editor/core/src/ui/props.tsx index 528f664ea26..d2a0d80639b 100644 --- a/packages/editor/core/src/ui/props.tsx +++ b/packages/editor/core/src/ui/props.tsx @@ -58,7 +58,6 @@ export function TiptapEditorProps( 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, uploadFile, setIsSubmitting); } diff --git a/packages/editor/rich-text-editor/src/extensions.tsx b/packages/editor/rich-text-editor/src/extensions.tsx new file mode 100644 index 00000000000..85087e5e1f9 --- /dev/null +++ b/packages/editor/rich-text-editor/src/extensions.tsx @@ -0,0 +1,66 @@ +import HorizontalRule from "@tiptap/extension-horizontal-rule"; +import { TableRow } from "@tiptap/extension-table-row"; +import Placeholder from "@tiptap/extension-placeholder"; +import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight"; +import { InputRule } from "@tiptap/core"; + +import ts from "highlight.js/lib/languages/typescript"; +import { lowlight } from "lowlight/lib/core"; +import "highlight.js/styles/github-dark.css"; +import { Table } from "./table/table"; +import { TableHeader } from "./table/table-header"; +import { CustomTableCell } from "./table/table-cell"; +import SlashCommand from "./slash-command"; +import { UploadImage } from "./types/upload-image"; + +lowlight.registerLanguage("ts", ts); + +export const TiptapExtensions = ( + uploadFile: UploadImage, + setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void +) => [ + CodeBlockLowlight.configure({ + lowlight, + }), + HorizontalRule.extend({ + addInputRules() { + return [ + new InputRule({ + find: /^(?:---|—-|___\s|\*\*\*\s)$/, + handler: ({ state, range, commands }) => { + commands.splitBlock(); + + const attributes = {}; + const { tr } = state; + const start = range.from; + const end = range.to; + // @ts-ignore + tr.replaceWith(start - 1, end, this.type.create(attributes)); + }, + }), + ]; + }, + }).configure({ + HTMLAttributes: { + class: "mb-6 border-t border-custom-border-300", + }, + }), + Placeholder.configure({ + placeholder: ({ node }) => { + if (node.type.name === "heading") { + return `Heading ${node.attrs.level}`; + } + if (node.type.name === "image" || node.type.name === "table") { + return ""; + } + + return "Press '/' for commands..."; + }, + includeChildren: true, + }), + SlashCommand(uploadFile, setIsSubmitting), + Table, + TableHeader, + CustomTableCell, + TableRow, + ]; diff --git a/packages/editor/rich-text-editor/src/index.tsx b/packages/editor/rich-text-editor/src/index.tsx new file mode 100644 index 00000000000..e69de29bb2d diff --git a/packages/editor/rich-text-editor/src/slash-command.tsx b/packages/editor/rich-text-editor/src/slash-command.tsx new file mode 100644 index 00000000000..844d4c55a58 --- /dev/null +++ b/packages/editor/rich-text-editor/src/slash-command.tsx @@ -0,0 +1,363 @@ +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/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 = + ( + 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, 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 = ( + uploadFile: UploadImage, + setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void +) => + Command.configure({ + suggestion: { + items: getSuggestionItems(uploadFile, setIsSubmitting), + render: renderItems, + }, + }); + +export default SlashCommand; diff --git a/packages/editor/rich-text-editor/src/table/table-cell.ts b/packages/editor/rich-text-editor/src/table/table-cell.ts new file mode 100644 index 00000000000..643cb8c64a7 --- /dev/null +++ b/packages/editor/rich-text-editor/src/table/table-cell.ts @@ -0,0 +1,32 @@ +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/rich-text-editor/src/table/table-header.ts b/packages/editor/rich-text-editor/src/table/table-header.ts new file mode 100644 index 00000000000..f23aa93ef55 --- /dev/null +++ b/packages/editor/rich-text-editor/src/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/packages/editor/rich-text-editor/src/table/table.ts b/packages/editor/rich-text-editor/src/table/table.ts new file mode 100644 index 00000000000..9b727bb51bd --- /dev/null +++ b/packages/editor/rich-text-editor/src/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/packages/editor/rich-text-editor/src/types/upload-image.ts b/packages/editor/rich-text-editor/src/types/upload-image.ts new file mode 100644 index 00000000000..3cf1408d22b --- /dev/null +++ b/packages/editor/rich-text-editor/src/types/upload-image.ts @@ -0,0 +1 @@ +export type UploadImage = (file: File) => Promise; diff --git a/packages/tailwind-config-custom/package.json b/packages/tailwind-config-custom/package.json index 1bd5a0e1cf9..b6c3ec614df 100644 --- a/packages/tailwind-config-custom/package.json +++ b/packages/tailwind-config-custom/package.json @@ -4,7 +4,12 @@ "description": "common tailwind configuration across monorepo", "main": "index.js", "devDependencies": { - "@tailwindcss/typography": "^0.5.10", - "tailwindcss-animate": "^1.0.7" + "@tailwindcss/typography": "^0.5.9", + "autoprefixer": "^10.4.14", + "postcss": "^8.4.21", + "prettier": "^2.8.8", + "prettier-plugin-tailwindcss": "^0.3.0", + "tailwindcss": "^3.2.7", + "tailwindcss-animate": "^1.0.6" } } diff --git a/web/postcss.config.js b/web/postcss.config.js index 129aa7f59ec..6887c82624a 100644 --- a/web/postcss.config.js +++ b/web/postcss.config.js @@ -1 +1,8 @@ -module.exports = require("tailwind-config-custom/postcss.config"); +module.exports = { + plugins: { + "postcss-import": {}, + "tailwindcss/nesting": {}, + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/yarn.lock b/yarn.lock index d92d076bfaf..b2d3e099b57 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2340,7 +2340,7 @@ dependencies: tslib "^2.4.0" -"@tailwindcss/typography@^0.5.10": +"@tailwindcss/typography@^0.5.9": version "0.5.10" resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.10.tgz#2abde4c6d5c797ab49cf47610830a301de4c1e0a" integrity sha512-Pe8BuPJQJd3FfRnm6H0ulKIGoMEQS+Vq01R6M5aCrFB/ccR/shT+0kXLjouGC1gFLm9hopTFN+DMP0pfwRWzPw== @@ -3193,6 +3193,18 @@ attr-accept@^2.2.2: resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b" integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== +autoprefixer@^10.4.14: + version "10.4.16" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.16.tgz#fad1411024d8670880bdece3970aa72e3572feb8" + integrity sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ== + dependencies: + browserslist "^4.21.10" + caniuse-lite "^1.0.30001538" + fraction.js "^4.3.6" + normalize-range "^0.1.2" + picocolors "^1.0.0" + postcss-value-parser "^4.2.0" + autoprefixer@^10.4.15: version "10.4.15" resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.15.tgz#a1230f4aeb3636b89120b34a1f513e2f6834d530" @@ -3406,6 +3418,11 @@ caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001517, caniuse-lite@^1.0.300015 resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001538.tgz#9dbc6b9af1ff06b5eb12350c2012b3af56744f3f" integrity sha512-HWJnhnID+0YMtGlzcp3T9drmBJUVDchPJ08tpUGFLs9CYlwWPH2uLgpHn8fND5pCgXVtnGS3H4QR9XLMHVNkHw== +caniuse-lite@^1.0.30001538: + version "1.0.30001541" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001541.tgz#b1aef0fadd87fb72db4dcb55d220eae17b81cdb1" + integrity sha512-bLOsqxDgTqUBkzxbNlSBt8annkDpQB9NdzdTbO2ooJ+eC/IQcvDspDc058g84ejCelF7vHUx57KIOjEecOHXaw== + capital-case@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/capital-case/-/capital-case-1.0.4.tgz#9d130292353c9249f6b00fa5852bee38a717e669" @@ -4860,7 +4877,7 @@ format@^0.2.0: resolved "https://registry.yarnpkg.com/format/-/format-0.2.2.tgz#d6170107e9efdc4ed30c9dc39016df942b5cb58b" integrity sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww== -fraction.js@^4.2.0: +fraction.js@^4.2.0, fraction.js@^4.3.6: version "4.3.6" resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.6.tgz#e9e3acec6c9a28cf7bc36cbe35eea4ceb2c5c92d" integrity sha512-n2aZ9tNfYDwaHhvFTkhFErqOMIb8uyzSQ+vGJBjZyanAKZVbGUQ1sngfk9FdkBw7G26O7AgNjLcecLffD1c7eg== @@ -6811,7 +6828,7 @@ postcss@8.4.14: picocolors "^1.0.0" source-map-js "^1.0.2" -postcss@^8.4.23, postcss@^8.4.29: +postcss@^8.4.21, postcss@^8.4.23, postcss@^8.4.29: version "8.4.30" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.30.tgz#0e0648d551a606ef2192a26da4cabafcc09c1aa7" integrity sha512-7ZEao1g4kd68l97aWG/etQKPKq07us0ieSZ2TnFDk11i0ZfDW2AwKHYU8qv4MZKqN2fdBfg+7q0ES06UA73C1g== @@ -6843,12 +6860,17 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== +prettier-plugin-tailwindcss@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.3.0.tgz#8299b307c7f6467f52732265579ed9375be6c818" + integrity sha512-009/Xqdy7UmkcTBpwlq7jsViDqXAYSOMLDrHAdTMlVZOrKfM2o9Ci7EMWTMZ7SkKBFTG04UM9F9iM2+4i6boDA== + prettier-plugin-tailwindcss@^0.5.4: version "0.5.4" resolved "https://registry.yarnpkg.com/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.5.4.tgz#ebfacbcb90e2ca1df671ffe4083e99f81d72040d" integrity sha512-QZzzB1bID6qPsKHTeA9qPo1APmmxfFrA5DD3LQ+vbTmAnY40eJI7t9Q1ocqel2EKMWNPLJqdTDWZj1hKYgqSgg== -prettier@^2.8.7: +prettier@^2.8.7, prettier@^2.8.8: version "2.8.8" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== @@ -7977,12 +7999,12 @@ tailwind-merge@^1.14.0: resolved "https://registry.yarnpkg.com/tailwind-merge/-/tailwind-merge-1.14.0.tgz#e677f55d864edc6794562c63f5001f45093cdb8b" integrity sha512-3mFKyCo/MBcgyOTlrY8T7odzZFx+w+qKSMAmdFzRvqBfLlSigU6TZnlFHK0lkMwj9Bj8OYU+9yW9lmGuS0QEnQ== -tailwindcss-animate@^1.0.7: +tailwindcss-animate@^1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/tailwindcss-animate/-/tailwindcss-animate-1.0.7.tgz#318b692c4c42676cc9e67b19b78775742388bef4" integrity sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA== -tailwindcss@^3.3.3: +tailwindcss@^3.2.7, tailwindcss@^3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.3.3.tgz#90da807393a2859189e48e9e7000e6880a736daf" integrity sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w== From da86f1ad03a3f7205549a20456740e74cb59a10b Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Sat, 30 Sep 2023 17:20:59 +0530 Subject: [PATCH 22/57] refactoring to LiteTextEditor and RichTextEditor --- packages/editor/core/package.json | 2 +- packages/editor/core/src/hooks/useEditor.tsx | 34 -- packages/editor/core/src/index.ts | 17 +- packages/editor/core/src/interfaces/index.ts | 4 - packages/editor/core/src/lib/utils.ts | 16 +- .../editor/core/src/ui/editor-container.tsx | 20 + .../editor/core/src/ui/editor-content.tsx | 19 + .../image/{updated-image.tsx => index.tsx} | 4 +- .../core/src/ui/extensions/index-new.tsx | 88 ----- .../editor/core/src/ui/extensions/index.tsx | 69 +--- .../editor/core/src/ui/hooks/useEditor.tsx | 70 ++++ packages/editor/core/src/ui/index-new.tsx | 150 -------- packages/editor/core/src/ui/index.tsx | 94 ++--- packages/editor/core/src/useEditor.tsx | 35 -- packages/editor/lite-text-editor/package.json | 25 +- packages/editor/lite-text-editor/src/index.ts | 1 + .../editor/lite-text-editor/src/ui/index.tsx | 96 +++++ .../src/ui/menus/fixed-menu/icon.tsx | 13 + .../src/ui/menus/fixed-menu/index.tsx | 115 ++++++ .../src/ui/menus/fixed-menu/tooltip.tsx | 77 ++++ packages/editor/rich-text-editor/package.json | 37 +- .../rich-text-editor/src/extensions.tsx | 66 ---- packages/editor/rich-text-editor/src/index.ts | 1 + .../editor/rich-text-editor/src/index.tsx | 0 .../rich-text-editor/src/slash-command.tsx | 363 ------------------ .../rich-text-editor/src/table/table-cell.ts | 32 -- .../src/table/table-header.ts | 7 - .../rich-text-editor/src/table/table.ts | 9 - .../src/types/upload-image.ts | 1 - .../src/ui/extensions/index.tsx | 20 + .../src/ui/extensions/slash-command.tsx | 5 +- .../editor/rich-text-editor/src/ui/index.tsx | 83 ++++ .../src/ui/menus/bubble-menu/index.tsx | 121 ++++++ .../ui/menus/bubble-menu/link-selector.tsx | 93 +++++ .../ui/menus/bubble-menu/node-selector.tsx | 130 +++++++ .../src/ui/menus/bubble-menu/utils/index.tsx | 11 + .../peek-overview/comment/add-comment.tsx | 7 +- .../comment/comment-detail-card.tsx | 12 +- .../issues/peek-overview/issue-details.tsx | 7 +- space/package.json | 2 +- space/services/file.service.ts | 18 +- turbo.json | 2 +- .../core/modals/gpt-assistant-modal.tsx | 12 +- web/components/issues/comment/add-comment.tsx | 15 +- .../issues/comment/comment-card.tsx | 12 +- web/components/issues/description-form.tsx | 4 +- web/components/issues/draft-issue-form.tsx | 5 +- web/components/issues/form.tsx | 5 +- .../pages/create-update-block-inline.tsx | 8 +- web/components/pages/single-page-block.tsx | 7 +- web/components/web-view/add-comment.tsx | 5 +- .../web-view/issue-web-view-form.tsx | 7 +- web/package.json | 3 +- web/pages/[workspaceSlug]/editor.tsx | 7 +- .../[workspaceSlug]/me/profile/activity.tsx | 7 +- web/pages/m/[workspaceSlug]/editor.tsx | 7 +- yarn.lock | 2 +- 57 files changed, 1005 insertions(+), 1077 deletions(-) delete mode 100644 packages/editor/core/src/hooks/useEditor.tsx delete mode 100644 packages/editor/core/src/interfaces/index.ts create mode 100644 packages/editor/core/src/ui/editor-container.tsx create mode 100644 packages/editor/core/src/ui/editor-content.tsx rename packages/editor/core/src/ui/extensions/image/{updated-image.tsx => index.tsx} (83%) delete mode 100644 packages/editor/core/src/ui/extensions/index-new.tsx create mode 100644 packages/editor/core/src/ui/hooks/useEditor.tsx delete mode 100644 packages/editor/core/src/ui/index-new.tsx delete mode 100644 packages/editor/core/src/useEditor.tsx create mode 100644 packages/editor/lite-text-editor/src/index.ts create mode 100644 packages/editor/lite-text-editor/src/ui/index.tsx create mode 100644 packages/editor/lite-text-editor/src/ui/menus/fixed-menu/icon.tsx create mode 100644 packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx create mode 100644 packages/editor/lite-text-editor/src/ui/menus/fixed-menu/tooltip.tsx delete mode 100644 packages/editor/rich-text-editor/src/extensions.tsx create mode 100644 packages/editor/rich-text-editor/src/index.ts delete mode 100644 packages/editor/rich-text-editor/src/index.tsx delete mode 100644 packages/editor/rich-text-editor/src/slash-command.tsx delete mode 100644 packages/editor/rich-text-editor/src/table/table-cell.ts delete mode 100644 packages/editor/rich-text-editor/src/table/table-header.ts delete mode 100644 packages/editor/rich-text-editor/src/table/table.ts delete mode 100644 packages/editor/rich-text-editor/src/types/upload-image.ts create mode 100644 packages/editor/rich-text-editor/src/ui/extensions/index.tsx rename packages/editor/{core => rich-text-editor}/src/ui/extensions/slash-command.tsx (98%) create mode 100644 packages/editor/rich-text-editor/src/ui/index.tsx create mode 100644 packages/editor/rich-text-editor/src/ui/menus/bubble-menu/index.tsx create mode 100644 packages/editor/rich-text-editor/src/ui/menus/bubble-menu/link-selector.tsx create mode 100644 packages/editor/rich-text-editor/src/ui/menus/bubble-menu/node-selector.tsx create mode 100644 packages/editor/rich-text-editor/src/ui/menus/bubble-menu/utils/index.tsx diff --git a/packages/editor/core/package.json b/packages/editor/core/package.json index a6a61cffbe4..9cf27203c27 100644 --- a/packages/editor/core/package.json +++ b/packages/editor/core/package.json @@ -1,5 +1,5 @@ { - "name": "@plane/editor", + "name": "@plane/editor-core", "version": "0.0.1", "description": "Rich Text Editor that powers Plane", "main": "./dist/index.mjs", diff --git a/packages/editor/core/src/hooks/useEditor.tsx b/packages/editor/core/src/hooks/useEditor.tsx deleted file mode 100644 index 9d121fcfffa..00000000000 --- a/packages/editor/core/src/hooks/useEditor.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { DeleteImage } from "@/types/delete-image"; -import { UploadImage } from "@/types/upload-image"; -import { TiptapExtensions } from "@/ui/extensions"; -import { TiptapEditorProps } from "@/ui/props"; -import { useEditor as useTiptapEditor } from "@tiptap/react"; - -interface ITiptapEditor { - value: string; - uploadFile: UploadImage; - deleteFile: DeleteImage; - onChange?: (json: any, html: string) => void; - setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void; - setShouldShowAlert?: (showAlert: boolean) => void; - editable?: boolean; - debouncedUpdatesEnabled?: boolean; - debouncedUpdates: ({ onChange, editor }: { onChange?: (json: any, html: string) => void; editor: any }) => void; -} - -export const useEditor = ({ uploadFile, debouncedUpdates, setShouldShowAlert, deleteFile, setIsSubmitting, value, onChange, debouncedUpdatesEnabled, editable }: ITiptapEditor) => useTiptapEditor({ - editable: editable ?? true, - editorProps: TiptapEditorProps(uploadFile, setIsSubmitting), - extensions: TiptapExtensions(uploadFile, deleteFile, setIsSubmitting), - content: (typeof value === "string" && value.trim() !== "") ? value : "

", - onUpdate: async ({ editor }) => { - // for instant feedback loop - setIsSubmitting?.("submitting"); - setShouldShowAlert?.(true); - if (debouncedUpdatesEnabled) { - debouncedUpdates({ onChange, editor }); - } else { - onChange?.(editor.getJSON(), editor.getHTML()); - } - }, -}); diff --git a/packages/editor/core/src/index.ts b/packages/editor/core/src/index.ts index 890841cb9e4..1fc9b618cb2 100644 --- a/packages/editor/core/src/index.ts +++ b/packages/editor/core/src/index.ts @@ -1,13 +1,10 @@ import "@/styles/tailwind.css"; import "@/styles/editor.css"; -// export { ImageResizer } from "./ui/extensions/image/image-resize"; -// export { TiptapEditorProps } from "./ui/props"; -// export { TableMenu } from "./ui/menus/table-menu"; -// export { TiptapExtensions } from "./ui/extensions"; -// export { cn } from "./lib/utils"; -// export { FixedMenu } from "./ui/menus/fixed-menu"; -// export { EditorBubbleMenu } from "./ui/menus/bubble-menu"; +export { startImageUpload } from "@/ui/plugins/upload-image"; -export { TiptapEditor, TiptapEditorWithRef } from "@/ui"; - -export { useEditor } from "@/useEditor"; +// export { TiptapEditor, TiptapEditorWithRef } from "@/ui"; +export { useEditor } from "@/ui/hooks/useEditor"; +export { cn } from "@/lib/utils"; +export { getEditorClassNames } from "@/lib/utils"; +export { EditorContainer } from "@/ui/editor-container"; +export { EditorContentWrapper } from "@/ui/editor-content"; diff --git a/packages/editor/core/src/interfaces/index.ts b/packages/editor/core/src/interfaces/index.ts deleted file mode 100644 index 7f5492df7dd..00000000000 --- a/packages/editor/core/src/interfaces/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface EditorHandle { - clearEditor: () => void; - setEditorValue: (content: string) => void; -} diff --git a/packages/editor/core/src/lib/utils.ts b/packages/editor/core/src/lib/utils.ts index 1c985922b92..64b5a3db76b 100644 --- a/packages/editor/core/src/lib/utils.ts +++ b/packages/editor/core/src/lib/utils.ts @@ -12,4 +12,18 @@ export const findTableAncestor = ( node = node.parentNode; } return node as HTMLTableElement; -}; \ No newline at end of file +}; + +interface EditorClassNames { + noBorder?: boolean; + borderOnFocus?: boolean; + customClassName?: string; +} + +export const getEditorClassNames = ({ noBorder, borderOnFocus, customClassName }: EditorClassNames) => cn( + 'relative w-full max-w-full sm:rounded-lg mt-2 p-3 relative focus:outline-none rounded-md', + noBorder ? '' : 'border border-custom-border-200', + borderOnFocus ? 'focus:border border-custom-border-300' : 'focus:border-0', + customClassName +); + diff --git a/packages/editor/core/src/ui/editor-container.tsx b/packages/editor/core/src/ui/editor-container.tsx new file mode 100644 index 00000000000..fca24f96261 --- /dev/null +++ b/packages/editor/core/src/ui/editor-container.tsx @@ -0,0 +1,20 @@ +import { Editor } from "@tiptap/react"; +import { ReactNode } from "react"; + +interface EditorContainerProps { + editor: Editor | null; + editorClassNames: string; + children: ReactNode; +} + +export const EditorContainer = ({ editor, editorClassNames, children }: EditorContainerProps) => ( +
{ + editor?.chain().focus().run(); + }} + className={`tiptap-editor-container cursor-text ${editorClassNames}`} + > + {children} +
+); diff --git a/packages/editor/core/src/ui/editor-content.tsx b/packages/editor/core/src/ui/editor-content.tsx new file mode 100644 index 00000000000..7b06944d878 --- /dev/null +++ b/packages/editor/core/src/ui/editor-content.tsx @@ -0,0 +1,19 @@ +import { Editor, EditorContent } from "@tiptap/react"; +import { ReactNode } from "react"; +import { ImageResizer } from "@/ui/extensions/image/image-resize"; +import { TableMenu } from "./menus/table-menu"; + +interface EditorContentProps { + editor: Editor | null; + editorContentCustomClassNames: string | undefined; + children?: ReactNode; +} + +export const EditorContentWrapper = ({ editor, editorContentCustomClassNames = '', children }: EditorContentProps) => ( +
+ + + {editor?.isActive("image") && } + {children} +
+); diff --git a/packages/editor/core/src/ui/extensions/image/updated-image.tsx b/packages/editor/core/src/ui/extensions/image/index.tsx similarity index 83% rename from packages/editor/core/src/ui/extensions/image/updated-image.tsx rename to packages/editor/core/src/ui/extensions/image/index.tsx index 9157e890569..ac8d4359731 100644 --- a/packages/editor/core/src/ui/extensions/image/updated-image.tsx +++ b/packages/editor/core/src/ui/extensions/image/index.tsx @@ -3,7 +3,7 @@ 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({ +const ImageExtension = (deleteImage: DeleteImage) => Image.extend({ addProseMirrorPlugins() { return [UploadImagesPlugin(), TrackImageDeletionPlugin(deleteImage)]; }, @@ -20,4 +20,4 @@ const UpdatedImage = (deleteImage: DeleteImage) => Image.extend({ }, }); -export default UpdatedImage; +export default ImageExtension; diff --git a/packages/editor/core/src/ui/extensions/index-new.tsx b/packages/editor/core/src/ui/extensions/index-new.tsx deleted file mode 100644 index 27639fe06d4..00000000000 --- a/packages/editor/core/src/ui/extensions/index-new.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import StarterKit from "@tiptap/starter-kit"; -import TiptapLink from "@tiptap/extension-link"; -import TiptapUnderline from "@tiptap/extension-underline"; -import TextStyle from "@tiptap/extension-text-style"; -import { Color } from "@tiptap/extension-color"; -import TaskItem from "@tiptap/extension-task-item"; -import TaskList from "@tiptap/extension-task-list"; -import { Markdown } from "tiptap-markdown"; -import Gapcursor from "@tiptap/extension-gapcursor"; - -import UpdatedImage from "@/ui/extensions/image/updated-image"; - -import { DeleteImage } from "@/types/delete-image"; - -import isValidHttpUrl from "@/ui/menus/bubble-menu/utils" - -export const TiptapExtensions = ( - deleteFile: DeleteImage, -) => [ - StarterKit.configure({ - bulletList: { - HTMLAttributes: { - class: "list-disc list-outside leading-3 -mt-2", - }, - }, - orderedList: { - HTMLAttributes: { - class: "list-decimal list-outside leading-3 -mt-2", - }, - }, - listItem: { - HTMLAttributes: { - class: "leading-normal -mb-2", - }, - }, - blockquote: { - HTMLAttributes: { - class: "border-l-4 border-custom-border-300", - }, - }, - code: { - HTMLAttributes: { - class: - "rounded-md bg-custom-primary-30 mx-1 px-1 py-1 font-mono font-medium text-custom-text-1000", - spellcheck: "false", - }, - }, - codeBlock: false, - horizontalRule: false, - dropcursor: { - color: "rgba(var(--color-text-100))", - width: 2, - }, - gapcursor: false, - }), - Gapcursor, - TiptapLink.configure({ - protocols: ["http", "https"], - validate: (url) => isValidHttpUrl(url), - HTMLAttributes: { - class: - "text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer", - }, - }), - UpdatedImage(deleteFile).configure({ - HTMLAttributes: { - class: "rounded-lg border border-custom-border-300", - }, - }), - TiptapUnderline, - TextStyle, - Color, - TaskList.configure({ - HTMLAttributes: { - class: "not-prose pl-2", - }, - }), - TaskItem.configure({ - HTMLAttributes: { - class: "flex items-start my-4", - }, - nested: true, - }), - Markdown.configure({ - html: true, - transformCopiedText: true, - }), - ]; diff --git a/packages/editor/core/src/ui/extensions/index.tsx b/packages/editor/core/src/ui/extensions/index.tsx index 1c113244483..65fb7582d17 100644 --- a/packages/editor/core/src/ui/extensions/index.tsx +++ b/packages/editor/core/src/ui/extensions/index.tsx @@ -1,40 +1,26 @@ import StarterKit from "@tiptap/starter-kit"; -import HorizontalRule from "@tiptap/extension-horizontal-rule"; import TiptapLink from "@tiptap/extension-link"; -import Placeholder from "@tiptap/extension-placeholder"; import TiptapUnderline from "@tiptap/extension-underline"; import TextStyle from "@tiptap/extension-text-style"; import { Color } from "@tiptap/extension-color"; import TaskItem from "@tiptap/extension-task-item"; import TaskList from "@tiptap/extension-task-list"; import { Markdown } from "tiptap-markdown"; -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/extensions/table/table"; -import { TableHeader } from "@/ui/extensions/table/table-header"; + +import { CustomTableCell } from "./table/table-cell"; +import { Table } from "./table/table"; +import { TableHeader } from "./table/table-header"; import { TableRow } from "@tiptap/extension-table-row"; -import { CustomTableCell } from "@/ui/extensions/table/table-cell"; -import UpdatedImage from "@/ui/extensions/image/updated-image"; -import SlashCommand from "@/ui/extensions/slash-command"; +import ImageExtension from "@/ui/extensions/image"; import { DeleteImage } from "@/types/delete-image"; -import { UploadImage } from "@/types/upload-image"; import isValidHttpUrl from "@/ui/menus/bubble-menu/utils" -import ts from "highlight.js/lib/languages/typescript"; -import { lowlight } from "lowlight/lib/core"; -import "highlight.js/styles/github-dark.css"; - -lowlight.registerLanguage("ts", ts); - export const TiptapExtensions = ( - uploadFile: UploadImage, deleteFile: DeleteImage, - setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void ) => [ StarterKit.configure({ bulletList: { @@ -72,32 +58,6 @@ export const TiptapExtensions = ( }, gapcursor: false, }), - CodeBlockLowlight.configure({ - lowlight, - }), - HorizontalRule.extend({ - addInputRules() { - return [ - new InputRule({ - find: /^(?:---|—-|___\s|\*\*\*\s)$/, - handler: ({ state, range, commands }) => { - commands.splitBlock(); - - const attributes = {}; - const { tr } = state; - const start = range.from; - const end = range.to; - // @ts-ignore - tr.replaceWith(start - 1, end, this.type.create(attributes)); - }, - }), - ]; - }, - }).configure({ - HTMLAttributes: { - class: "mb-6 border-t border-custom-border-300", - }, - }), Gapcursor, TiptapLink.configure({ protocols: ["http", "https"], @@ -107,31 +67,14 @@ export const TiptapExtensions = ( "text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer", }, }), - UpdatedImage(deleteFile).configure({ + ImageExtension(deleteFile).configure({ HTMLAttributes: { class: "rounded-lg border border-custom-border-300", }, }), - Placeholder.configure({ - placeholder: ({ node }) => { - if (node.type.name === "heading") { - return `Heading ${node.attrs.level}`; - } - if (node.type.name === "image" || node.type.name === "table") { - return ""; - } - - return "Press '/' for commands..."; - }, - includeChildren: true, - }), - SlashCommand(uploadFile, setIsSubmitting), TiptapUnderline, TextStyle, Color, - Highlight.configure({ - multicolor: true, - }), TaskList.configure({ HTMLAttributes: { class: "not-prose pl-2", diff --git a/packages/editor/core/src/ui/hooks/useEditor.tsx b/packages/editor/core/src/ui/hooks/useEditor.tsx new file mode 100644 index 00000000000..cec52d25f38 --- /dev/null +++ b/packages/editor/core/src/ui/hooks/useEditor.tsx @@ -0,0 +1,70 @@ +import { useEditor as useCustomEditor, Editor, Extension } from "@tiptap/react"; +import { useImperativeHandle, useRef, MutableRefObject, forwardRef } from "react"; +import { useDebouncedCallback } from "use-debounce"; +import { UploadImage } from '@/types/upload-image'; +import { DeleteImage } from '@/types/delete-image'; +import { TiptapEditorProps } from "../props"; +import { TiptapExtensions } from "../extensions"; +import { EditorProps } from '@tiptap/pm/view'; + +const DEBOUNCE_DELAY = 1500; + +interface CustomEditorProps { + editable?: boolean; + uploadFile: UploadImage; + setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void; + setShouldShowAlert?: (showAlert: boolean) => void; + value: string; + deleteFile: DeleteImage; + debouncedUpdatesEnabled?: boolean; + onChange?: (json: any, html: string) => void; + extensions?: Extension[]; + editorProps?: EditorProps; + forwardedRef?: any; +} + +export const useEditor = ({ uploadFile, editable, deleteFile, editorProps = {}, value, extensions = [], onChange, setIsSubmitting, debouncedUpdatesEnabled, forwardedRef, setShouldShowAlert, }: CustomEditorProps) => { + const editor = useCustomEditor({ + editable: editable ?? true, + editorProps: { + ...TiptapEditorProps(uploadFile, setIsSubmitting), + ...editorProps, + }, + extensions: [...TiptapExtensions(deleteFile), ...extensions], + content: (typeof value === "string" && value.trim() !== "") ? value : "

", + onUpdate: async ({ editor }) => { + // for instant feedback loop + setIsSubmitting?.("submitting"); + setShouldShowAlert?.(true); + if (debouncedUpdatesEnabled) { + debouncedUpdates({ onChange: onChange, editor }); + } else { + onChange?.(editor.getJSON(), editor.getHTML()); + } + }, + }); + + const editorRef: MutableRefObject = useRef(null); + editorRef.current = editor; + + useImperativeHandle(forwardedRef, () => ({ + clearEditor: () => { + editorRef.current?.commands.clearContent(); + }, + setEditorValue: (content: string) => { + editorRef.current?.commands.setContent(content); + }, + })); + + const debouncedUpdates = useDebouncedCallback(async ({ onChange, editor }) => { + if (onChange) { + onChange(editor.getJSON(), editor.getHTML()); + } + }, DEBOUNCE_DELAY); + + if (!editor) { + return null; + } + + return editor; +}; diff --git a/packages/editor/core/src/ui/index-new.tsx b/packages/editor/core/src/ui/index-new.tsx deleted file mode 100644 index b6e42348b84..00000000000 --- a/packages/editor/core/src/ui/index-new.tsx +++ /dev/null @@ -1,150 +0,0 @@ -"use client" -import * as React from 'react'; -import { useImperativeHandle, useRef, forwardRef } from "react"; -import { useEditor, EditorContent, Editor, Extension } from "@tiptap/react"; -import { useDebouncedCallback } from "use-debounce"; -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'; -import { FixedMenu } from './menus/fixed-menu'; -import { EditorProps } from '@tiptap/pm/view'; - -interface ITiptapEditor { - value: string; - uploadFile: UploadImage; - deleteFile: DeleteImage; - noBorder?: boolean; - borderOnFocus?: boolean; - customClassName?: string; - editorContentCustomClassNames?: string; - onChange?: (json: any, html: string) => void; - setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void; - setShouldShowAlert?: (showAlert: boolean) => void; - editable?: boolean; - forwardedRef?: any; - debouncedUpdatesEnabled?: boolean; - accessValue: string; - onAccessChange: (accessKey: string) => void; - commentAccess: { - icon: string; - key: string; - label: "Private" | "Public"; - }[]; - extensions?: Extension[]; - editorProps?: EditorProps; -} - -interface TiptapProps extends ITiptapEditor { - forwardedRef?: React.Ref; -} - -interface EditorHandle { - clearEditor: () => void; - setEditorValue: (content: string) => void; -} - -const DEBOUNCE_DELAY = 1500; - -const TiptapEditor = ({ - onChange, - debouncedUpdatesEnabled, - editable, - setIsSubmitting, - setShouldShowAlert, - editorContentCustomClassNames, - value, - uploadFile, - extensions = [], - editorProps = {}, - deleteFile, - noBorder, - borderOnFocus, - customClassName, - forwardedRef, - accessValue, - onAccessChange, - commentAccess, -}: TiptapProps) => { - const editor = useEditor({ - editable: editable ?? true, - editorProps: { - ...TiptapEditorProps(uploadFile, setIsSubmitting), - ...editorProps, - }, - extensions: [...TiptapExtensions(uploadFile, deleteFile, setIsSubmitting), ...extensions], - content: (typeof value === "string" && value.trim() !== "") ? value : "

", - onUpdate: async ({ editor }) => { - // for instant feedback loop - setIsSubmitting?.("submitting"); - setShouldShowAlert?.(true); - if (debouncedUpdatesEnabled) { - debouncedUpdates({ onChange, editor }); - } else { - onChange?.(editor.getJSON(), editor.getHTML()); - } - }, - }); - - const editorRef: React.MutableRefObject = useRef(null); - editorRef.current = editor; - - useImperativeHandle(forwardedRef, () => ({ - clearEditor: () => { - editorRef.current?.commands.clearContent(); - }, - setEditorValue: (content: string) => { - editorRef.current?.commands.setContent(content); - }, - })); - - const debouncedUpdates = useDebouncedCallback(async ({ onChange, editor }) => { - if (onChange) { - onChange(editor.getJSON(), editor.getHTML()); - } - }, DEBOUNCE_DELAY); - - const editorClassNames = cn( - 'relative w-full max-w-full sm:rounded-lg mt-2 p-3 relative focus:outline-none rounded-md', - noBorder ? '' : 'border border-custom-border-200', - borderOnFocus ? 'focus:border border-custom-border-300' : 'focus:border-0', - customClassName - ); - - if (!editor) return null; - - return ( -
{ - editor?.chain().focus().run(); - }} - className={`tiptap-editor-container cursor-text ${editorClassNames}`} - > -
-
- - - {editor?.isActive("image") && } -
- {editor && editable !== false && - (
- -
) - } -
-
- ); -}; - -const TiptapEditorWithRef = forwardRef((props, ref) => ( - -)); - -TiptapEditorWithRef.displayName = "TiptapEditorWithRef"; - -export { TiptapEditor, TiptapEditorWithRef }; diff --git a/packages/editor/core/src/ui/index.tsx b/packages/editor/core/src/ui/index.tsx index 28808f649aa..ae2654e1c42 100644 --- a/packages/editor/core/src/ui/index.tsx +++ b/packages/editor/core/src/ui/index.tsx @@ -1,17 +1,13 @@ "use client" 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/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 { Extension } from "@tiptap/react"; import { UploadImage } from '@/types/upload-image'; import { DeleteImage } from '@/types/delete-image'; -import { cn } from '@/lib/utils'; -import { FixedMenu } from './menus/fixed-menu'; +import { getEditorClassNames } from '@/lib/utils'; +import { EditorProps } from '@tiptap/pm/view'; +import { useEditor } from './hooks/useEditor'; +import { EditorContainer } from '@/ui/editor-container'; +import { EditorContentWrapper } from '@/ui/editor-content'; interface ITiptapEditor { value: string; @@ -34,6 +30,8 @@ interface ITiptapEditor { key: string; label: "Private" | "Public"; }[]; + extensions?: Extension[]; + editorProps?: EditorProps; } interface TiptapProps extends ITiptapEditor { @@ -45,8 +43,6 @@ interface EditorHandle { setEditorValue: (content: string) => void; } -const DEBOUNCE_DELAY = 1500; - const TiptapEditor = ({ onChange, debouncedUpdatesEnabled, @@ -61,79 +57,33 @@ const TiptapEditor = ({ borderOnFocus, customClassName, forwardedRef, - accessValue, - onAccessChange, - commentAccess, }: TiptapProps) => { const editor = useEditor({ - editable: editable ?? true, - editorProps: TiptapEditorProps(uploadFile, setIsSubmitting), - extensions: TiptapExtensions(uploadFile, deleteFile, setIsSubmitting), - content: (typeof value === "string" && value.trim() !== "") ? value : "

", - onUpdate: async ({ editor }) => { - // for instant feedback loop - setIsSubmitting?.("submitting"); - setShouldShowAlert?.(true); - if (debouncedUpdatesEnabled) { - debouncedUpdates({ onChange, editor }); - } else { - onChange?.(editor.getJSON(), editor.getHTML()); - } - }, + onChange, + debouncedUpdatesEnabled, + editable, + setIsSubmitting, + setShouldShowAlert, + value, + uploadFile, + deleteFile, + forwardedRef, }); - const editorRef: React.MutableRefObject = useRef(null); - editorRef.current = editor; - - useImperativeHandle(forwardedRef, () => ({ - clearEditor: () => { - editorRef.current?.commands.clearContent(); - }, - setEditorValue: (content: string) => { - editorRef.current?.commands.setContent(content); - }, - })); - - const debouncedUpdates = useDebouncedCallback(async ({ onChange, editor }) => { - if (onChange) { - onChange(editor.getJSON(), editor.getHTML()); - } - }, DEBOUNCE_DELAY); - - const editorClassNames = cn( - 'relative w-full max-w-full sm:rounded-lg mt-2 p-3 relative focus:outline-none rounded-md', - noBorder ? '' : 'border border-custom-border-200', - borderOnFocus ? 'focus:border border-custom-border-300' : 'focus:border-0', - customClassName - ); + const editorClassNames = getEditorClassNames({ noBorder, borderOnFocus, customClassName }); if (!editor) return null; return ( -
{ - editor?.chain().focus().run(); - }} - className={`tiptap-editor-container cursor-text ${editorClassNames}`} - > +
-
- - - {editor?.isActive("image") && } -
- {editor && editable !== false && - (
- -
) - } +
-
+ ); }; -const TiptapEditorWithRef = forwardRef((props, ref) => ( +const TiptapEditorWithRef = React.forwardRef((props, ref) => ( )); diff --git a/packages/editor/core/src/useEditor.tsx b/packages/editor/core/src/useEditor.tsx deleted file mode 100644 index 552c0ca2168..00000000000 --- a/packages/editor/core/src/useEditor.tsx +++ /dev/null @@ -1,35 +0,0 @@ -import { - useEditor as useEditorCore, -} from "@tiptap/react"; -import { findTableAncestor } from "@/lib/utils"; - -export const useEditor = (props: any) => useEditorCore({ - editorProps: { - 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: () => { - if (typeof window !== "undefined") { - const selection: any = window?.getSelection(); - if (selection.rangeCount !== 0) { - const range = selection.getRangeAt(0); - if (findTableAncestor(range.startContainer)) { - return; - } - } - } - }, - }, - ...props, -}); diff --git a/packages/editor/lite-text-editor/package.json b/packages/editor/lite-text-editor/package.json index fe1d7ee0126..f2805da9912 100644 --- a/packages/editor/lite-text-editor/package.json +++ b/packages/editor/lite-text-editor/package.json @@ -24,28 +24,6 @@ "react": "^18.2.0" }, "dependencies": { - "@blueprintjs/popover2": "^2.0.10", - "@radix-ui/react-slot": "^1.0.2", - "@tiptap/core": "^2.1.7", - "@tiptap/extension-code-block-lowlight": "^2.0.4", - "@tiptap/extension-color": "^2.1.11", - "@tiptap/extension-highlight": "^2.1.7", - "@tiptap/extension-horizontal-rule": "^2.1.7", - "@tiptap/extension-image": "^2.1.7", - "@tiptap/extension-link": "^2.1.7", - "@tiptap/extension-placeholder": "2.0.3", - "@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.1.7", - "@tiptap/extension-task-list": "^2.1.7", - "@tiptap/extension-text-style": "^2.1.11", - "@tiptap/extension-underline": "^2.1.7", - "@tiptap/pm": "^2.1.7", - "@tiptap/react": "^2.1.7", - "@tiptap/starter-kit": "^2.1.10", - "@tiptap/suggestion": "^2.1.7", "@types/node": "18.15.3", "@types/react": "18.0.28", "@types/react-dom": "18.0.11", @@ -64,7 +42,8 @@ "tailwind-merge": "^1.14.0", "tippy.js": "^6.3.7", "tiptap-markdown": "^0.8.2", - "use-debounce": "^9.0.4" + "use-debounce": "^9.0.4", + "@plane/editor-core": "*" }, "devDependencies": { "@types/react": "^18.2.5", diff --git a/packages/editor/lite-text-editor/src/index.ts b/packages/editor/lite-text-editor/src/index.ts new file mode 100644 index 00000000000..9238be8b965 --- /dev/null +++ b/packages/editor/lite-text-editor/src/index.ts @@ -0,0 +1 @@ +export { LiteTextEditor, LiteTextEditorWithRef } from "@/ui"; diff --git a/packages/editor/lite-text-editor/src/ui/index.tsx b/packages/editor/lite-text-editor/src/ui/index.tsx new file mode 100644 index 00000000000..ce87a39b3cf --- /dev/null +++ b/packages/editor/lite-text-editor/src/ui/index.tsx @@ -0,0 +1,96 @@ +"use client" +import * as React from 'react'; +import { EditorContainer, EditorContentWrapper, getEditorClassNames, useEditor } from '@plane/editor-core'; +import { FixedMenu } from './menus/fixed-menu'; + +export type UploadImage = (file: File) => Promise; +export type DeleteImage = (assetUrlWithWorkspaceId: string) => Promise; + +interface ITiptapEditor { + value: string; + uploadFile: UploadImage; + deleteFile: DeleteImage; + noBorder?: boolean; + borderOnFocus?: boolean; + customClassName?: string; + editorContentCustomClassNames?: string; + onChange?: (json: any, html: string) => void; + setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void; + setShouldShowAlert?: (showAlert: boolean) => void; + editable?: boolean; + forwardedRef?: any; + debouncedUpdatesEnabled?: boolean; + commentAccessSpecifier?: { + accessValue: string, + onAccessChange: (accessKey: string) => void, + showAccessSpecifier: boolean, + commentAccess: { + icon: string; + key: string; + label: "Private" | "Public"; + }[] + } +} + +interface TiptapProps extends ITiptapEditor { + forwardedRef?: React.Ref; +} + +interface EditorHandle { + clearEditor: () => void; + setEditorValue: (content: string) => void; +} + +const LiteTextEditor = ({ + onChange, + debouncedUpdatesEnabled, + editable, + setIsSubmitting, + setShouldShowAlert, + editorContentCustomClassNames, + value, + uploadFile, + deleteFile, + noBorder, + borderOnFocus, + customClassName, + forwardedRef, + commentAccessSpecifier, +}: TiptapProps) => { + const editor = useEditor({ + onChange, + debouncedUpdatesEnabled, + editable, + setIsSubmitting, + setShouldShowAlert, + value, + uploadFile, + deleteFile, + forwardedRef, + }); + + const editorClassNames = getEditorClassNames({ noBorder, borderOnFocus, customClassName }); + + if (!editor) return null; + + return ( + +
+ + {(editable !== false) && + (
+ +
) + } +
+
+ ); +}; + +const LiteTextEditorWithRef = React.forwardRef((props, ref) => ( + +)); + +LiteTextEditorWithRef.displayName = "LiteTextEditorWithRef"; + +export { LiteTextEditor, LiteTextEditorWithRef }; diff --git a/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/icon.tsx b/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/icon.tsx new file mode 100644 index 00000000000..c0006b3f257 --- /dev/null +++ b/packages/editor/lite-text-editor/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/lite-text-editor/src/ui/menus/fixed-menu/index.tsx b/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx new file mode 100644 index 00000000000..0cece1d580f --- /dev/null +++ b/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx @@ -0,0 +1,115 @@ +import { Editor } from "@tiptap/react"; +import { BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, CodeIcon } from "lucide-react"; + +import { cn } from "@plane/editor-core"; +import { Tooltip } from "./tooltip"; +import { Icon } from "./icon"; + +export interface BubbleMenuItem { + name: string; + isActive: () => boolean; + command: () => void; + icon: typeof BoldIcon; +} + +type EditorBubbleMenuProps = { + editor: Editor; + commentAccessSpecifier?: { + accessValue: string, + onAccessChange: (accessKey: string) => void, + showAccessSpecifier: boolean, + commentAccess: { + icon: string; + key: string; + label: "Private" | "Public"; + }[] | undefined; + } +} + +export const FixedMenu = (props: EditorBubbleMenuProps) => { + 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 handleAccessChange = (accessKey: string) => { + props.commentAccessSpecifier?.onAccessChange(accessKey); + }; + + + return ( +
+
+ {props.commentAccessSpecifier && (
+ {props?.commentAccessSpecifier.commentAccess?.map((access) => ( + + + + ))} +
)} + {items.map((item, index) => ( + + ))} +
+
+ ); +}; diff --git a/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/tooltip.tsx b/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/tooltip.tsx new file mode 100644 index 00000000000..f29d8a49177 --- /dev/null +++ b/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/tooltip.tsx @@ -0,0 +1,77 @@ +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/rich-text-editor/package.json b/packages/editor/rich-text-editor/package.json index 3dc8f2b271b..27ca22ac472 100644 --- a/packages/editor/rich-text-editor/package.json +++ b/packages/editor/rich-text-editor/package.json @@ -24,49 +24,18 @@ "react": "^18.2.0" }, "dependencies": { - "@blueprintjs/popover2": "^2.0.10", - "@radix-ui/react-slot": "^1.0.2", - "@tiptap/core": "^2.1.7", - "@tiptap/extension-code-block-lowlight": "^2.0.4", - "@tiptap/extension-color": "^2.1.11", - "@tiptap/extension-highlight": "^2.1.7", - "@tiptap/extension-horizontal-rule": "^2.1.7", - "@tiptap/extension-image": "^2.1.7", - "@tiptap/extension-link": "^2.1.7", - "@tiptap/extension-placeholder": "2.0.3", - "@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.1.7", - "@tiptap/extension-task-list": "^2.1.7", - "@tiptap/extension-text-style": "^2.1.11", - "@tiptap/extension-underline": "^2.1.7", - "@tiptap/pm": "^2.1.7", - "@tiptap/react": "^2.1.7", - "@tiptap/starter-kit": "^2.1.10", - "@tiptap/suggestion": "^2.1.7", - "@types/node": "18.15.3", - "@types/react": "18.0.28", - "@types/react-dom": "18.0.11", "class-variance-authority": "^0.7.0", "clsx": "^1.2.1", - "eslint": "8.36.0", - "eslint-config-next": "13.2.4", - "eventsource-parser": "^0.1.0", "lowlight": "^2.9.0", "lucide-react": "^0.244.0", "next": "12.3.2", - "next-themes": "^0.2.1", "react": "18.2.0", "react-dom": "18.2.0", - "react-markdown": "^8.0.7", - "tailwind-merge": "^1.14.0", - "tippy.js": "^6.3.7", - "tiptap-markdown": "^0.8.2", - "use-debounce": "^9.0.4" + "@plane/editor-core": "*" }, "devDependencies": { + "@types/node": "18.15.3", + "@types/react-dom": "18.0.11", "@types/react": "^18.2.5", "eslint": "^7.32.0", "postcss": "^8.4.29", diff --git a/packages/editor/rich-text-editor/src/extensions.tsx b/packages/editor/rich-text-editor/src/extensions.tsx deleted file mode 100644 index 85087e5e1f9..00000000000 --- a/packages/editor/rich-text-editor/src/extensions.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import HorizontalRule from "@tiptap/extension-horizontal-rule"; -import { TableRow } from "@tiptap/extension-table-row"; -import Placeholder from "@tiptap/extension-placeholder"; -import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight"; -import { InputRule } from "@tiptap/core"; - -import ts from "highlight.js/lib/languages/typescript"; -import { lowlight } from "lowlight/lib/core"; -import "highlight.js/styles/github-dark.css"; -import { Table } from "./table/table"; -import { TableHeader } from "./table/table-header"; -import { CustomTableCell } from "./table/table-cell"; -import SlashCommand from "./slash-command"; -import { UploadImage } from "./types/upload-image"; - -lowlight.registerLanguage("ts", ts); - -export const TiptapExtensions = ( - uploadFile: UploadImage, - setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void -) => [ - CodeBlockLowlight.configure({ - lowlight, - }), - HorizontalRule.extend({ - addInputRules() { - return [ - new InputRule({ - find: /^(?:---|—-|___\s|\*\*\*\s)$/, - handler: ({ state, range, commands }) => { - commands.splitBlock(); - - const attributes = {}; - const { tr } = state; - const start = range.from; - const end = range.to; - // @ts-ignore - tr.replaceWith(start - 1, end, this.type.create(attributes)); - }, - }), - ]; - }, - }).configure({ - HTMLAttributes: { - class: "mb-6 border-t border-custom-border-300", - }, - }), - Placeholder.configure({ - placeholder: ({ node }) => { - if (node.type.name === "heading") { - return `Heading ${node.attrs.level}`; - } - if (node.type.name === "image" || node.type.name === "table") { - return ""; - } - - return "Press '/' for commands..."; - }, - includeChildren: true, - }), - SlashCommand(uploadFile, setIsSubmitting), - Table, - TableHeader, - CustomTableCell, - TableRow, - ]; diff --git a/packages/editor/rich-text-editor/src/index.ts b/packages/editor/rich-text-editor/src/index.ts new file mode 100644 index 00000000000..eeca9f83711 --- /dev/null +++ b/packages/editor/rich-text-editor/src/index.ts @@ -0,0 +1 @@ +export { RichTextEditor, RichTextEditorWithRef } from "@/ui"; diff --git a/packages/editor/rich-text-editor/src/index.tsx b/packages/editor/rich-text-editor/src/index.tsx deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/packages/editor/rich-text-editor/src/slash-command.tsx b/packages/editor/rich-text-editor/src/slash-command.tsx deleted file mode 100644 index 844d4c55a58..00000000000 --- a/packages/editor/rich-text-editor/src/slash-command.tsx +++ /dev/null @@ -1,363 +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/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 = - ( - 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, 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 = ( - uploadFile: UploadImage, - setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void -) => - Command.configure({ - suggestion: { - items: getSuggestionItems(uploadFile, setIsSubmitting), - render: renderItems, - }, - }); - -export default SlashCommand; diff --git a/packages/editor/rich-text-editor/src/table/table-cell.ts b/packages/editor/rich-text-editor/src/table/table-cell.ts deleted file mode 100644 index 643cb8c64a7..00000000000 --- a/packages/editor/rich-text-editor/src/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/rich-text-editor/src/table/table-header.ts b/packages/editor/rich-text-editor/src/table/table-header.ts deleted file mode 100644 index f23aa93ef55..00000000000 --- a/packages/editor/rich-text-editor/src/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/rich-text-editor/src/table/table.ts b/packages/editor/rich-text-editor/src/table/table.ts deleted file mode 100644 index 9b727bb51bd..00000000000 --- a/packages/editor/rich-text-editor/src/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/rich-text-editor/src/types/upload-image.ts b/packages/editor/rich-text-editor/src/types/upload-image.ts deleted file mode 100644 index 3cf1408d22b..00000000000 --- a/packages/editor/rich-text-editor/src/types/upload-image.ts +++ /dev/null @@ -1 +0,0 @@ -export type UploadImage = (file: File) => Promise; diff --git a/packages/editor/rich-text-editor/src/ui/extensions/index.tsx b/packages/editor/rich-text-editor/src/ui/extensions/index.tsx new file mode 100644 index 00000000000..7c394b53eae --- /dev/null +++ b/packages/editor/rich-text-editor/src/ui/extensions/index.tsx @@ -0,0 +1,20 @@ +import HorizontalRule from "@tiptap/extension-horizontal-rule"; +import Placeholder from "@tiptap/extension-placeholder"; +import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight"; +import { lowlight } from "lowlight/lib/core"; +import { InputRule } from "@tiptap/core"; + +import ts from "highlight.js/lib/languages/typescript"; + +import "highlight.js/styles/github-dark.css"; +import SlashCommand from "./slash-command"; +import { UploadImage } from ".."; + +lowlight.registerLanguage("ts", ts); + +export const RichTextEditorExtensions = ( + uploadFile: UploadImage, + setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void +) => [ + SlashCommand(uploadFile, setIsSubmitting), + ]; diff --git a/packages/editor/core/src/ui/extensions/slash-command.tsx b/packages/editor/rich-text-editor/src/ui/extensions/slash-command.tsx similarity index 98% rename from packages/editor/core/src/ui/extensions/slash-command.tsx rename to packages/editor/rich-text-editor/src/ui/extensions/slash-command.tsx index 844d4c55a58..8fdb5ddcd40 100644 --- a/packages/editor/core/src/ui/extensions/slash-command.tsx +++ b/packages/editor/rich-text-editor/src/ui/extensions/slash-command.tsx @@ -17,9 +17,8 @@ import { ImageIcon, Table, } from "lucide-react"; -import { startImageUpload } from "@/ui/plugins/upload-image"; -import { cn } from "@/lib/utils"; -import { UploadImage } from "@/types/upload-image"; +import { UploadImage } from ".."; +import { cn, startImageUpload } from "@plane/editor-core"; interface CommandItemProps { title: string; diff --git a/packages/editor/rich-text-editor/src/ui/index.tsx b/packages/editor/rich-text-editor/src/ui/index.tsx new file mode 100644 index 00000000000..8784ae17df8 --- /dev/null +++ b/packages/editor/rich-text-editor/src/ui/index.tsx @@ -0,0 +1,83 @@ +"use client" +import * as React from 'react'; +import { EditorContainer, EditorContentWrapper, getEditorClassNames, useEditor } from '@plane/editor-core'; +import { EditorBubbleMenu } from './menus/bubble-menu'; +import { RichTextEditorExtensions } from './extensions'; + +export type UploadImage = (file: File) => Promise; +export type DeleteImage = (assetUrlWithWorkspaceId: string) => Promise; + +interface ITiptapEditor { + value: string; + uploadFile: UploadImage; + deleteFile: DeleteImage; + noBorder?: boolean; + borderOnFocus?: boolean; + customClassName?: string; + editorContentCustomClassNames?: string; + onChange?: (json: any, html: string) => void; + setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void; + setShouldShowAlert?: (showAlert: boolean) => void; + editable?: boolean; + forwardedRef?: any; + debouncedUpdatesEnabled?: boolean; +} + +interface TiptapProps extends ITiptapEditor { + forwardedRef?: React.Ref; +} + +interface EditorHandle { + clearEditor: () => void; + setEditorValue: (content: string) => void; +} + +const RichTextEditor = ({ + onChange, + debouncedUpdatesEnabled, + editable, + setIsSubmitting, + setShouldShowAlert, + editorContentCustomClassNames, + value, + uploadFile, + deleteFile, + noBorder, + borderOnFocus, + customClassName, + forwardedRef, +}: TiptapProps) => { + const editor = useEditor({ + onChange, + debouncedUpdatesEnabled, + editable, + setIsSubmitting, + setShouldShowAlert, + value, + uploadFile, + deleteFile, + forwardedRef, + extensions: RichTextEditorExtensions(uploadFile, setIsSubmitting) + }); + + const editorClassNames = getEditorClassNames({ noBorder, borderOnFocus, customClassName }); + + if (!editor) return null; + + return ( + + {editor && } +
+ +
+
+ ); +}; + +const RichTextEditorWithRef = React.forwardRef((props, ref) => ( + +)); + +RichTextEditorWithRef.displayName = "RichTextEditorWithRef"; + +export { RichTextEditor, RichTextEditorWithRef}; diff --git a/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/index.tsx b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/index.tsx new file mode 100644 index 00000000000..b9ce6159d72 --- /dev/null +++ b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/index.tsx @@ -0,0 +1,121 @@ +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 "@plane/editor-core"; + +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/rich-text-editor/src/ui/menus/bubble-menu/link-selector.tsx b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/link-selector.tsx new file mode 100644 index 00000000000..cf347cf3b06 --- /dev/null +++ b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/link-selector.tsx @@ -0,0 +1,93 @@ +import { Editor } from "@tiptap/core"; +import { Check, Trash } from "lucide-react"; +import { Dispatch, FC, SetStateAction, useCallback, useEffect, useRef } from "react"; +import isValidHttpUrl from "@/ui/menus/bubble-menu/utils"; +import { cn } from "@plane/editor-core"; + +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/rich-text-editor/src/ui/menus/bubble-menu/node-selector.tsx b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/node-selector.tsx new file mode 100644 index 00000000000..e1f8ce2111f --- /dev/null +++ b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/node-selector.tsx @@ -0,0 +1,130 @@ +import { cn } from "@plane/editor-core"; +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/rich-text-editor/src/ui/menus/bubble-menu/utils/index.tsx b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/utils/index.tsx new file mode 100644 index 00000000000..b5add3f544e --- /dev/null +++ b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/utils/index.tsx @@ -0,0 +1,11 @@ +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/space/components/issues/peek-overview/comment/add-comment.tsx b/space/components/issues/peek-overview/comment/add-comment.tsx index 7869667d2cf..c06634fc6ad 100644 --- a/space/components/issues/peek-overview/comment/add-comment.tsx +++ b/space/components/issues/peek-overview/comment/add-comment.tsx @@ -11,7 +11,7 @@ import { SecondaryButton } from "components/ui"; // types import { Comment } from "types/issue"; // components -import { TiptapEditorWithRef } from "@plane/editor"; +import { RichTextEditorWithRef } from "@plane/rich-text-editor"; // service import fileService from "@/services/file.service"; @@ -71,10 +71,9 @@ export const AddComment: React.FC = observer((props) => { name="comment_html" control={control} render={({ field: { value, onChange } }) => ( - = observer((props) => { control={control} name="comment_html" render={({ field: { onChange, value } }) => ( - = observer((props) => {
- = ({ issueDetails }) => {

{issueDetails.name}

{issueDetails.description_html !== "" && issueDetails.description_html !== "

" && ( - { - return this.mediaUpload(`/api/workspaces/${workspaceSlug}/file-assets/`, file) + return this.post(`/api/workspaces/${workspaceSlug}/file-assets/`, file, { + headers: { + ...this.getHeaders(), + "Content-Type": "multipart/form-data", + }, + }) .then((response) => response?.data) .catch((error) => { throw error?.response?.data; }); } + getUploadFileFunction(workspaceSlug: string): (file: File) => Promise { + return async (file: File) => { + const formData = new FormData(); + formData.append("asset", file); + formData.append("attributes", JSON.stringify({})); + + const data = await this.uploadFile(workspaceSlug, formData); + return data.asset; + }; + } + async deleteImage(assetUrlWithWorkspaceId: string): Promise { return this.delete(`/api/workspaces/file-assets/${assetUrlWithWorkspaceId}/`) .then((response) => response?.status) diff --git a/turbo.json b/turbo.json index e7a4a08d590..40f67bc05f2 100644 --- a/turbo.json +++ b/turbo.json @@ -44,7 +44,7 @@ "cache": false, "persistent": true, "dependsOn": [ - "@plane/editor#build" + "@plane/editor-core#build" ] }, "test": { diff --git a/web/components/core/modals/gpt-assistant-modal.tsx b/web/components/core/modals/gpt-assistant-modal.tsx index 8c5895f3995..236037531e7 100644 --- a/web/components/core/modals/gpt-assistant-modal.tsx +++ b/web/components/core/modals/gpt-assistant-modal.tsx @@ -11,7 +11,7 @@ import useUserAuth from "hooks/use-user-auth"; // ui import { Input, PrimaryButton, SecondaryButton } from "components/ui"; // components -import { TiptapEditor, TiptapEditorWithRef } from "@plane/editor"; +import { RichTextEditor, RichTextEditorWithRef } from "@plane/rich-text-editor"; // types import { IIssue, IPageBlock } from "types"; // services @@ -143,10 +143,9 @@ export const GptAssistantModal: React.FC = ({ {((content && content !== "") || (htmlContent && htmlContent !== "

")) && (
Content: - ${content}

`} customClassName="-m-3" noBorder @@ -159,10 +158,9 @@ export const GptAssistantModal: React.FC = ({ {response !== "" && (
Response: - ${response}

`} customClassName="-mx-3 -my-3" noBorder diff --git a/web/components/issues/comment/add-comment.tsx b/web/components/issues/comment/add-comment.tsx index 76a45faa428..4b0e92ba7e1 100644 --- a/web/components/issues/comment/add-comment.tsx +++ b/web/components/issues/comment/add-comment.tsx @@ -3,9 +3,9 @@ import { useRouter } from "next/router"; // react-hook-form import { useForm, Controller } from "react-hook-form"; // components -import { TiptapEditorWithRef } from "@plane/editor"; +import { LiteTextEditorWithRef } from "@plane/lite-text-editor"; // ui -import { Icon, SecondaryButton, Tooltip } from "components/ui"; +import { SecondaryButton } from "components/ui"; // types import type { IIssueComment } from "types"; // services @@ -74,23 +74,20 @@ export const AddComment: React.FC = ({ ( + render={({ field: { onChange: onAccessChange, value: accessValue } }) => ( ( -

" : 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} + commentAccessSpecifier={{ accessValue, onAccessChange, showAccessSpecifier, commentAccess }} /> )} /> diff --git a/web/components/issues/comment/comment-card.tsx b/web/components/issues/comment/comment-card.tsx index 19cc0fe7efd..147c49bd16e 100644 --- a/web/components/issues/comment/comment-card.tsx +++ b/web/components/issues/comment/comment-card.tsx @@ -9,7 +9,7 @@ import useUser from "hooks/use-user"; // ui import { CustomMenu, Icon } from "components/ui"; import { CommentReaction } from "components/issues"; -import { TiptapEditorWithRef } from "@plane/editor"; +import { LiteTextEditorWithRef } from "@plane/lite-text-editor"; // helpers import { timeAgo } from "helpers/date-time.helper"; // types @@ -112,10 +112,9 @@ export const CommentCard: React.FC = ({ onSubmit={handleSubmit(onEnter)} >
- = ({ />
)} - = ({ if (!value) return <>; return ( - = (props) => { return ( = (props) => { return ( = ({ if (!data) return (

"} debouncedUpdatesEnabled={false} @@ -304,9 +303,8 @@ export const CreateUpdateBlockInline: React.FC = ({ return ( 0 diff --git a/web/components/pages/single-page-block.tsx b/web/components/pages/single-page-block.tsx index 592da42c71f..356186882ef 100644 --- a/web/components/pages/single-page-block.tsx +++ b/web/components/pages/single-page-block.tsx @@ -19,7 +19,7 @@ import useOutsideClickDetector from "hooks/use-outside-click-detector"; // components import { GptAssistantModal } from "components/core"; import { CreateUpdateBlockInline } from "components/pages"; -import { TiptapEditor } from "@plane/editor"; +import { RichTextEditor } from "@plane/rich-text-editor"; // ui import { CustomMenu, TextArea } from "components/ui"; // icons @@ -452,10 +452,9 @@ export const SinglePageBlock: React.FC = ({ {showBlockDetails ? block.description_html.length > 7 && ( - = ({ disabled = false, onSubmit }) => { control={control} render={({ field: { value, onChange } }) => (

" : value} customClassName="p-3 min-h-[100px] shadow-sm" diff --git a/web/components/web-view/issue-web-view-form.tsx b/web/components/web-view/issue-web-view-form.tsx index 13824210414..8a791e9ac25 100644 --- a/web/components/web-view/issue-web-view-form.tsx +++ b/web/components/web-view/issue-web-view-form.tsx @@ -16,7 +16,7 @@ import useReloadConfirmations from "hooks/use-reload-confirmation"; import { TextArea } from "components/ui"; // components -import { TiptapEditor } from "@plane/editor"; +import { RichTextEditor } from "@plane/rich-text-editor"; import { Label } from "components/web-view"; // types @@ -123,8 +123,8 @@ export const IssueWebViewForm: React.FC = (props) => { if (!value) return <>; return ( - = (props) => { ? "

" : value } - workspaceSlug={workspaceSlug!.toString()} debouncedUpdatesEnabled={true} setShouldShowAlert={setShowAlert} setIsSubmitting={setIsSubmitting} diff --git a/web/package.json b/web/package.json index 8e4629242e0..23aa28bfa69 100644 --- a/web/package.json +++ b/web/package.json @@ -27,7 +27,8 @@ "@nivo/pie": "0.80.0", "@nivo/scatterplot": "0.80.0", "@sentry/nextjs": "^7.36.0", - "@plane/editor": "*", + "@plane/lite-text-editor": "*", + "@plane/rich-text-editor": "*", "@types/lodash.debounce": "^4.0.7", "@types/react-datepicker": "^4.8.0", "axios": "^1.1.3", diff --git a/web/pages/[workspaceSlug]/editor.tsx b/web/pages/[workspaceSlug]/editor.tsx index d825826c2cc..7b16bdd54c2 100644 --- a/web/pages/[workspaceSlug]/editor.tsx +++ b/web/pages/[workspaceSlug]/editor.tsx @@ -1,4 +1,4 @@ -import { TiptapEditor } from "@plane/editor"; +import { RichTextEditor } from "@plane/rich-text-editor"; import type { NextPage } from "next"; import { useCallback, useEffect, useState } from "react"; import { Controller, useForm } from "react-hook-form"; @@ -135,8 +135,8 @@ const Editor: NextPage = () => { name="description_html" control={control} render={({ field: { value, onChange } }) => ( - { } editable={editable === "true"} noBorder={true} - workspaceSlug={cookies.MOBILE_slug ?? ""} debouncedUpdatesEnabled={true} setShouldShowAlert={setShowAlert} setIsSubmitting={setIsSubmitting} diff --git a/web/pages/[workspaceSlug]/me/profile/activity.tsx b/web/pages/[workspaceSlug]/me/profile/activity.tsx index b6c478a8607..68e46723df6 100644 --- a/web/pages/[workspaceSlug]/me/profile/activity.tsx +++ b/web/pages/[workspaceSlug]/me/profile/activity.tsx @@ -9,7 +9,7 @@ import userService from "services/user.service"; import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; // components import { ActivityIcon, ActivityMessage } from "components/core"; -import { TiptapEditor } from "@plane/editor"; +import { RichTextEditor } from "@plane/rich-text-editor"; // icons import { ArrowTopRightOnSquareIcon, ChatBubbleLeftEllipsisIcon } from "@heroicons/react/24/outline"; // ui @@ -98,10 +98,9 @@ const ProfileActivity = () => {

- { name="data_html" control={control} render={({ field: { value, onChange } }) => ( - { } editable={isEditable} noBorder={true} - workspaceSlug={workspaceSlug?.toString() ?? ""} debouncedUpdatesEnabled={true} customClassName="min-h-[150px] shadow-sm" editorContentCustomClassNames="pb-9" diff --git a/yarn.lock b/yarn.lock index b2d3e099b57..bdee8735008 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2808,7 +2808,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@18.0.15", "@types/react@18.0.28", "@types/react@18.2.0", "@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", "@types/react@^18.2.5": version "18.2.0" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.0.tgz#15cda145354accfc09a18d2f2305f9fc099ada21" integrity sha512-0FLj93y5USLHdnhIhABk83rm8XEGA7kH3cr+YUlvxoUGp1xNt/DINUMvqPxLyOQMzLmZe8i4RTHbvb8MC7NmrA== From b5228bb0efb072e5292f62b764177a110283accb Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Mon, 2 Oct 2023 14:15:16 +0530 Subject: [PATCH 23/57] fixed global css issue with highlight js --- packages/editor/core/src/index.ts | 1 - .../editor/core/src/ui/hooks/useEditor.tsx | 4 +- packages/editor/core/tsup.config.ts | 2 +- .../src/ui/menus/fixed-menu/index.tsx | 4 +- .../src/ui/{menus/fixed-menu => }/tooltip.tsx | 0 .../editor/lite-text-editor/tsup.config.ts | 2 +- packages/editor/rich-text-editor/package.json | 13 ++++-- packages/editor/rich-text-editor/src/index.ts | 2 + .../src/styles/github-dark.css | 2 + .../src/ui/extensions/index.tsx | 46 +++++++++++++++++-- .../editor/rich-text-editor/tsup.config.ts | 2 +- .../tailwind-config-custom/tailwind.config.js | 2 + 12 files changed, 65 insertions(+), 15 deletions(-) rename packages/editor/lite-text-editor/src/ui/{menus/fixed-menu => }/tooltip.tsx (100%) create mode 100644 packages/editor/rich-text-editor/src/styles/github-dark.css diff --git a/packages/editor/core/src/index.ts b/packages/editor/core/src/index.ts index 1fc9b618cb2..8b72e0bf3fd 100644 --- a/packages/editor/core/src/index.ts +++ b/packages/editor/core/src/index.ts @@ -2,7 +2,6 @@ import "@/styles/tailwind.css"; import "@/styles/editor.css"; export { startImageUpload } from "@/ui/plugins/upload-image"; -// export { TiptapEditor, TiptapEditorWithRef } from "@/ui"; export { useEditor } from "@/ui/hooks/useEditor"; export { cn } from "@/lib/utils"; export { getEditorClassNames } from "@/lib/utils"; diff --git a/packages/editor/core/src/ui/hooks/useEditor.tsx b/packages/editor/core/src/ui/hooks/useEditor.tsx index cec52d25f38..66d904cf174 100644 --- a/packages/editor/core/src/ui/hooks/useEditor.tsx +++ b/packages/editor/core/src/ui/hooks/useEditor.tsx @@ -1,4 +1,4 @@ -import { useEditor as useCustomEditor, Editor, Extension } from "@tiptap/react"; +import { useEditor as useCustomEditor, Editor, Extension, Node, Mark } from "@tiptap/react"; import { useImperativeHandle, useRef, MutableRefObject, forwardRef } from "react"; import { useDebouncedCallback } from "use-debounce"; import { UploadImage } from '@/types/upload-image'; @@ -18,7 +18,7 @@ interface CustomEditorProps { deleteFile: DeleteImage; debouncedUpdatesEnabled?: boolean; onChange?: (json: any, html: string) => void; - extensions?: Extension[]; + extensions?: any; editorProps?: EditorProps; forwardedRef?: any; } diff --git a/packages/editor/core/tsup.config.ts b/packages/editor/core/tsup.config.ts index 5e89e04afad..907f339a1d0 100644 --- a/packages/editor/core/tsup.config.ts +++ b/packages/editor/core/tsup.config.ts @@ -3,7 +3,7 @@ import { defineConfig, Options } from "tsup"; export default defineConfig((options: Options) => ({ entry: ["src/index.ts"], format: ["cjs", "esm"], - dts: true, + dts: false, clean: false, external: ["react"], injectStyle: true, diff --git a/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx b/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx index 0cece1d580f..cc32052381a 100644 --- a/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx +++ b/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx @@ -2,8 +2,8 @@ import { Editor } from "@tiptap/react"; import { BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, CodeIcon } from "lucide-react"; import { cn } from "@plane/editor-core"; -import { Tooltip } from "./tooltip"; import { Icon } from "./icon"; +import { Tooltip } from "@/ui/tooltip"; export interface BubbleMenuItem { name: string; @@ -81,7 +81,7 @@ export const FixedMenu = (props: EditorBubbleMenuProps) => { > ({ entry: ["src/index.ts"], format: ["cjs", "esm"], - dts: true, + dts: false, clean: false, external: ["react"], injectStyle: true, diff --git a/packages/editor/rich-text-editor/package.json b/packages/editor/rich-text-editor/package.json index 27ca22ac472..2c7d4ff4f86 100644 --- a/packages/editor/rich-text-editor/package.json +++ b/packages/editor/rich-text-editor/package.json @@ -24,19 +24,24 @@ "react": "^18.2.0" }, "dependencies": { + "@plane/editor-core": "*", + "@tiptap/core": "^2.1.11", + "@tiptap/extension-code-block-lowlight": "^2.1.11", + "@tiptap/extension-horizontal-rule": "^2.1.11", + "@tiptap/extension-placeholder": "^2.1.11", "class-variance-authority": "^0.7.0", "clsx": "^1.2.1", - "lowlight": "^2.9.0", + "highlight.js": "^11.8.0", + "lowlight": "^3.0.0", "lucide-react": "^0.244.0", "next": "12.3.2", "react": "18.2.0", - "react-dom": "18.2.0", - "@plane/editor-core": "*" + "react-dom": "18.2.0" }, "devDependencies": { "@types/node": "18.15.3", - "@types/react-dom": "18.0.11", "@types/react": "^18.2.5", + "@types/react-dom": "18.0.11", "eslint": "^7.32.0", "postcss": "^8.4.29", "react": "^18.2.0", diff --git a/packages/editor/rich-text-editor/src/index.ts b/packages/editor/rich-text-editor/src/index.ts index eeca9f83711..b5196a8b5e5 100644 --- a/packages/editor/rich-text-editor/src/index.ts +++ b/packages/editor/rich-text-editor/src/index.ts @@ -1 +1,3 @@ +import "./styles/github-dark.css"; + export { RichTextEditor, RichTextEditorWithRef } from "@/ui"; diff --git a/packages/editor/rich-text-editor/src/styles/github-dark.css b/packages/editor/rich-text-editor/src/styles/github-dark.css new file mode 100644 index 00000000000..20a7f4e66bf --- /dev/null +++ b/packages/editor/rich-text-editor/src/styles/github-dark.css @@ -0,0 +1,2 @@ +pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px} +.hljs{color:#c9d1d9;background:#0d1117}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#ff7b72}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#d2a8ff}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id,.hljs-variable{color:#79c0ff}.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#a5d6ff}.hljs-built_in,.hljs-symbol{color:#ffa657}.hljs-code,.hljs-comment,.hljs-formula{color:#8b949e}.hljs-name,.hljs-quote,.hljs-selector-pseudo,.hljs-selector-tag{color:#7ee787}.hljs-subst{color:#c9d1d9}.hljs-section{color:#1f6feb;font-weight:700}.hljs-bullet{color:#f2cc60}.hljs-emphasis{color:#c9d1d9;font-style:italic}.hljs-strong{color:#c9d1d9;font-weight:700}.hljs-addition{color:#aff5b4;background-color:#033a16}.hljs-deletion{color:#ffdcd7;background-color:#67060c} diff --git a/packages/editor/rich-text-editor/src/ui/extensions/index.tsx b/packages/editor/rich-text-editor/src/ui/extensions/index.tsx index 7c394b53eae..69f89e2f164 100644 --- a/packages/editor/rich-text-editor/src/ui/extensions/index.tsx +++ b/packages/editor/rich-text-editor/src/ui/extensions/index.tsx @@ -1,20 +1,60 @@ import HorizontalRule from "@tiptap/extension-horizontal-rule"; import Placeholder from "@tiptap/extension-placeholder"; import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight"; -import { lowlight } from "lowlight/lib/core"; +import { common, createLowlight } from 'lowlight' import { InputRule } from "@tiptap/core"; import ts from "highlight.js/lib/languages/typescript"; -import "highlight.js/styles/github-dark.css"; +// import "highlight.js/styles/github-dark.css"; import SlashCommand from "./slash-command"; import { UploadImage } from ".."; -lowlight.registerLanguage("ts", ts); +const lowlight = createLowlight(common) +lowlight.register("ts", ts); export const RichTextEditorExtensions = ( uploadFile: UploadImage, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void ) => [ + HorizontalRule.extend({ + addInputRules() { + return [ + new InputRule({ + find: /^(?:---|—-|___\s|\*\*\*\s)$/, + handler: ({ state, range, commands }) => { + commands.splitBlock(); + + const attributes = {}; + const { tr } = state; + const start = range.from; + const end = range.to; + // @ts-ignore + tr.replaceWith(start - 1, end, this.type.create(attributes)); + }, + }), + ]; + }, + }).configure({ + HTMLAttributes: { + class: "mb-6 border-t border-custom-border-300", + }, + }), SlashCommand(uploadFile, setIsSubmitting), + CodeBlockLowlight.configure({ + lowlight, + }), + Placeholder.configure({ + placeholder: ({ node }) => { + if (node.type.name === "heading") { + return `Heading ${node.attrs.level}`; + } + if (node.type.name === "image" || node.type.name === "table") { + return ""; + } + + return "Press '/' for commands..."; + }, + includeChildren: true, + }), ]; diff --git a/packages/editor/rich-text-editor/tsup.config.ts b/packages/editor/rich-text-editor/tsup.config.ts index 5e89e04afad..907f339a1d0 100644 --- a/packages/editor/rich-text-editor/tsup.config.ts +++ b/packages/editor/rich-text-editor/tsup.config.ts @@ -3,7 +3,7 @@ import { defineConfig, Options } from "tsup"; export default defineConfig((options: Options) => ({ entry: ["src/index.ts"], format: ["cjs", "esm"], - dts: true, + dts: false, clean: false, external: ["react"], injectStyle: true, diff --git a/packages/tailwind-config-custom/tailwind.config.js b/packages/tailwind-config-custom/tailwind.config.js index 061168c4f78..b58baa284ba 100644 --- a/packages/tailwind-config-custom/tailwind.config.js +++ b/packages/tailwind-config-custom/tailwind.config.js @@ -1,5 +1,6 @@ const convertToRGB = (variableName) => `rgba(var(${variableName}))`; +/** @type {import('tailwindcss').Config} */ module.exports = { darkMode: "class", content: [ @@ -8,6 +9,7 @@ module.exports = { "./layouts/**/*.tsx", "./pages/**/*.tsx", "./ui/**/*.tsx", + "../../packages/**/*.{js,ts,jsx,tsx}", ], theme: { extend: { From 3d87a56e3b0195a1dbb89217f181cad68f73f59b Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Mon, 2 Oct 2023 14:52:16 +0530 Subject: [PATCH 24/57] refactoring tiptap to core/lite/rich text editor --- packages/editor/core/src/styles/editor.css | 2 +- .../editor/core/src/ui/editor-container.tsx | 4 +- .../editor/core/src/ui/extensions/index.tsx | 2 +- .../editor/core/src/ui/hooks/useEditor.tsx | 12 ++-- packages/editor/core/src/ui/index.tsx | 16 ++--- packages/editor/core/src/ui/props.tsx | 2 +- .../editor/lite-text-editor/src/ui/index.tsx | 8 +-- packages/editor/rich-text-editor/src/index.ts | 2 +- .../src/ui/extensions/slash-command.tsx | 2 +- .../editor/rich-text-editor/src/ui/index.tsx | 8 +-- space/styles/editor.css | 2 +- web/components/issues/draft-issue-form.tsx | 4 +- web/components/issues/form.tsx | 21 +++--- .../pages/create-update-block-inline.tsx | 6 +- web/components/web-view/add-comment.tsx | 72 ++++++++----------- web/styles/editor.css | 2 +- yarn.lock | 48 +++++++++++++ 17 files changed, 122 insertions(+), 91 deletions(-) diff --git a/packages/editor/core/src/styles/editor.css b/packages/editor/core/src/styles/editor.css index 9da250dd108..85d881eeb46 100644 --- a/packages/editor/core/src/styles/editor.css +++ b/packages/editor/core/src/styles/editor.css @@ -155,7 +155,7 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p { } } -#tiptap-container { +#editor-container { table { border-collapse: collapse; table-layout: fixed; diff --git a/packages/editor/core/src/ui/editor-container.tsx b/packages/editor/core/src/ui/editor-container.tsx index fca24f96261..8de6298b57e 100644 --- a/packages/editor/core/src/ui/editor-container.tsx +++ b/packages/editor/core/src/ui/editor-container.tsx @@ -9,11 +9,11 @@ interface EditorContainerProps { export const EditorContainer = ({ editor, editorClassNames, children }: EditorContainerProps) => (
{ editor?.chain().focus().run(); }} - className={`tiptap-editor-container cursor-text ${editorClassNames}`} + className={`cursor-text ${editorClassNames}`} > {children}
diff --git a/packages/editor/core/src/ui/extensions/index.tsx b/packages/editor/core/src/ui/extensions/index.tsx index 65fb7582d17..b2d0a5c576d 100644 --- a/packages/editor/core/src/ui/extensions/index.tsx +++ b/packages/editor/core/src/ui/extensions/index.tsx @@ -19,7 +19,7 @@ import { DeleteImage } from "@/types/delete-image"; import isValidHttpUrl from "@/ui/menus/bubble-menu/utils" -export const TiptapExtensions = ( +export const CoreEditorExtensions = ( deleteFile: DeleteImage, ) => [ StarterKit.configure({ diff --git a/packages/editor/core/src/ui/hooks/useEditor.tsx b/packages/editor/core/src/ui/hooks/useEditor.tsx index 66d904cf174..7f762911913 100644 --- a/packages/editor/core/src/ui/hooks/useEditor.tsx +++ b/packages/editor/core/src/ui/hooks/useEditor.tsx @@ -1,10 +1,10 @@ -import { useEditor as useCustomEditor, Editor, Extension, Node, Mark } from "@tiptap/react"; -import { useImperativeHandle, useRef, MutableRefObject, forwardRef } from "react"; +import { useEditor as useCustomEditor, Editor } from "@tiptap/react"; +import { useImperativeHandle, useRef, MutableRefObject } from "react"; import { useDebouncedCallback } from "use-debounce"; import { UploadImage } from '@/types/upload-image'; import { DeleteImage } from '@/types/delete-image'; -import { TiptapEditorProps } from "../props"; -import { TiptapExtensions } from "../extensions"; +import { CoreEditorProps } from "../props"; +import { CoreEditorExtensions } from "../extensions"; import { EditorProps } from '@tiptap/pm/view'; const DEBOUNCE_DELAY = 1500; @@ -27,10 +27,10 @@ export const useEditor = ({ uploadFile, editable, deleteFile, editorProps = {}, const editor = useCustomEditor({ editable: editable ?? true, editorProps: { - ...TiptapEditorProps(uploadFile, setIsSubmitting), + ...CoreEditorProps(uploadFile, setIsSubmitting), ...editorProps, }, - extensions: [...TiptapExtensions(deleteFile), ...extensions], + extensions: [...CoreEditorExtensions(deleteFile), ...extensions], content: (typeof value === "string" && value.trim() !== "") ? value : "

", onUpdate: async ({ editor }) => { // for instant feedback loop diff --git a/packages/editor/core/src/ui/index.tsx b/packages/editor/core/src/ui/index.tsx index ae2654e1c42..2871075a812 100644 --- a/packages/editor/core/src/ui/index.tsx +++ b/packages/editor/core/src/ui/index.tsx @@ -9,7 +9,7 @@ import { useEditor } from './hooks/useEditor'; import { EditorContainer } from '@/ui/editor-container'; import { EditorContentWrapper } from '@/ui/editor-content'; -interface ITiptapEditor { +interface ICoreEditor { value: string; uploadFile: UploadImage; deleteFile: DeleteImage; @@ -34,7 +34,7 @@ interface ITiptapEditor { editorProps?: EditorProps; } -interface TiptapProps extends ITiptapEditor { +interface EditorCoreProps extends ICoreEditor { forwardedRef?: React.Ref; } @@ -43,7 +43,7 @@ interface EditorHandle { setEditorValue: (content: string) => void; } -const TiptapEditor = ({ +const CoreEditor = ({ onChange, debouncedUpdatesEnabled, editable, @@ -57,7 +57,7 @@ const TiptapEditor = ({ borderOnFocus, customClassName, forwardedRef, -}: TiptapProps) => { +}: EditorCoreProps) => { const editor = useEditor({ onChange, debouncedUpdatesEnabled, @@ -83,10 +83,10 @@ const TiptapEditor = ({ ); }; -const TiptapEditorWithRef = React.forwardRef((props, ref) => ( - +const CoreEditorWithRef = React.forwardRef((props, ref) => ( + )); -TiptapEditorWithRef.displayName = "TiptapEditorWithRef"; +CoreEditorWithRef.displayName = "CoreEditorWithRef"; -export { TiptapEditor, TiptapEditorWithRef }; +export { CoreEditor, CoreEditorWithRef }; diff --git a/packages/editor/core/src/ui/props.tsx b/packages/editor/core/src/ui/props.tsx index d2a0d80639b..7a43005e798 100644 --- a/packages/editor/core/src/ui/props.tsx +++ b/packages/editor/core/src/ui/props.tsx @@ -3,7 +3,7 @@ import { findTableAncestor } from "@/lib/utils"; import { startImageUpload } from "@/ui/plugins/upload-image"; import { UploadImage } from "@/types/upload-image"; -export function TiptapEditorProps( +export function CoreEditorProps( uploadFile: UploadImage, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void ): EditorProps { diff --git a/packages/editor/lite-text-editor/src/ui/index.tsx b/packages/editor/lite-text-editor/src/ui/index.tsx index ce87a39b3cf..85321fccb12 100644 --- a/packages/editor/lite-text-editor/src/ui/index.tsx +++ b/packages/editor/lite-text-editor/src/ui/index.tsx @@ -6,7 +6,7 @@ import { FixedMenu } from './menus/fixed-menu'; export type UploadImage = (file: File) => Promise; export type DeleteImage = (assetUrlWithWorkspaceId: string) => Promise; -interface ITiptapEditor { +interface ILiteTextEditor { value: string; uploadFile: UploadImage; deleteFile: DeleteImage; @@ -32,7 +32,7 @@ interface ITiptapEditor { } } -interface TiptapProps extends ITiptapEditor { +interface LiteTextEditorProps extends ILiteTextEditor { forwardedRef?: React.Ref; } @@ -56,7 +56,7 @@ const LiteTextEditor = ({ customClassName, forwardedRef, commentAccessSpecifier, -}: TiptapProps) => { +}: LiteTextEditorProps) => { const editor = useEditor({ onChange, debouncedUpdatesEnabled, @@ -87,7 +87,7 @@ const LiteTextEditor = ({ ); }; -const LiteTextEditorWithRef = React.forwardRef((props, ref) => ( +const LiteTextEditorWithRef = React.forwardRef((props, ref) => ( )); diff --git a/packages/editor/rich-text-editor/src/index.ts b/packages/editor/rich-text-editor/src/index.ts index b5196a8b5e5..b7ef6bbe4ba 100644 --- a/packages/editor/rich-text-editor/src/index.ts +++ b/packages/editor/rich-text-editor/src/index.ts @@ -1,3 +1,3 @@ -import "./styles/github-dark.css"; +import "@/styles/github-dark.css"; export { RichTextEditor, RichTextEditorWithRef } from "@/ui"; diff --git a/packages/editor/rich-text-editor/src/ui/extensions/slash-command.tsx b/packages/editor/rich-text-editor/src/ui/extensions/slash-command.tsx index 8fdb5ddcd40..7d3b49ca654 100644 --- a/packages/editor/rich-text-editor/src/ui/extensions/slash-command.tsx +++ b/packages/editor/rich-text-editor/src/ui/extensions/slash-command.tsx @@ -315,7 +315,7 @@ const renderItems = () => { // @ts-ignore popup = tippy("body", { getReferenceClientRect: props.clientRect, - appendTo: () => document.querySelector("#tiptap-container"), + appendTo: () => document.querySelector("#editor-container"), content: component.element, showOnCreate: true, interactive: true, diff --git a/packages/editor/rich-text-editor/src/ui/index.tsx b/packages/editor/rich-text-editor/src/ui/index.tsx index 8784ae17df8..8794822a057 100644 --- a/packages/editor/rich-text-editor/src/ui/index.tsx +++ b/packages/editor/rich-text-editor/src/ui/index.tsx @@ -7,7 +7,7 @@ import { RichTextEditorExtensions } from './extensions'; export type UploadImage = (file: File) => Promise; export type DeleteImage = (assetUrlWithWorkspaceId: string) => Promise; -interface ITiptapEditor { +interface IRichTextEditor { value: string; uploadFile: UploadImage; deleteFile: DeleteImage; @@ -23,7 +23,7 @@ interface ITiptapEditor { debouncedUpdatesEnabled?: boolean; } -interface TiptapProps extends ITiptapEditor { +interface RichTextEditorProps extends IRichTextEditor { forwardedRef?: React.Ref; } @@ -46,7 +46,7 @@ const RichTextEditor = ({ borderOnFocus, customClassName, forwardedRef, -}: TiptapProps) => { +}: RichTextEditorProps) => { const editor = useEditor({ onChange, debouncedUpdatesEnabled, @@ -74,7 +74,7 @@ const RichTextEditor = ({ ); }; -const RichTextEditorWithRef = React.forwardRef((props, ref) => ( +const RichTextEditorWithRef = React.forwardRef((props, ref) => ( )); diff --git a/space/styles/editor.css b/space/styles/editor.css index 9da250dd108..85d881eeb46 100644 --- a/space/styles/editor.css +++ b/space/styles/editor.css @@ -155,7 +155,7 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p { } } -#tiptap-container { +#editor-container { table { border-collapse: collapse; table-layout: fixed; diff --git a/web/components/issues/draft-issue-form.tsx b/web/components/issues/draft-issue-form.tsx index af0509551c5..cf1dd0f412b 100644 --- a/web/components/issues/draft-issue-form.tsx +++ b/web/components/issues/draft-issue-form.tsx @@ -25,7 +25,7 @@ import { CreateLabelModal } from "components/labels"; // ui import { CustomMenu, Input, PrimaryButton, SecondaryButton, ToggleSwitch } from "components/ui"; // components -import { TiptapEditorWithRef } from "@plane/rich-text-editor"; +import { RichTextEditorWithRef } from "@plane/rich-text-editor"; // icons import { SparklesIcon, XMarkIcon } from "@heroicons/react/24/outline"; // types @@ -386,7 +386,7 @@ export const DraftIssueForm: FC = (props) => { if (!value && !watch("description_html")) return <>; return ( - = (props) => { {issueName && issueName !== "" && (
= (props) => { ? "Updating Issue..." : "Update Issue" : isSubmitting - ? "Adding Issue..." - : "Add Issue"} + ? "Adding Issue..." + : "Add Issue"}
diff --git a/web/components/pages/create-update-block-inline.tsx b/web/components/pages/create-update-block-inline.tsx index b28d88d009f..5f7fa0facbf 100644 --- a/web/components/pages/create-update-block-inline.tsx +++ b/web/components/pages/create-update-block-inline.tsx @@ -11,7 +11,7 @@ import aiService from "services/ai.service"; import useToast from "hooks/use-toast"; // components import { GptAssistantModal } from "components/core"; -import { TiptapEditorWithRef } from "@plane/rich-text-editor"; +import { RichTextEditorWithRef } from "@plane/rich-text-editor"; import { PrimaryButton, SecondaryButton, TextArea } from "components/ui"; // types import { ICurrentUserResponse, IPageBlock } from "types"; @@ -281,7 +281,7 @@ export const CreateUpdateBlockInline: React.FC = ({ render={({ field: { value, onChange } }) => { if (!data) return ( - = ({ ); return ( - Promise; }; -const commentAccess = [ +type commentAccessType = { + icon: string; + key: string; + label: "Private" | "Public"; +} + +const commentAccess: commentAccessType[] = [ { icon: "lock", key: "INTERNAL", @@ -53,7 +58,7 @@ export const AddComment: React.FC = ({ disabled = false, onSubmit }) => { const { projectDetails } = useProjectDetails(); - const showAccessSpecifier = projectDetails?.is_deployed; + const showAccessSpecifier = projectDetails?.is_deployed || false; const { control, @@ -73,51 +78,30 @@ export const AddComment: React.FC = ({ disabled = false, onSubmit }) => { return (
-
- ( -

" : value} - customClassName="p-3 min-h-[100px] shadow-sm" - debouncedUpdatesEnabled={false} - onChange={(comment_json: Object, comment_html: string) => onChange(comment_html)} - /> - )} - /> - {showAccessSpecifier && ( -
+
( -
- {commentAccess.map((access) => ( - - - - ))} -
+ control={control} + render={({ field: { onChange: onAccessChange, value: accessValue } }) => ( + ( +

" : commentValue} + customClassName="p-3 min-h-[100px] shadow-sm" + debouncedUpdatesEnabled={false} + onChange={(comment_json: Object, comment_html: string) => onCommentChange(comment_html)} + commentAccessSpecifier={{ accessValue, onAccessChange, showAccessSpecifier, commentAccess }} + /> + )} + /> )} />
- )} -
div > p { } } -#tiptap-container { +#editor-container { table { border-collapse: collapse; table-layout: fixed; diff --git a/yarn.lock b/yarn.lock index bdee8735008..bfba25960d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2355,6 +2355,11 @@ resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.1.10.tgz#6d8f3c777f1700dcc6c903b1185576754175e366" integrity sha512-yhUKsac6nlqbPQfwQnp+4Jb110EqmzocXKoZacLwzHpM7JVsr2+LXMDu9kahtrvHNJErJljhnQvDHRsrrYeJkQ== +"@tiptap/core@^2.1.11": + version "2.1.11" + resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.1.11.tgz#06bbd189c6b2dffe58b1c80f848737d76fb012bd" + integrity sha512-1W2DdjpPwfphHgQ3Qm4s5wzCnEjiXm1TeZ+6/zBl89yKURXgv8Mw1JGdj/NcImQjtDcsNn97MscACK3GKbEJBA== + "@tiptap/extension-blockquote@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.1.10.tgz#dc475bef70dd460fc730a14b3b4cc18f37cd1b2d" @@ -2382,6 +2387,11 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.1.10.tgz#22dabaa8c087bd03c160590f7b8bf9b1501752b5" integrity sha512-HBrsgDX1sMx6FSoKxAhz2On8lwL8S1lqNryMQBTE63PemjOxcyxPNdGWZz+JfQmxyvymQoGhibaW5ImNAK84Zg== +"@tiptap/extension-code-block-lowlight@^2.1.11": + version "2.1.11" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.1.11.tgz#6eec38c3b8662fae81ec2f117a2d18564f1fbb1a" + integrity sha512-k3olDvsRYO32JR9hyNa6VLqUdhwcpLwvR4Z6tJ66jHag5rsfP/7JZxJhrX9A1AF/jRCILdTiq9DTKybHieFjsw== + "@tiptap/extension-code-block@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.1.10.tgz#a125a12f716728b271a130178c6fc60237ed46f5" @@ -2444,6 +2454,11 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.1.10.tgz#cfdb67530be100054fc8511942d4ec3534acf828" integrity sha512-91lGpK2d6WMPhrMDPBURS8z8pEg1CUBYy7GmBenKvvgh+JzVhG+U6MtykfWNfm2R4iRXOl1xLbyUOCiOSUXodQ== +"@tiptap/extension-horizontal-rule@^2.1.11": + version "2.1.11" + resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.1.11.tgz#e423a2b41123ef7f8d778a1cd026e6606e7be28b" + integrity sha512-uvHPa2YCKnDhtSBSZB3lk5U4H3wRKP0DNvVx4Y2F7MdQianVzcyOd1pZYO9BQs+lUB1aZots6doE69Zqz3mU2Q== + "@tiptap/extension-image@^2.1.7": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.1.10.tgz#6c597ad02285f1f3508fd4aa21e30213657cbd7c" @@ -2481,6 +2496,11 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.0.3.tgz#69575353f09fc7524c9cdbfbf16c04f73c29d154" integrity sha512-Z42jo0termRAf0S0L8oxrts94IWX5waU4isS2CUw8xCUigYyCFslkhQXkWATO1qRbjNFLKN2C9qvCgGf4UeBrw== +"@tiptap/extension-placeholder@^2.1.11": + version "2.1.11" + resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.1.11.tgz#ba115f714dd48d5bbc65df277b74f357ff3b100e" + integrity sha512-laHYRFxJWj6m72Yf1v6Q5nF2nvwWpQlKUj6Yu/yluOOoVE92HpLqCAvA8RamqLtPiw5VxR3v3oCY0WNeQRvyIg== + "@tiptap/extension-strike@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.1.10.tgz#ec311395d16af15345b63d2dac2d459b9ad5fa9e" @@ -2630,6 +2650,13 @@ dependencies: "@types/unist" "^2" +"@types/hast@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-3.0.1.tgz#e1705ec9258ac4885659c2d50bac06b4fcd16466" + integrity sha512-hs/iBJx2aydugBQx5ETV3ZgeSS0oIreQrFJ4bjBl0XvM4wAmDjFEALY7p0rTSLt2eL+ibjRAAs9dTPiCLtmbqQ== + dependencies: + "@types/unist" "*" + "@types/hoist-non-react-statics@^3.3.0": version "3.3.2" resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#dc1e9ded53375d37603c479cc12c693b0878aa2a" @@ -2851,6 +2878,11 @@ resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.4.tgz#2b38784cd16957d3782e8e2b31c03bc1d13b4d65" integrity sha512-IDaobHimLQhjwsQ/NMwRVfa/yL7L/wriQPMhw1ZJall0KX6E1oxk29XMDeilW5qTIg5aoiqf5Udy8U/51aNoQQ== +"@types/unist@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.0.tgz#988ae8af1e5239e89f9fbb1ade4c935f4eeedf9a" + integrity sha512-MFETx3tbTjE7Uk6vvnWINA/1iJ7LuMdO4fcq8UfF0pRbj01aGLduVvQcRyswuACJdpnHgg8E3rQLhaRdNEJS0w== + "@types/unist@^2", "@types/unist@^2.0.0": version "2.0.8" resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.8.tgz#bb197b9639aa1a04cf464a617fe800cccd92ad5c" @@ -3936,6 +3968,13 @@ detect-node-es@^1.1.0: resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== +devlop@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/devlop/-/devlop-1.1.0.tgz#4db7c2ca4dc6e0e834c30be70c94bbc976dc7018" + integrity sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA== + dependencies: + dequal "^2.0.0" + didyoumean@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" @@ -5904,6 +5943,15 @@ lowlight@^2.9.0: fault "^2.0.0" highlight.js "~11.8.0" +lowlight@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-3.0.0.tgz#8772e6514f1c14cd576b5a7a22668f5aa2ddd10b" + integrity sha512-kedX6yxvgak8P4LGh3vKRDQuMbVcnP+qRuDJlve2w+mNJAbEhEQPjYCp9QJnpVL5F2aAAVjeIzzrbQZUKHiDJw== + dependencies: + "@types/hast" "^3.0.0" + devlop "^1.0.0" + highlight.js "~11.8.0" + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" From de07f6308925205f7273f2d1ef9c64ecefdb4a26 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Mon, 2 Oct 2023 16:24:57 +0530 Subject: [PATCH 25/57] read only editor support added --- packages/editor/core/src/index.ts | 15 ++- .../ui/{ => components}/editor-container.tsx | 0 .../ui/{ => components}/editor-content.tsx | 2 +- .../ui/extensions/image/read-only-image.tsx | 17 ++++ .../editor/core/src/ui/extensions/index.tsx | 6 +- .../extensions/table/{table.ts => index.ts} | 0 .../core/src/ui/hooks/useReadOnlyEditor.tsx | 37 ++++++++ .../core/src/ui/read-only/extensions.tsx | 92 +++++++++++++++++++ .../editor/core/src/ui/read-only/props.tsx | 8 ++ packages/editor/core/tsup.config.ts | 2 +- packages/editor/lite-text-editor/src/index.ts | 1 + .../src/ui/read-only/index.tsx | 54 +++++++++++ .../editor/lite-text-editor/tsup.config.ts | 2 +- packages/editor/rich-text-editor/src/index.ts | 1 + .../src/ui/read-only/index.tsx | 54 +++++++++++ .../editor/rich-text-editor/tsup.config.ts | 2 +- .../issues/comment/comment-card.tsx | 7 +- 17 files changed, 284 insertions(+), 16 deletions(-) rename packages/editor/core/src/ui/{ => components}/editor-container.tsx (100%) rename packages/editor/core/src/ui/{ => components}/editor-content.tsx (92%) create mode 100644 packages/editor/core/src/ui/extensions/image/read-only-image.tsx rename packages/editor/core/src/ui/extensions/table/{table.ts => index.ts} (100%) create mode 100644 packages/editor/core/src/ui/hooks/useReadOnlyEditor.tsx create mode 100644 packages/editor/core/src/ui/read-only/extensions.tsx create mode 100644 packages/editor/core/src/ui/read-only/props.tsx create mode 100644 packages/editor/lite-text-editor/src/ui/read-only/index.tsx create mode 100644 packages/editor/rich-text-editor/src/ui/read-only/index.tsx diff --git a/packages/editor/core/src/index.ts b/packages/editor/core/src/index.ts index 8b72e0bf3fd..c46ad933613 100644 --- a/packages/editor/core/src/index.ts +++ b/packages/editor/core/src/index.ts @@ -1,9 +1,16 @@ +// styles import "@/styles/tailwind.css"; import "@/styles/editor.css"; -export { startImageUpload } from "@/ui/plugins/upload-image"; -export { useEditor } from "@/ui/hooks/useEditor"; +// utils export { cn } from "@/lib/utils"; export { getEditorClassNames } from "@/lib/utils"; -export { EditorContainer } from "@/ui/editor-container"; -export { EditorContentWrapper } from "@/ui/editor-content"; +export { startImageUpload } from "@/ui/plugins/upload-image"; + +// components +export { EditorContainer } from "@/ui/components/editor-container"; +export { EditorContentWrapper } from "@/ui/components/editor-content"; + +// hooks +export { useEditor } from "@/ui/hooks/useEditor"; +export { useReadOnlyEditor } from "@/ui/hooks/useReadOnlyEditor"; diff --git a/packages/editor/core/src/ui/editor-container.tsx b/packages/editor/core/src/ui/components/editor-container.tsx similarity index 100% rename from packages/editor/core/src/ui/editor-container.tsx rename to packages/editor/core/src/ui/components/editor-container.tsx diff --git a/packages/editor/core/src/ui/editor-content.tsx b/packages/editor/core/src/ui/components/editor-content.tsx similarity index 92% rename from packages/editor/core/src/ui/editor-content.tsx rename to packages/editor/core/src/ui/components/editor-content.tsx index 7b06944d878..1e56e98c994 100644 --- a/packages/editor/core/src/ui/editor-content.tsx +++ b/packages/editor/core/src/ui/components/editor-content.tsx @@ -1,7 +1,7 @@ import { Editor, EditorContent } from "@tiptap/react"; import { ReactNode } from "react"; import { ImageResizer } from "@/ui/extensions/image/image-resize"; -import { TableMenu } from "./menus/table-menu"; +import { TableMenu } from "@/ui/menus/table-menu"; interface EditorContentProps { editor: Editor | null; diff --git a/packages/editor/core/src/ui/extensions/image/read-only-image.tsx b/packages/editor/core/src/ui/extensions/image/read-only-image.tsx new file mode 100644 index 00000000000..73a763d0428 --- /dev/null +++ b/packages/editor/core/src/ui/extensions/image/read-only-image.tsx @@ -0,0 +1,17 @@ +import Image from "@tiptap/extension-image"; + +const ReadOnlyImageExtension = Image.extend({ + addAttributes() { + return { + ...this.parent?.(), + width: { + default: "35%", + }, + height: { + default: null, + }, + }; + }, +}); + +export default ReadOnlyImageExtension; diff --git a/packages/editor/core/src/ui/extensions/index.tsx b/packages/editor/core/src/ui/extensions/index.tsx index b2d0a5c576d..7aac1adb1a7 100644 --- a/packages/editor/core/src/ui/extensions/index.tsx +++ b/packages/editor/core/src/ui/extensions/index.tsx @@ -8,9 +8,9 @@ import TaskList from "@tiptap/extension-task-list"; import { Markdown } from "tiptap-markdown"; import Gapcursor from "@tiptap/extension-gapcursor"; -import { CustomTableCell } from "./table/table-cell"; -import { Table } from "./table/table"; -import { TableHeader } from "./table/table-header"; +import { CustomTableCell } from "@/ui/extensions/table/table-cell"; +import { Table } from "@/ui/extensions/table"; +import { TableHeader } from "@/ui/extensions/table/table-header"; import { TableRow } from "@tiptap/extension-table-row"; import ImageExtension from "@/ui/extensions/image"; diff --git a/packages/editor/core/src/ui/extensions/table/table.ts b/packages/editor/core/src/ui/extensions/table/index.ts similarity index 100% rename from packages/editor/core/src/ui/extensions/table/table.ts rename to packages/editor/core/src/ui/extensions/table/index.ts diff --git a/packages/editor/core/src/ui/hooks/useReadOnlyEditor.tsx b/packages/editor/core/src/ui/hooks/useReadOnlyEditor.tsx new file mode 100644 index 00000000000..5d08b867c27 --- /dev/null +++ b/packages/editor/core/src/ui/hooks/useReadOnlyEditor.tsx @@ -0,0 +1,37 @@ +import { useEditor as useCustomEditor, Editor } from "@tiptap/react"; +import { useImperativeHandle, useRef, MutableRefObject } from "react"; +import { CoreReadOnlyEditorExtensions } from "@/ui/read-only/extensions"; +import { CoreReadOnlyEditorProps } from "@/ui/read-only/props"; + +interface CustomReadOnlyEditorProps { + value: string; + forwardedRef?: any; +} + +export const useReadOnlyEditor = ({ value, forwardedRef }: CustomReadOnlyEditorProps) => { + const editor = useCustomEditor({ + editable: false, + content: (typeof value === "string" && value.trim() !== "") ? value : "

", + editorProps: CoreReadOnlyEditorProps, + extensions: CoreReadOnlyEditorExtensions, + }); + + const editorRef: MutableRefObject = useRef(null); + editorRef.current = editor; + + useImperativeHandle(forwardedRef, () => ({ + clearEditor: () => { + editorRef.current?.commands.clearContent(); + }, + setEditorValue: (content: string) => { + editorRef.current?.commands.setContent(content); + }, + })); + + + if (!editor) { + return null; + } + + return editor; +}; diff --git a/packages/editor/core/src/ui/read-only/extensions.tsx b/packages/editor/core/src/ui/read-only/extensions.tsx new file mode 100644 index 00000000000..f879b2744a3 --- /dev/null +++ b/packages/editor/core/src/ui/read-only/extensions.tsx @@ -0,0 +1,92 @@ +import StarterKit from "@tiptap/starter-kit"; +import TiptapLink from "@tiptap/extension-link"; +import TiptapUnderline from "@tiptap/extension-underline"; +import TextStyle from "@tiptap/extension-text-style"; +import { Color } from "@tiptap/extension-color"; +import TaskItem from "@tiptap/extension-task-item"; +import TaskList from "@tiptap/extension-task-list"; +import { Markdown } from "tiptap-markdown"; +import Gapcursor from "@tiptap/extension-gapcursor"; + +import { CustomTableCell } from "@/ui/extensions/table/table-cell"; +import { Table } from "@/ui/extensions/table"; +import { TableHeader } from "@/ui/extensions/table/table-header"; +import { TableRow } from "@tiptap/extension-table-row"; + +import isValidHttpUrl from "@/ui/menus/bubble-menu/utils"; +import ReadOnlyImageExtension from "@/ui/extensions/image/read-only-image"; + +export const CoreReadOnlyEditorExtensions = [ + StarterKit.configure({ + bulletList: { + HTMLAttributes: { + class: "list-disc list-outside leading-3 -mt-2", + }, + }, + orderedList: { + HTMLAttributes: { + class: "list-decimal list-outside leading-3 -mt-2", + }, + }, + listItem: { + HTMLAttributes: { + class: "leading-normal -mb-2", + }, + }, + blockquote: { + HTMLAttributes: { + class: "border-l-4 border-custom-border-300", + }, + }, + code: { + HTMLAttributes: { + class: + "rounded-md bg-custom-primary-30 mx-1 px-1 py-1 font-mono font-medium text-custom-text-1000", + spellcheck: "false", + }, + }, + codeBlock: false, + horizontalRule: false, + dropcursor: { + color: "rgba(var(--color-text-100))", + width: 2, + }, + gapcursor: false, + }), + Gapcursor, + TiptapLink.configure({ + protocols: ["http", "https"], + validate: (url) => isValidHttpUrl(url), + HTMLAttributes: { + class: + "text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer", + }, + }), + ReadOnlyImageExtension.configure({ + HTMLAttributes: { + class: "rounded-lg border border-custom-border-300", + }, + }), + TiptapUnderline, + TextStyle, + Color, + TaskList.configure({ + HTMLAttributes: { + class: "not-prose pl-2", + }, + }), + TaskItem.configure({ + HTMLAttributes: { + class: "flex items-start my-4", + }, + nested: true, + }), + Markdown.configure({ + html: true, + transformCopiedText: true, + }), + Table, + TableHeader, + CustomTableCell, + TableRow, + ]; diff --git a/packages/editor/core/src/ui/read-only/props.tsx b/packages/editor/core/src/ui/read-only/props.tsx new file mode 100644 index 00000000000..25db2b68c1a --- /dev/null +++ b/packages/editor/core/src/ui/read-only/props.tsx @@ -0,0 +1,8 @@ +import { EditorProps } from "@tiptap/pm/view"; + +export const CoreReadOnlyEditorProps: EditorProps = +{ + attributes: { + class: `prose prose-brand max-w-full prose-headings:font-display font-default focus:outline-none`, + }, +}; diff --git a/packages/editor/core/tsup.config.ts b/packages/editor/core/tsup.config.ts index 907f339a1d0..5e89e04afad 100644 --- a/packages/editor/core/tsup.config.ts +++ b/packages/editor/core/tsup.config.ts @@ -3,7 +3,7 @@ import { defineConfig, Options } from "tsup"; export default defineConfig((options: Options) => ({ entry: ["src/index.ts"], format: ["cjs", "esm"], - dts: false, + dts: true, clean: false, external: ["react"], injectStyle: true, diff --git a/packages/editor/lite-text-editor/src/index.ts b/packages/editor/lite-text-editor/src/index.ts index 9238be8b965..0a276d1c049 100644 --- a/packages/editor/lite-text-editor/src/index.ts +++ b/packages/editor/lite-text-editor/src/index.ts @@ -1 +1,2 @@ export { LiteTextEditor, LiteTextEditorWithRef } from "@/ui"; +export { LiteReadOnlyEditor, LiteReadOnlyEditorWithRef } from "@/ui/read-only"; diff --git a/packages/editor/lite-text-editor/src/ui/read-only/index.tsx b/packages/editor/lite-text-editor/src/ui/read-only/index.tsx new file mode 100644 index 00000000000..3990cb734f5 --- /dev/null +++ b/packages/editor/lite-text-editor/src/ui/read-only/index.tsx @@ -0,0 +1,54 @@ +"use client" +import { EditorContainer, EditorContentWrapper, getEditorClassNames, useReadOnlyEditor } from '@plane/editor-core'; +import * as React from 'react'; + +interface ICoreReadOnlyEditor { + value: string; + editorContentCustomClassNames?: string; + noBorder?: boolean; + borderOnFocus?: boolean; + customClassName?: string; +} + +interface EditorCoreProps extends ICoreReadOnlyEditor { + forwardedRef?: React.Ref; +} + +interface EditorHandle { + clearEditor: () => void; + setEditorValue: (content: string) => void; +} + +const LiteReadOnlyEditor = ({ + editorContentCustomClassNames, + noBorder, + borderOnFocus, + customClassName, + value, + forwardedRef, +}: EditorCoreProps) => { + const editor = useReadOnlyEditor({ + value, + forwardedRef, + }); + + const editorClassNames = getEditorClassNames({ noBorder, borderOnFocus, customClassName }); + + if (!editor) return null; + + return ( + +
+ +
+
+ ); +}; + +const LiteReadOnlyEditorWithRef = React.forwardRef((props, ref) => ( + +)); + +LiteReadOnlyEditorWithRef.displayName = "LiteReadOnlyEditorWithRef"; + +export { LiteReadOnlyEditor , LiteReadOnlyEditorWithRef }; diff --git a/packages/editor/lite-text-editor/tsup.config.ts b/packages/editor/lite-text-editor/tsup.config.ts index 907f339a1d0..5e89e04afad 100644 --- a/packages/editor/lite-text-editor/tsup.config.ts +++ b/packages/editor/lite-text-editor/tsup.config.ts @@ -3,7 +3,7 @@ import { defineConfig, Options } from "tsup"; export default defineConfig((options: Options) => ({ entry: ["src/index.ts"], format: ["cjs", "esm"], - dts: false, + dts: true, clean: false, external: ["react"], injectStyle: true, diff --git a/packages/editor/rich-text-editor/src/index.ts b/packages/editor/rich-text-editor/src/index.ts index b7ef6bbe4ba..dd8f35791a8 100644 --- a/packages/editor/rich-text-editor/src/index.ts +++ b/packages/editor/rich-text-editor/src/index.ts @@ -1,3 +1,4 @@ import "@/styles/github-dark.css"; export { RichTextEditor, RichTextEditorWithRef } from "@/ui"; +export { RichReadOnlyEditor, RichReadOnlyEditorWithRef } from "@/ui/read-only"; diff --git a/packages/editor/rich-text-editor/src/ui/read-only/index.tsx b/packages/editor/rich-text-editor/src/ui/read-only/index.tsx new file mode 100644 index 00000000000..dc058cf8937 --- /dev/null +++ b/packages/editor/rich-text-editor/src/ui/read-only/index.tsx @@ -0,0 +1,54 @@ +"use client" +import { EditorContainer, EditorContentWrapper, getEditorClassNames, useReadOnlyEditor } from '@plane/editor-core'; +import * as React from 'react'; + +interface IRichTextReadOnlyEditor { + value: string; + editorContentCustomClassNames?: string; + noBorder?: boolean; + borderOnFocus?: boolean; + customClassName?: string; +} + +interface RichTextReadOnlyEditorProps extends IRichTextReadOnlyEditor { + forwardedRef?: React.Ref; +} + +interface EditorHandle { + clearEditor: () => void; + setEditorValue: (content: string) => void; +} + +const RichReadOnlyEditor = ({ + editorContentCustomClassNames, + noBorder, + borderOnFocus, + customClassName, + value, + forwardedRef, +}: RichTextReadOnlyEditorProps) => { + const editor = useReadOnlyEditor({ + value, + forwardedRef, + }); + + const editorClassNames = getEditorClassNames({ noBorder, borderOnFocus, customClassName }); + + if (!editor) return null; + + return ( + +
+ +
+
+ ); +}; + +const RichReadOnlyEditorWithRef = React.forwardRef((props, ref) => ( + +)); + +RichReadOnlyEditorWithRef.displayName = "RichReadOnlyEditorWithRef"; + +export { RichReadOnlyEditor , RichReadOnlyEditorWithRef }; diff --git a/packages/editor/rich-text-editor/tsup.config.ts b/packages/editor/rich-text-editor/tsup.config.ts index 907f339a1d0..5e89e04afad 100644 --- a/packages/editor/rich-text-editor/tsup.config.ts +++ b/packages/editor/rich-text-editor/tsup.config.ts @@ -3,7 +3,7 @@ import { defineConfig, Options } from "tsup"; export default defineConfig((options: Options) => ({ entry: ["src/index.ts"], format: ["cjs", "esm"], - dts: false, + dts: true, clean: false, external: ["react"], injectStyle: true, diff --git a/web/components/issues/comment/comment-card.tsx b/web/components/issues/comment/comment-card.tsx index 147c49bd16e..db33189f812 100644 --- a/web/components/issues/comment/comment-card.tsx +++ b/web/components/issues/comment/comment-card.tsx @@ -9,7 +9,7 @@ import useUser from "hooks/use-user"; // ui import { CustomMenu, Icon } from "components/ui"; import { CommentReaction } from "components/issues"; -import { LiteTextEditorWithRef } from "@plane/lite-text-editor"; +import { LiteTextEditorWithRef, LiteReadOnlyEditorWithRef } from "@plane/lite-text-editor"; // helpers import { timeAgo } from "helpers/date-time.helper"; // types @@ -151,12 +151,9 @@ export const CommentCard: React.FC = ({ />
)} - From 51e281592f3c73f8f8dd99f073f9575f5633a5b1 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Mon, 2 Oct 2023 16:35:54 +0530 Subject: [PATCH 26/57] replaced all read-only instances --- packages/editor/core/src/ui/index.tsx | 4 +- .../comment/comment-detail-card.tsx | 9 +-- .../issues/peek-overview/issue-details.tsx | 55 +++++++------------ .../core/modals/gpt-assistant-modal.tsx | 32 ++++------- .../[workspaceSlug]/me/profile/activity.tsx | 19 +++---- 5 files changed, 44 insertions(+), 75 deletions(-) diff --git a/packages/editor/core/src/ui/index.tsx b/packages/editor/core/src/ui/index.tsx index 2871075a812..93e7b682980 100644 --- a/packages/editor/core/src/ui/index.tsx +++ b/packages/editor/core/src/ui/index.tsx @@ -6,8 +6,8 @@ import { DeleteImage } from '@/types/delete-image'; import { getEditorClassNames } from '@/lib/utils'; import { EditorProps } from '@tiptap/pm/view'; import { useEditor } from './hooks/useEditor'; -import { EditorContainer } from '@/ui/editor-container'; -import { EditorContentWrapper } from '@/ui/editor-content'; +import { EditorContainer } from '@/ui/components/editor-container'; +import { EditorContentWrapper } from '@/ui/components/editor-content'; interface ICoreEditor { value: string; diff --git a/space/components/issues/peek-overview/comment/comment-detail-card.tsx b/space/components/issues/peek-overview/comment/comment-detail-card.tsx index fc5140af2e4..cfd7ba49379 100644 --- a/space/components/issues/peek-overview/comment/comment-detail-card.tsx +++ b/space/components/issues/peek-overview/comment/comment-detail-card.tsx @@ -9,7 +9,7 @@ import { Menu, Transition } from "@headlessui/react"; // lib import { useMobxStore } from "lib/mobx/store-provider"; // components -import { RichTextEditorWithRef } from "@plane/rich-text-editor"; +import { LiteReadOnlyEditorWithRef, LiteTextEditorWithRef } from "@plane/lite-text-editor"; import { CommentReactions } from "components/issues/peek-overview"; // icons @@ -103,7 +103,7 @@ export const CommentCard: React.FC = observer((props) => { control={control} name="comment_html" render={({ field: { onChange, value } }) => ( - = observer((props) => {
- diff --git a/space/components/issues/peek-overview/issue-details.tsx b/space/components/issues/peek-overview/issue-details.tsx index f6f34c5b2e8..24dd656513b 100644 --- a/space/components/issues/peek-overview/issue-details.tsx +++ b/space/components/issues/peek-overview/issue-details.tsx @@ -1,43 +1,28 @@ import { IssueReactions } from "components/issues/peek-overview"; -import { RichTextEditor } from "@plane/rich-text-editor"; -import { useRouter } from "next/router"; +import { RichReadOnlyEditor } from "@plane/rich-text-editor"; // types import { IIssue } from "types/issue"; -// services -import fileService from "@/services/file.service"; type Props = { issueDetails: IIssue; }; -export const PeekOverviewIssueDetails: React.FC = ({ issueDetails }) => { - const router = useRouter(); - const { workspace_slug } = router.query; - - return ( -
-
- {issueDetails.project_detail.identifier}-{issueDetails.sequence_id} -
-

{issueDetails.name}

- {issueDetails.description_html !== "" && issueDetails.description_html !== "

" && ( -

" - : issueDetails.description_html - } - customClassName="p-3 min-h-[50px] shadow-sm" - debouncedUpdatesEnabled={false} - editable={false} - /> - )} - -
- ); -}; +export const PeekOverviewIssueDetails: React.FC = ({ issueDetails }) => ( +
+
+ {issueDetails.project_detail.identifier}-{issueDetails.sequence_id} +
+

{issueDetails.name}

+ {issueDetails.description_html !== "" && issueDetails.description_html !== "

" && ( +

" + : issueDetails.description_html} + customClassName="p-3 min-h-[50px] shadow-sm" /> + )} + +
+); diff --git a/web/components/core/modals/gpt-assistant-modal.tsx b/web/components/core/modals/gpt-assistant-modal.tsx index 236037531e7..65495805aee 100644 --- a/web/components/core/modals/gpt-assistant-modal.tsx +++ b/web/components/core/modals/gpt-assistant-modal.tsx @@ -11,11 +11,9 @@ import useUserAuth from "hooks/use-user-auth"; // ui import { Input, PrimaryButton, SecondaryButton } from "components/ui"; // components -import { RichTextEditor, RichTextEditorWithRef } from "@plane/rich-text-editor"; +import { RichReadOnlyEditor, RichReadOnlyEditorWithRef } from "@plane/rich-text-editor"; // types import { IIssue, IPageBlock } from "types"; -// services -import fileService from "@/services/file.service"; type Props = { isOpen: boolean; @@ -136,21 +134,17 @@ export const GptAssistantModal: React.FC = ({ return (
{((content && content !== "") || (htmlContent && htmlContent !== "

")) && (
Content: - ${content}

`} customClassName="-m-3" noBorder borderOnFocus={false} - editable={false} ref={editorRef} />
@@ -158,14 +152,11 @@ export const GptAssistantModal: React.FC = ({ {response !== "" && (
Response: - ${response}

`} customClassName="-mx-3 -my-3" noBorder borderOnFocus={false} - editable={false} />
)} @@ -179,11 +170,10 @@ export const GptAssistantModal: React.FC = ({ type="text" name="task" register={register} - placeholder={`${ - content && content !== "" - ? "Tell AI what action to perform on this content..." - : "Ask AI anything..." - }`} + placeholder={`${content && content !== "" + ? "Tell AI what action to perform on this content..." + : "Ask AI anything..." + }`} autoComplete="off" />
@@ -219,8 +209,8 @@ export const GptAssistantModal: React.FC = ({ {isSubmitting ? "Generating response..." : response === "" - ? "Generate response" - : "Generate again"} + ? "Generate response" + : "Generate again"}
diff --git a/web/pages/[workspaceSlug]/me/profile/activity.tsx b/web/pages/[workspaceSlug]/me/profile/activity.tsx index 68e46723df6..a50fdde017e 100644 --- a/web/pages/[workspaceSlug]/me/profile/activity.tsx +++ b/web/pages/[workspaceSlug]/me/profile/activity.tsx @@ -9,7 +9,7 @@ import userService from "services/user.service"; import { WorkspaceAuthorizationLayout } from "layouts/auth-layout"; // components import { ActivityIcon, ActivityMessage } from "components/core"; -import { RichTextEditor } from "@plane/rich-text-editor"; +import { RichReadOnlyEditor } from "@plane/rich-text-editor"; // icons import { ArrowTopRightOnSquareIcon, ChatBubbleLeftEllipsisIcon } from "@heroicons/react/24/outline"; // ui @@ -98,9 +98,7 @@ const ProfileActivity = () => {

- { customClassName="text-xs border border-custom-border-200 bg-custom-background-100" noBorder borderOnFocus={false} - editable={false} />
@@ -120,11 +117,11 @@ const ProfileActivity = () => { const message = activityItem.verb === "created" && - activityItem.field !== "cycles" && - activityItem.field !== "modules" && - activityItem.field !== "attachment" && - activityItem.field !== "link" && - activityItem.field !== "estimate" ? ( + activityItem.field !== "cycles" && + activityItem.field !== "modules" && + activityItem.field !== "attachment" && + activityItem.field !== "link" && + activityItem.field !== "estimate" ? ( created{" "} {
{activityItem.field === "archived_at" && - activityItem.new_value !== "restore" ? ( + activityItem.new_value !== "restore" ? ( Plane ) : activityItem.actor_detail.is_bot ? ( From 2c804c8d6c93b89ad65b802d8b921cfe3cf07e77 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Mon, 2 Oct 2023 17:44:56 +0530 Subject: [PATCH 27/57] trimming html at start and end of content added --- packages/editor/core/src/lib/utils.ts | 30 +++++++++++-------- .../editor/core/src/ui/hooks/useEditor.tsx | 6 ++-- .../[workspaceSlug]/me/profile/activity.tsx | 2 -- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/packages/editor/core/src/lib/utils.ts b/packages/editor/core/src/lib/utils.ts index 64b5a3db76b..82618a4c6a5 100644 --- a/packages/editor/core/src/lib/utils.ts +++ b/packages/editor/core/src/lib/utils.ts @@ -1,5 +1,17 @@ import { clsx, type ClassValue } from "clsx"; import { twMerge } from "tailwind-merge"; +interface EditorClassNames { + noBorder?: boolean; + borderOnFocus?: boolean; + customClassName?: string; +} + +export const getEditorClassNames = ({ noBorder, borderOnFocus, customClassName }: EditorClassNames) => cn( + 'relative w-full max-w-full sm:rounded-lg mt-2 p-3 relative focus:outline-none rounded-md', + noBorder ? '' : 'border border-custom-border-200', + borderOnFocus ? 'focus:border border-custom-border-300' : 'focus:border-0', + customClassName +); export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); @@ -14,16 +26,8 @@ export const findTableAncestor = ( return node as HTMLTableElement; }; -interface EditorClassNames { - noBorder?: boolean; - borderOnFocus?: boolean; - customClassName?: string; -} - -export const getEditorClassNames = ({ noBorder, borderOnFocus, customClassName }: EditorClassNames) => cn( - 'relative w-full max-w-full sm:rounded-lg mt-2 p-3 relative focus:outline-none rounded-md', - noBorder ? '' : 'border border-custom-border-200', - borderOnFocus ? 'focus:border border-custom-border-300' : 'focus:border-0', - customClassName -); - +export const getTrimmedHTML = (html: string) => { + html = html.replace(/^(

<\/p>)+/, ''); + html = html.replace(/(

<\/p>)+$/, ''); + return html; +} \ No newline at end of file diff --git a/packages/editor/core/src/ui/hooks/useEditor.tsx b/packages/editor/core/src/ui/hooks/useEditor.tsx index 7f762911913..43d7799ee29 100644 --- a/packages/editor/core/src/ui/hooks/useEditor.tsx +++ b/packages/editor/core/src/ui/hooks/useEditor.tsx @@ -6,6 +6,7 @@ import { DeleteImage } from '@/types/delete-image'; import { CoreEditorProps } from "../props"; import { CoreEditorExtensions } from "../extensions"; import { EditorProps } from '@tiptap/pm/view'; +import { getTrimmedHTML } from "@/lib/utils"; const DEBOUNCE_DELAY = 1500; @@ -24,6 +25,7 @@ interface CustomEditorProps { } export const useEditor = ({ uploadFile, editable, deleteFile, editorProps = {}, value, extensions = [], onChange, setIsSubmitting, debouncedUpdatesEnabled, forwardedRef, setShouldShowAlert, }: CustomEditorProps) => { + console.log("content aaya", value) const editor = useCustomEditor({ editable: editable ?? true, editorProps: { @@ -39,7 +41,7 @@ export const useEditor = ({ uploadFile, editable, deleteFile, editorProps = {}, if (debouncedUpdatesEnabled) { debouncedUpdates({ onChange: onChange, editor }); } else { - onChange?.(editor.getJSON(), editor.getHTML()); + onChange?.(editor.getJSON(), getTrimmedHTML(editor.getHTML())); } }, }); @@ -58,7 +60,7 @@ export const useEditor = ({ uploadFile, editable, deleteFile, editorProps = {}, const debouncedUpdates = useDebouncedCallback(async ({ onChange, editor }) => { if (onChange) { - onChange(editor.getJSON(), editor.getHTML()); + onChange(editor.getJSON(), getTrimmedHTML(editor.getHTML())); } }, DEBOUNCE_DELAY); diff --git a/web/pages/[workspaceSlug]/me/profile/activity.tsx b/web/pages/[workspaceSlug]/me/profile/activity.tsx index a50fdde017e..9305577cf0c 100644 --- a/web/pages/[workspaceSlug]/me/profile/activity.tsx +++ b/web/pages/[workspaceSlug]/me/profile/activity.tsx @@ -20,8 +20,6 @@ import { USER_ACTIVITY } from "constants/fetch-keys"; // helper import { timeAgo } from "helpers/date-time.helper"; import { SettingsSidebar } from "components/project"; -// services -import fileService from "@/services/file.service"; const ProfileActivity = () => { const router = useRouter(); From b479718ecef71527f6c1d753f85988bf076f1aac Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Mon, 2 Oct 2023 20:10:05 +0530 Subject: [PATCH 28/57] onSubmit on enterkey captured --- .../src/ui/extensions/enter-key-extension.tsx | 14 ++++++++++++++ .../lite-text-editor/src/ui/extensions/index.tsx | 5 +++++ packages/editor/lite-text-editor/src/ui/index.tsx | 2 ++ packages/editor/rich-text-editor/tsconfig.json | 2 +- 4 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 packages/editor/lite-text-editor/src/ui/extensions/enter-key-extension.tsx create mode 100644 packages/editor/lite-text-editor/src/ui/extensions/index.tsx diff --git a/packages/editor/lite-text-editor/src/ui/extensions/enter-key-extension.tsx b/packages/editor/lite-text-editor/src/ui/extensions/enter-key-extension.tsx new file mode 100644 index 00000000000..3d19703eced --- /dev/null +++ b/packages/editor/lite-text-editor/src/ui/extensions/enter-key-extension.tsx @@ -0,0 +1,14 @@ +import { Extension } from '@tiptap/core'; + +export const EnterKeyExtension = Extension.create({ + name: 'enterKey', + + addKeyboardShortcuts() { + return { + 'Enter': () => { + console.log('Submit comment'); + return true; + }, + } + }, +}); diff --git a/packages/editor/lite-text-editor/src/ui/extensions/index.tsx b/packages/editor/lite-text-editor/src/ui/extensions/index.tsx new file mode 100644 index 00000000000..e1ef3db84b8 --- /dev/null +++ b/packages/editor/lite-text-editor/src/ui/extensions/index.tsx @@ -0,0 +1,5 @@ +import { EnterKeyExtension } from "./enter-key-extension"; + +export const LiteTextEditorExtensions = () => [ + EnterKeyExtension + ]; diff --git a/packages/editor/lite-text-editor/src/ui/index.tsx b/packages/editor/lite-text-editor/src/ui/index.tsx index 85321fccb12..dfdee150541 100644 --- a/packages/editor/lite-text-editor/src/ui/index.tsx +++ b/packages/editor/lite-text-editor/src/ui/index.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import { EditorContainer, EditorContentWrapper, getEditorClassNames, useEditor } from '@plane/editor-core'; import { FixedMenu } from './menus/fixed-menu'; +import { LiteTextEditorExtensions } from './extensions'; export type UploadImage = (file: File) => Promise; export type DeleteImage = (assetUrlWithWorkspaceId: string) => Promise; @@ -67,6 +68,7 @@ const LiteTextEditor = ({ uploadFile, deleteFile, forwardedRef, + extensions: LiteTextEditorExtensions(), }); const editorClassNames = getEditorClassNames({ noBorder, borderOnFocus, customClassName }); diff --git a/packages/editor/rich-text-editor/tsconfig.json b/packages/editor/rich-text-editor/tsconfig.json index bf38514e1f7..f83a493ea84 100644 --- a/packages/editor/rich-text-editor/tsconfig.json +++ b/packages/editor/rich-text-editor/tsconfig.json @@ -3,7 +3,7 @@ "include": [ "src/**/*", "index.d.ts" - ], +, "../lite-text-editor/src/ui/extensions/enter-key-extension.tsx" ], "exclude": [ "dist", "build", From 857fa18719daae5fcbd48266ae791156749b4e06 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Tue, 3 Oct 2023 09:27:52 +0530 Subject: [PATCH 29/57] removed absolute imports from editor/core package --- packages/editor/core/src/index.ts | 18 +++++++++--------- .../core/src/ui/components/editor-content.tsx | 4 ++-- .../core/src/ui/extensions/image/index.tsx | 6 +++--- .../editor/core/src/ui/extensions/index.tsx | 12 ++++++------ .../editor/core/src/ui/hooks/useEditor.tsx | 7 +++---- .../core/src/ui/hooks/useReadOnlyEditor.tsx | 4 ++-- packages/editor/core/src/ui/index.tsx | 10 +++++----- .../core/src/ui/menus/bubble-menu/index.tsx | 2 +- .../src/ui/menus/bubble-menu/link-selector.tsx | 4 ++-- .../src/ui/menus/bubble-menu/node-selector.tsx | 2 +- .../core/src/ui/menus/fixed-menu/index.tsx | 2 +- .../core/src/ui/menus/table-menu/index.tsx | 2 +- .../core/src/ui/plugins/delete-image.tsx | 2 +- .../core/src/ui/plugins/upload-image.tsx | 2 +- packages/editor/core/src/ui/props.tsx | 6 +++--- .../core/src/ui/read-only/extensions.tsx | 10 +++++----- packages/editor/core/tsconfig.json | 5 ----- .../src/ui/extensions/index.tsx | 2 +- .../src/ui/extensions/index.tsx | 2 +- 19 files changed, 48 insertions(+), 54 deletions(-) diff --git a/packages/editor/core/src/index.ts b/packages/editor/core/src/index.ts index c46ad933613..523c1cdff94 100644 --- a/packages/editor/core/src/index.ts +++ b/packages/editor/core/src/index.ts @@ -1,16 +1,16 @@ // styles -import "@/styles/tailwind.css"; -import "@/styles/editor.css"; +import "./styles/tailwind.css"; +import "./styles/editor.css"; // utils -export { cn } from "@/lib/utils"; -export { getEditorClassNames } from "@/lib/utils"; -export { startImageUpload } from "@/ui/plugins/upload-image"; +export { cn } from "./lib/utils"; +export { getEditorClassNames } from "./lib/utils"; +export { startImageUpload } from "./ui/plugins/upload-image"; // components -export { EditorContainer } from "@/ui/components/editor-container"; -export { EditorContentWrapper } from "@/ui/components/editor-content"; +export { EditorContainer } from "./ui/components/editor-container"; +export { EditorContentWrapper } from "./ui/components/editor-content"; // hooks -export { useEditor } from "@/ui/hooks/useEditor"; -export { useReadOnlyEditor } from "@/ui/hooks/useReadOnlyEditor"; +export { useEditor } from "./ui/hooks/useEditor"; +export { useReadOnlyEditor } from "./ui/hooks/useReadOnlyEditor"; diff --git a/packages/editor/core/src/ui/components/editor-content.tsx b/packages/editor/core/src/ui/components/editor-content.tsx index 1e56e98c994..5ca07765767 100644 --- a/packages/editor/core/src/ui/components/editor-content.tsx +++ b/packages/editor/core/src/ui/components/editor-content.tsx @@ -1,7 +1,7 @@ import { Editor, EditorContent } from "@tiptap/react"; import { ReactNode } from "react"; -import { ImageResizer } from "@/ui/extensions/image/image-resize"; -import { TableMenu } from "@/ui/menus/table-menu"; +import { ImageResizer } from "../extensions/image/image-resize"; +import { TableMenu } from "../menus/table-menu"; interface EditorContentProps { editor: Editor | null; diff --git a/packages/editor/core/src/ui/extensions/image/index.tsx b/packages/editor/core/src/ui/extensions/image/index.tsx index ac8d4359731..f9345509d98 100644 --- a/packages/editor/core/src/ui/extensions/image/index.tsx +++ b/packages/editor/core/src/ui/extensions/image/index.tsx @@ -1,7 +1,7 @@ import Image from "@tiptap/extension-image"; -import TrackImageDeletionPlugin from "@/ui/plugins/delete-image"; -import UploadImagesPlugin from "@/ui/plugins/upload-image"; -import { DeleteImage } from "@/types/delete-image"; +import TrackImageDeletionPlugin from "../../plugins/delete-image"; +import UploadImagesPlugin from "../../plugins/upload-image"; +import { DeleteImage } from "../../../types/delete-image"; const ImageExtension = (deleteImage: DeleteImage) => Image.extend({ addProseMirrorPlugins() { diff --git a/packages/editor/core/src/ui/extensions/index.tsx b/packages/editor/core/src/ui/extensions/index.tsx index 7aac1adb1a7..acd60e63467 100644 --- a/packages/editor/core/src/ui/extensions/index.tsx +++ b/packages/editor/core/src/ui/extensions/index.tsx @@ -8,16 +8,16 @@ import TaskList from "@tiptap/extension-task-list"; import { Markdown } from "tiptap-markdown"; import Gapcursor from "@tiptap/extension-gapcursor"; -import { CustomTableCell } from "@/ui/extensions/table/table-cell"; -import { Table } from "@/ui/extensions/table"; -import { TableHeader } from "@/ui/extensions/table/table-header"; +import { CustomTableCell } from "./table/table-cell"; +import { Table } from "./table"; +import { TableHeader } from "./table/table-header"; import { TableRow } from "@tiptap/extension-table-row"; -import ImageExtension from "@/ui/extensions/image"; +import ImageExtension from "./image"; -import { DeleteImage } from "@/types/delete-image"; +import { DeleteImage } from "../../types/delete-image"; -import isValidHttpUrl from "@/ui/menus/bubble-menu/utils" +import isValidHttpUrl from "../menus/bubble-menu/utils" export const CoreEditorExtensions = ( deleteFile: DeleteImage, diff --git a/packages/editor/core/src/ui/hooks/useEditor.tsx b/packages/editor/core/src/ui/hooks/useEditor.tsx index 43d7799ee29..9a3f4882af6 100644 --- a/packages/editor/core/src/ui/hooks/useEditor.tsx +++ b/packages/editor/core/src/ui/hooks/useEditor.tsx @@ -1,12 +1,12 @@ import { useEditor as useCustomEditor, Editor } from "@tiptap/react"; import { useImperativeHandle, useRef, MutableRefObject } from "react"; import { useDebouncedCallback } from "use-debounce"; -import { UploadImage } from '@/types/upload-image'; -import { DeleteImage } from '@/types/delete-image'; +import { DeleteImage } from '../../types/delete-image'; import { CoreEditorProps } from "../props"; import { CoreEditorExtensions } from "../extensions"; import { EditorProps } from '@tiptap/pm/view'; -import { getTrimmedHTML } from "@/lib/utils"; +import { getTrimmedHTML } from "../../lib/utils"; +import { UploadImage } from "../../types/upload-image"; const DEBOUNCE_DELAY = 1500; @@ -25,7 +25,6 @@ interface CustomEditorProps { } export const useEditor = ({ uploadFile, editable, deleteFile, editorProps = {}, value, extensions = [], onChange, setIsSubmitting, debouncedUpdatesEnabled, forwardedRef, setShouldShowAlert, }: CustomEditorProps) => { - console.log("content aaya", value) const editor = useCustomEditor({ editable: editable ?? true, editorProps: { diff --git a/packages/editor/core/src/ui/hooks/useReadOnlyEditor.tsx b/packages/editor/core/src/ui/hooks/useReadOnlyEditor.tsx index 5d08b867c27..a6130cff149 100644 --- a/packages/editor/core/src/ui/hooks/useReadOnlyEditor.tsx +++ b/packages/editor/core/src/ui/hooks/useReadOnlyEditor.tsx @@ -1,7 +1,7 @@ import { useEditor as useCustomEditor, Editor } from "@tiptap/react"; import { useImperativeHandle, useRef, MutableRefObject } from "react"; -import { CoreReadOnlyEditorExtensions } from "@/ui/read-only/extensions"; -import { CoreReadOnlyEditorProps } from "@/ui/read-only/props"; +import { CoreReadOnlyEditorExtensions } from "../../ui/read-only/extensions"; +import { CoreReadOnlyEditorProps } from "../../ui/read-only/props"; interface CustomReadOnlyEditorProps { value: string; diff --git a/packages/editor/core/src/ui/index.tsx b/packages/editor/core/src/ui/index.tsx index 93e7b682980..3c64e8ba68d 100644 --- a/packages/editor/core/src/ui/index.tsx +++ b/packages/editor/core/src/ui/index.tsx @@ -1,13 +1,13 @@ "use client" import * as React from 'react'; import { Extension } from "@tiptap/react"; -import { UploadImage } from '@/types/upload-image'; -import { DeleteImage } from '@/types/delete-image'; -import { getEditorClassNames } from '@/lib/utils'; +import { UploadImage } from '../types/upload-image'; +import { DeleteImage } from '../types/delete-image'; +import { getEditorClassNames } from '../lib/utils'; import { EditorProps } from '@tiptap/pm/view'; import { useEditor } from './hooks/useEditor'; -import { EditorContainer } from '@/ui/components/editor-container'; -import { EditorContentWrapper } from '@/ui/components/editor-content'; +import { EditorContainer } from '../ui/components/editor-container'; +import { EditorContentWrapper } from '../ui/components/editor-content'; interface ICoreEditor { value: string; diff --git a/packages/editor/core/src/ui/menus/bubble-menu/index.tsx b/packages/editor/core/src/ui/menus/bubble-menu/index.tsx index 9592cf6175f..686cd919437 100644 --- a/packages/editor/core/src/ui/menus/bubble-menu/index.tsx +++ b/packages/editor/core/src/ui/menus/bubble-menu/index.tsx @@ -4,7 +4,7 @@ import { BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, CodeIcon } from import { NodeSelector } from "./node-selector"; import { LinkSelector } from "./link-selector"; -import { cn } from "@/lib/utils"; +import { cn } from "../../../lib/utils"; export interface BubbleMenuItem { name: string; diff --git a/packages/editor/core/src/ui/menus/bubble-menu/link-selector.tsx b/packages/editor/core/src/ui/menus/bubble-menu/link-selector.tsx index f3730c4dcf3..7060ff9d8e6 100644 --- a/packages/editor/core/src/ui/menus/bubble-menu/link-selector.tsx +++ b/packages/editor/core/src/ui/menus/bubble-menu/link-selector.tsx @@ -1,8 +1,8 @@ -import { cn } from "@/lib/utils"; +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/menus/bubble-menu/utils"; +import isValidHttpUrl from "./utils"; interface LinkSelectorProps { editor: Editor; diff --git a/packages/editor/core/src/ui/menus/bubble-menu/node-selector.tsx b/packages/editor/core/src/ui/menus/bubble-menu/node-selector.tsx index 99918450699..c3003be2314 100644 --- a/packages/editor/core/src/ui/menus/bubble-menu/node-selector.tsx +++ b/packages/editor/core/src/ui/menus/bubble-menu/node-selector.tsx @@ -1,4 +1,4 @@ -import { cn } from "@/lib/utils"; +import { cn } from "../../../lib/utils"; import { Editor } from "@tiptap/core"; import { Check, diff --git a/packages/editor/core/src/ui/menus/fixed-menu/index.tsx b/packages/editor/core/src/ui/menus/fixed-menu/index.tsx index 7d00b65e626..c9b8cfcb151 100644 --- a/packages/editor/core/src/ui/menus/fixed-menu/index.tsx +++ b/packages/editor/core/src/ui/menus/fixed-menu/index.tsx @@ -1,7 +1,7 @@ import { Editor } from "@tiptap/react"; import { BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, CodeIcon } from "lucide-react"; -import { cn } from "@/lib/utils"; +import { cn } from "../../../lib/utils"; import { Tooltip } from "../table-menu/tooltip"; import { Icon } from "./icon"; diff --git a/packages/editor/core/src/ui/menus/table-menu/index.tsx b/packages/editor/core/src/ui/menus/table-menu/index.tsx index 96a0af22854..fc84fd0698e 100644 --- a/packages/editor/core/src/ui/menus/table-menu/index.tsx +++ b/packages/editor/core/src/ui/menus/table-menu/index.tsx @@ -4,7 +4,7 @@ import InsertLeftTableIcon from "./InsertLeftTableIcon"; import InsertRightTableIcon from "./InsertRightTableIcon"; import InsertTopTableIcon from "./InsertTopTableIcon"; import InsertBottomTableIcon from "./InsertBottomTableIcon"; -import { cn, findTableAncestor } from "@/lib/utils"; +import { cn, findTableAncestor } from "../../../lib/utils"; import { Tooltip } from "./tooltip"; interface TableMenuItem { diff --git a/packages/editor/core/src/ui/plugins/delete-image.tsx b/packages/editor/core/src/ui/plugins/delete-image.tsx index 9204481a8dd..ba21d686d75 100644 --- a/packages/editor/core/src/ui/plugins/delete-image.tsx +++ b/packages/editor/core/src/ui/plugins/delete-image.tsx @@ -1,6 +1,6 @@ import { EditorState, Plugin, PluginKey, Transaction } from "@tiptap/pm/state"; import { Node as ProseMirrorNode } from "@tiptap/pm/model"; -import { DeleteImage } from "@/types/delete-image"; +import { DeleteImage } from "../../types/delete-image"; const deleteKey = new PluginKey("delete-image"); const IMAGE_NODE_TYPE = "image"; diff --git a/packages/editor/core/src/ui/plugins/upload-image.tsx b/packages/editor/core/src/ui/plugins/upload-image.tsx index 976c4968b43..cdd62ae4836 100644 --- a/packages/editor/core/src/ui/plugins/upload-image.tsx +++ b/packages/editor/core/src/ui/plugins/upload-image.tsx @@ -1,4 +1,4 @@ -import { UploadImage } from "@/types/upload-image"; +import { UploadImage } from "../../types/upload-image"; import { EditorState, Plugin, PluginKey } from "@tiptap/pm/state"; import { Decoration, DecorationSet, EditorView } from "@tiptap/pm/view"; diff --git a/packages/editor/core/src/ui/props.tsx b/packages/editor/core/src/ui/props.tsx index 7a43005e798..8f002b76c4c 100644 --- a/packages/editor/core/src/ui/props.tsx +++ b/packages/editor/core/src/ui/props.tsx @@ -1,7 +1,7 @@ import { EditorProps } from "@tiptap/pm/view"; -import { findTableAncestor } from "@/lib/utils"; -import { startImageUpload } from "@/ui/plugins/upload-image"; -import { UploadImage } from "@/types/upload-image"; +import { findTableAncestor } from "../lib/utils"; +import { startImageUpload } from "./plugins/upload-image"; +import { UploadImage } from "../types/upload-image"; export function CoreEditorProps( uploadFile: UploadImage, diff --git a/packages/editor/core/src/ui/read-only/extensions.tsx b/packages/editor/core/src/ui/read-only/extensions.tsx index f879b2744a3..e9fba4eab20 100644 --- a/packages/editor/core/src/ui/read-only/extensions.tsx +++ b/packages/editor/core/src/ui/read-only/extensions.tsx @@ -8,13 +8,13 @@ import TaskList from "@tiptap/extension-task-list"; import { Markdown } from "tiptap-markdown"; import Gapcursor from "@tiptap/extension-gapcursor"; -import { CustomTableCell } from "@/ui/extensions/table/table-cell"; -import { Table } from "@/ui/extensions/table"; -import { TableHeader } from "@/ui/extensions/table/table-header"; +import { CustomTableCell } from "../extensions/table/table-cell"; +import { Table } from "../extensions/table"; +import { TableHeader } from "../extensions/table/table-header"; import { TableRow } from "@tiptap/extension-table-row"; -import isValidHttpUrl from "@/ui/menus/bubble-menu/utils"; -import ReadOnlyImageExtension from "@/ui/extensions/image/read-only-image"; +import isValidHttpUrl from "../menus/bubble-menu/utils"; +import ReadOnlyImageExtension from "../extensions/image/read-only-image"; export const CoreReadOnlyEditorExtensions = [ StarterKit.configure({ diff --git a/packages/editor/core/tsconfig.json b/packages/editor/core/tsconfig.json index bf38514e1f7..b9964c0cad4 100644 --- a/packages/editor/core/tsconfig.json +++ b/packages/editor/core/tsconfig.json @@ -11,10 +11,5 @@ ], "compilerOptions": { "baseUrl": ".", - "paths": { - "@/*": [ - "src/*" - ] - } } } diff --git a/packages/editor/lite-text-editor/src/ui/extensions/index.tsx b/packages/editor/lite-text-editor/src/ui/extensions/index.tsx index e1ef3db84b8..cea0dfc6113 100644 --- a/packages/editor/lite-text-editor/src/ui/extensions/index.tsx +++ b/packages/editor/lite-text-editor/src/ui/extensions/index.tsx @@ -1,5 +1,5 @@ import { EnterKeyExtension } from "./enter-key-extension"; export const LiteTextEditorExtensions = () => [ - EnterKeyExtension + EnterKeyExtension, ]; diff --git a/packages/editor/rich-text-editor/src/ui/extensions/index.tsx b/packages/editor/rich-text-editor/src/ui/extensions/index.tsx index 69f89e2f164..e70fcc88d41 100644 --- a/packages/editor/rich-text-editor/src/ui/extensions/index.tsx +++ b/packages/editor/rich-text-editor/src/ui/extensions/index.tsx @@ -8,7 +8,7 @@ import ts from "highlight.js/lib/languages/typescript"; // import "highlight.js/styles/github-dark.css"; import SlashCommand from "./slash-command"; -import { UploadImage } from ".."; +import { UploadImage } from "../"; const lowlight = createLowlight(common) lowlight.register("ts", ts); From 0080880852a2d89ada2e4251cb5fc35d5108a295 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Tue, 3 Oct 2023 09:30:11 +0530 Subject: [PATCH 30/57] removed absolute imports from lite-text-editor --- packages/editor/lite-text-editor/src/index.ts | 4 ++-- .../editor/lite-text-editor/src/ui/extensions/index.tsx | 4 ++-- .../lite-text-editor/src/ui/menus/fixed-menu/index.tsx | 2 +- packages/editor/lite-text-editor/tsconfig.json | 7 +------ 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/packages/editor/lite-text-editor/src/index.ts b/packages/editor/lite-text-editor/src/index.ts index 0a276d1c049..de9323b3c5d 100644 --- a/packages/editor/lite-text-editor/src/index.ts +++ b/packages/editor/lite-text-editor/src/index.ts @@ -1,2 +1,2 @@ -export { LiteTextEditor, LiteTextEditorWithRef } from "@/ui"; -export { LiteReadOnlyEditor, LiteReadOnlyEditorWithRef } from "@/ui/read-only"; +export { LiteTextEditor, LiteTextEditorWithRef } from "./ui"; +export { LiteReadOnlyEditor, LiteReadOnlyEditorWithRef } from "./ui/read-only"; diff --git a/packages/editor/lite-text-editor/src/ui/extensions/index.tsx b/packages/editor/lite-text-editor/src/ui/extensions/index.tsx index cea0dfc6113..764188302e1 100644 --- a/packages/editor/lite-text-editor/src/ui/extensions/index.tsx +++ b/packages/editor/lite-text-editor/src/ui/extensions/index.tsx @@ -1,5 +1,5 @@ import { EnterKeyExtension } from "./enter-key-extension"; export const LiteTextEditorExtensions = () => [ - EnterKeyExtension, - ]; + EnterKeyExtension, +]; diff --git a/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx b/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx index cc32052381a..60bc0bbda47 100644 --- a/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx +++ b/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx @@ -3,7 +3,7 @@ import { BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, CodeIcon } from import { cn } from "@plane/editor-core"; import { Icon } from "./icon"; -import { Tooltip } from "@/ui/tooltip"; +import { Tooltip } from "../../tooltip"; export interface BubbleMenuItem { name: string; diff --git a/packages/editor/lite-text-editor/tsconfig.json b/packages/editor/lite-text-editor/tsconfig.json index bf38514e1f7..c230b89afa4 100644 --- a/packages/editor/lite-text-editor/tsconfig.json +++ b/packages/editor/lite-text-editor/tsconfig.json @@ -10,11 +10,6 @@ "node_modules" ], "compilerOptions": { - "baseUrl": ".", - "paths": { - "@/*": [ - "src/*" - ] - } + "baseUrl": "." } } From 95e5a306147ee7a0783455d200a799913a84ad4e Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Tue, 3 Oct 2023 09:32:16 +0530 Subject: [PATCH 31/57] removed absolute imports from rich-text-editor --- packages/editor/rich-text-editor/src/index.ts | 6 +++--- .../src/ui/menus/bubble-menu/link-selector.tsx | 2 +- packages/editor/rich-text-editor/tsconfig.json | 7 +------ 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/packages/editor/rich-text-editor/src/index.ts b/packages/editor/rich-text-editor/src/index.ts index dd8f35791a8..36d0a95f903 100644 --- a/packages/editor/rich-text-editor/src/index.ts +++ b/packages/editor/rich-text-editor/src/index.ts @@ -1,4 +1,4 @@ -import "@/styles/github-dark.css"; +import "./styles/github-dark.css"; -export { RichTextEditor, RichTextEditorWithRef } from "@/ui"; -export { RichReadOnlyEditor, RichReadOnlyEditorWithRef } from "@/ui/read-only"; +export { RichTextEditor, RichTextEditorWithRef } from "./ui"; +export { RichReadOnlyEditor, RichReadOnlyEditorWithRef } from "./ui/read-only"; diff --git a/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/link-selector.tsx b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/link-selector.tsx index cf347cf3b06..ba53608c54b 100644 --- a/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/link-selector.tsx +++ b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/link-selector.tsx @@ -1,7 +1,7 @@ import { Editor } from "@tiptap/core"; import { Check, Trash } from "lucide-react"; import { Dispatch, FC, SetStateAction, useCallback, useEffect, useRef } from "react"; -import isValidHttpUrl from "@/ui/menus/bubble-menu/utils"; +import isValidHttpUrl from "./utils"; import { cn } from "@plane/editor-core"; interface LinkSelectorProps { diff --git a/packages/editor/rich-text-editor/tsconfig.json b/packages/editor/rich-text-editor/tsconfig.json index f83a493ea84..c6fe47fe397 100644 --- a/packages/editor/rich-text-editor/tsconfig.json +++ b/packages/editor/rich-text-editor/tsconfig.json @@ -10,11 +10,6 @@ "node_modules" ], "compilerOptions": { - "baseUrl": ".", - "paths": { - "@/*": [ - "src/*" - ] - } + "baseUrl": "." } } From f408eb305588252e70b7ad202fc3ea1697723c07 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Tue, 3 Oct 2023 10:01:10 +0530 Subject: [PATCH 32/57] fixed dependencies in editor package --- packages/editor/core/package.json | 24 ++++++------------- packages/editor/lite-text-editor/package.json | 16 ++++++------- packages/editor/rich-text-editor/package.json | 11 +++++---- 3 files changed, 20 insertions(+), 31 deletions(-) diff --git a/packages/editor/core/package.json b/packages/editor/core/package.json index 9cf27203c27..78bf59db767 100644 --- a/packages/editor/core/package.json +++ b/packages/editor/core/package.json @@ -1,7 +1,7 @@ { "name": "@plane/editor-core", "version": "0.0.1", - "description": "Rich Text Editor that powers Plane", + "description": "Core Editor that powers Plane", "main": "./dist/index.mjs", "module": "./dist/index.mjs", "types": "./dist/index.d.mts", @@ -21,19 +21,17 @@ "check-types": "tsc --noEmit" }, "peerDependencies": { - "react": "^18.2.0" + "react": "^18.2.0", + "react-dom": "18.2.0", + "next": "12.3.2", + "next-themes": "^0.2.1" }, "dependencies": { "@blueprintjs/popover2": "^2.0.10", - "@radix-ui/react-slot": "^1.0.2", "@tiptap/core": "^2.1.7", - "@tiptap/extension-code-block-lowlight": "^2.0.4", "@tiptap/extension-color": "^2.1.11", - "@tiptap/extension-highlight": "^2.1.7", - "@tiptap/extension-horizontal-rule": "^2.1.7", "@tiptap/extension-image": "^2.1.7", "@tiptap/extension-link": "^2.1.7", - "@tiptap/extension-placeholder": "2.0.3", "@tiptap/extension-table": "^2.1.6", "@tiptap/extension-table-cell": "^2.1.6", "@tiptap/extension-table-header": "^2.1.6", @@ -45,21 +43,15 @@ "@tiptap/pm": "^2.1.7", "@tiptap/react": "^2.1.7", "@tiptap/starter-kit": "^2.1.10", - "@tiptap/suggestion": "^2.1.7", - "@types/node": "18.15.3", - "@types/react": "18.0.28", + "@types/react": "^18.2.5", "@types/react-dom": "18.0.11", + "@types/node": "18.15.3", "class-variance-authority": "^0.7.0", "clsx": "^1.2.1", "eslint": "8.36.0", "eslint-config-next": "13.2.4", "eventsource-parser": "^0.1.0", - "lowlight": "^2.9.0", "lucide-react": "^0.244.0", - "next": "12.3.2", - "next-themes": "^0.2.1", - "react": "18.2.0", - "react-dom": "18.2.0", "react-markdown": "^8.0.7", "tailwind-merge": "^1.14.0", "tippy.js": "^6.3.7", @@ -67,10 +59,8 @@ "use-debounce": "^9.0.4" }, "devDependencies": { - "@types/react": "^18.2.5", "eslint": "^7.32.0", "postcss": "^8.4.29", - "react": "^18.2.0", "tailwind-config-custom": "*", "tsconfig": "*", "tsup": "^7.2.0", diff --git a/packages/editor/lite-text-editor/package.json b/packages/editor/lite-text-editor/package.json index f2805da9912..1f0321e594a 100644 --- a/packages/editor/lite-text-editor/package.json +++ b/packages/editor/lite-text-editor/package.json @@ -1,7 +1,7 @@ { "name": "@plane/lite-text-editor", "version": "0.0.1", - "description": "Rich Text Editor that powers Plane", + "description": "Package that powers Plane's Comment Editor", "main": "./dist/index.mjs", "module": "./dist/index.mjs", "types": "./dist/index.d.mts", @@ -21,11 +21,14 @@ "check-types": "tsc --noEmit" }, "peerDependencies": { - "react": "^18.2.0" + "next": "12.3.2", + "next-themes": "^0.2.1", + "react": "^18.2.0", + "react-dom": "18.2.0" }, "dependencies": { + "@types/react": "^18.2.5", "@types/node": "18.15.3", - "@types/react": "18.0.28", "@types/react-dom": "18.0.11", "class-variance-authority": "^0.7.0", "clsx": "^1.2.1", @@ -34,10 +37,7 @@ "eventsource-parser": "^0.1.0", "lowlight": "^2.9.0", "lucide-react": "^0.244.0", - "next": "12.3.2", - "next-themes": "^0.2.1", - "react": "18.2.0", - "react-dom": "18.2.0", + "react-markdown": "^8.0.7", "tailwind-merge": "^1.14.0", "tippy.js": "^6.3.7", @@ -46,10 +46,8 @@ "@plane/editor-core": "*" }, "devDependencies": { - "@types/react": "^18.2.5", "eslint": "^7.32.0", "postcss": "^8.4.29", - "react": "^18.2.0", "tailwind-config-custom": "*", "tsconfig": "*", "tsup": "^7.2.0", diff --git a/packages/editor/rich-text-editor/package.json b/packages/editor/rich-text-editor/package.json index 2c7d4ff4f86..a5b2538f9f8 100644 --- a/packages/editor/rich-text-editor/package.json +++ b/packages/editor/rich-text-editor/package.json @@ -21,7 +21,10 @@ "check-types": "tsc --noEmit" }, "peerDependencies": { - "react": "^18.2.0" + "next": "12.3.2", + "next-themes": "^0.2.1", + "react": "^18.2.0", + "react-dom": "18.2.0" }, "dependencies": { "@plane/editor-core": "*", @@ -30,13 +33,11 @@ "@tiptap/extension-horizontal-rule": "^2.1.11", "@tiptap/extension-placeholder": "^2.1.11", "class-variance-authority": "^0.7.0", + "@tiptap/suggestion": "^2.1.7", "clsx": "^1.2.1", "highlight.js": "^11.8.0", "lowlight": "^3.0.0", - "lucide-react": "^0.244.0", - "next": "12.3.2", - "react": "18.2.0", - "react-dom": "18.2.0" + "lucide-react": "^0.244.0" }, "devDependencies": { "@types/node": "18.15.3", From fc8284d458101f97b99891477a8d869c0625a8ab Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Tue, 3 Oct 2023 19:26:48 +0530 Subject: [PATCH 33/57] fixed tailwind config for editor --- packages/editor/core/src/index.ts | 4 +-- packages/editor/core/tsconfig.json | 2 +- .../tailwind-config-custom/tailwind.config.js | 19 ++++++----- yarn.lock | 32 +------------------ 4 files changed, 15 insertions(+), 42 deletions(-) diff --git a/packages/editor/core/src/index.ts b/packages/editor/core/src/index.ts index 523c1cdff94..efab12eb180 100644 --- a/packages/editor/core/src/index.ts +++ b/packages/editor/core/src/index.ts @@ -1,6 +1,6 @@ // styles -import "./styles/tailwind.css"; -import "./styles/editor.css"; +// import "./styles/tailwind.css"; +// import "./styles/editor.css"; // utils export { cn } from "./lib/utils"; diff --git a/packages/editor/core/tsconfig.json b/packages/editor/core/tsconfig.json index b9964c0cad4..c230b89afa4 100644 --- a/packages/editor/core/tsconfig.json +++ b/packages/editor/core/tsconfig.json @@ -10,6 +10,6 @@ "node_modules" ], "compilerOptions": { - "baseUrl": ".", + "baseUrl": "." } } diff --git a/packages/tailwind-config-custom/tailwind.config.js b/packages/tailwind-config-custom/tailwind.config.js index b58baa284ba..dd2f9291b5a 100644 --- a/packages/tailwind-config-custom/tailwind.config.js +++ b/packages/tailwind-config-custom/tailwind.config.js @@ -3,14 +3,17 @@ const convertToRGB = (variableName) => `rgba(var(${variableName}))`; /** @type {import('tailwindcss').Config} */ module.exports = { darkMode: "class", - content: [ - "./components/**/*.tsx", - "./constants/**/*.{js,ts,jsx,tsx}", - "./layouts/**/*.tsx", - "./pages/**/*.tsx", - "./ui/**/*.tsx", - "../../packages/**/*.{js,ts,jsx,tsx}", - ], + content: { + relative: true, + files: [ + "./components/**/*.tsx", + "./constants/**/*.{js,ts,jsx,tsx}", + "./layouts/**/*.tsx", + "./pages/**/*.tsx", + "./ui/**/*.tsx", + "../packages/editor/**/*.{js,ts,jsx,tsx}" + ] + }, theme: { extend: { boxShadow: { diff --git a/yarn.lock b/yarn.lock index bfba25960d7..ba954f99493 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1892,13 +1892,6 @@ dependencies: "@babel/runtime" "^7.13.10" -"@radix-ui/react-compose-refs@1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.0.1.tgz#7ed868b66946aa6030e580b1ffca386dd4d21989" - integrity sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/react-context@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.0.0.tgz#f38e30c5859a9fb5e9aa9a9da452ee3ed9e0aee0" @@ -1997,14 +1990,6 @@ "@babel/runtime" "^7.13.10" "@radix-ui/react-compose-refs" "1.0.0" -"@radix-ui/react-slot@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.0.2.tgz#a9ff4423eade67f501ffb32ec22064bc9d3099ab" - integrity sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/react-compose-refs" "1.0.1" - "@radix-ui/react-use-callback-ref@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.0.0.tgz#9e7b8b6b4946fe3cbe8f748c82a2cce54e7b6a90" @@ -2382,11 +2367,6 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.1.10.tgz#e7d7fb578502da6c6208a4daa3e2fe4249ae6280" integrity sha512-e6aFr29OSOmXsjFZB2zt3p8aeCWOx0C9Ayrpdf4QBUCOUJtt6FQPxxiYc+XZcdrYbLGLznA7QJlulCK9SGv2Fw== -"@tiptap/extension-code-block-lowlight@^2.0.4": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.1.10.tgz#22dabaa8c087bd03c160590f7b8bf9b1501752b5" - integrity sha512-HBrsgDX1sMx6FSoKxAhz2On8lwL8S1lqNryMQBTE63PemjOxcyxPNdGWZz+JfQmxyvymQoGhibaW5ImNAK84Zg== - "@tiptap/extension-code-block-lowlight@^2.1.11": version "2.1.11" resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.1.11.tgz#6eec38c3b8662fae81ec2f117a2d18564f1fbb1a" @@ -2439,17 +2419,12 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.1.10.tgz#1b32726551466c29987861181966e5675417b28c" integrity sha512-1OgmrRPMcY52WI7I4799xd4eIsEX/bI813B8mZvNYXLzZI75pLW1hmz1mUvBYyMwlcek74zVTGYgPy11o+2JEg== -"@tiptap/extension-highlight@^2.1.7": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.1.10.tgz#8d94db01a2324e0ce380e6e7515fa0bc6004d9b9" - integrity sha512-HPD9T0MPEfrD40aSjcj23OcAYDnpsRLXxwQAYK1jw6Fvk7OtJZn8iaoAb4GcFfcKs3vgkpA9DC6DXlnvN0txYA== - "@tiptap/extension-history@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.1.10.tgz#efa60d657a76818361a3af14769660672d4bc227" integrity sha512-tApuN8MIJMzc0dxvkYJPt3t5cea9NuZBGNiuVedJwMMUF6hbFpMZAt20GW2qwjBaZ76rQwbLp1s3KnImFsPe5A== -"@tiptap/extension-horizontal-rule@^2.1.10", "@tiptap/extension-horizontal-rule@^2.1.7": +"@tiptap/extension-horizontal-rule@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.1.10.tgz#cfdb67530be100054fc8511942d4ec3534acf828" integrity sha512-91lGpK2d6WMPhrMDPBURS8z8pEg1CUBYy7GmBenKvvgh+JzVhG+U6MtykfWNfm2R4iRXOl1xLbyUOCiOSUXodQ== @@ -2491,11 +2466,6 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.1.10.tgz#ee1238d2d6e9460b2a929b05a5fd43cfb58a6017" integrity sha512-kzuHbrxcxpWkha5P+JFzCKT54pNqb4IBKMU5qT9YGhZSdNTtU63ncdCHM+Ad1ukLuvXAv95zh1IQC5j+Z1Qk4A== -"@tiptap/extension-placeholder@2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.0.3.tgz#69575353f09fc7524c9cdbfbf16c04f73c29d154" - integrity sha512-Z42jo0termRAf0S0L8oxrts94IWX5waU4isS2CUw8xCUigYyCFslkhQXkWATO1qRbjNFLKN2C9qvCgGf4UeBrw== - "@tiptap/extension-placeholder@^2.1.11": version "2.1.11" resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.1.11.tgz#ba115f714dd48d5bbc65df277b74f357ff3b100e" From ff29c1c87ef9fb0a39a0446bb1f2fb51ad4cb74e Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Tue, 3 Oct 2023 19:51:23 +0530 Subject: [PATCH 34/57] Enter key behaviour added for Comments --- .../src/ui/extensions/enter-key-extension.tsx | 6 ++++-- .../lite-text-editor/src/ui/extensions/index.tsx | 4 ++-- packages/editor/lite-text-editor/src/ui/index.tsx | 6 ++++-- .../issues/peek-overview/comment/add-comment.tsx | 9 +++++++-- .../peek-overview/comment/comment-detail-card.tsx | 13 ++++++------- web/components/issues/comment/add-comment.tsx | 1 + web/components/issues/comment/comment-card.tsx | 1 + 7 files changed, 25 insertions(+), 15 deletions(-) diff --git a/packages/editor/lite-text-editor/src/ui/extensions/enter-key-extension.tsx b/packages/editor/lite-text-editor/src/ui/extensions/enter-key-extension.tsx index 3d19703eced..04c4a1fbe92 100644 --- a/packages/editor/lite-text-editor/src/ui/extensions/enter-key-extension.tsx +++ b/packages/editor/lite-text-editor/src/ui/extensions/enter-key-extension.tsx @@ -1,12 +1,14 @@ import { Extension } from '@tiptap/core'; -export const EnterKeyExtension = Extension.create({ +export const EnterKeyExtension = (onEnterKeyPress?: () => void) => Extension.create({ name: 'enterKey', addKeyboardShortcuts() { return { 'Enter': () => { - console.log('Submit comment'); + if (onEnterKeyPress) { + onEnterKeyPress(); + } return true; }, } diff --git a/packages/editor/lite-text-editor/src/ui/extensions/index.tsx b/packages/editor/lite-text-editor/src/ui/extensions/index.tsx index 764188302e1..358f15294f6 100644 --- a/packages/editor/lite-text-editor/src/ui/extensions/index.tsx +++ b/packages/editor/lite-text-editor/src/ui/extensions/index.tsx @@ -1,5 +1,5 @@ import { EnterKeyExtension } from "./enter-key-extension"; -export const LiteTextEditorExtensions = () => [ - EnterKeyExtension, +export const LiteTextEditorExtensions = (onEnterKeyPress?: () => void) => [ + EnterKeyExtension(onEnterKeyPress), ]; diff --git a/packages/editor/lite-text-editor/src/ui/index.tsx b/packages/editor/lite-text-editor/src/ui/index.tsx index dfdee150541..34edaf87842 100644 --- a/packages/editor/lite-text-editor/src/ui/index.tsx +++ b/packages/editor/lite-text-editor/src/ui/index.tsx @@ -30,7 +30,8 @@ interface ILiteTextEditor { key: string; label: "Private" | "Public"; }[] - } + }; + onEnterKeyPress?: (e?: any) => void; } interface LiteTextEditorProps extends ILiteTextEditor { @@ -57,6 +58,7 @@ const LiteTextEditor = ({ customClassName, forwardedRef, commentAccessSpecifier, + onEnterKeyPress }: LiteTextEditorProps) => { const editor = useEditor({ onChange, @@ -68,7 +70,7 @@ const LiteTextEditor = ({ uploadFile, deleteFile, forwardedRef, - extensions: LiteTextEditorExtensions(), + extensions: LiteTextEditorExtensions(onEnterKeyPress), }); const editorClassNames = getEditorClassNames({ noBorder, borderOnFocus, customClassName }); diff --git a/space/components/issues/peek-overview/comment/add-comment.tsx b/space/components/issues/peek-overview/comment/add-comment.tsx index c06634fc6ad..c7852a47bb4 100644 --- a/space/components/issues/peek-overview/comment/add-comment.tsx +++ b/space/components/issues/peek-overview/comment/add-comment.tsx @@ -11,7 +11,7 @@ import { SecondaryButton } from "components/ui"; // types import { Comment } from "types/issue"; // components -import { RichTextEditorWithRef } from "@plane/rich-text-editor"; +import { LiteTextEditorWithRef } from "@plane/lite-text-editor"; // service import fileService from "@/services/file.service"; @@ -71,7 +71,12 @@ export const AddComment: React.FC = observer((props) => { name="comment_html" control={control} render={({ field: { value, onChange } }) => ( - { + userStore.requiredLogin(() => { + handleSubmit(onSubmit)(e); + }); + }} uploadFile={fileService.getUploadFileFunction(workspace_slug as string)} deleteFile={fileService.deleteImage} ref={editorRef} diff --git a/space/components/issues/peek-overview/comment/comment-detail-card.tsx b/space/components/issues/peek-overview/comment/comment-detail-card.tsx index cfd7ba49379..6857fca71bf 100644 --- a/space/components/issues/peek-overview/comment/comment-detail-card.tsx +++ b/space/components/issues/peek-overview/comment/comment-detail-card.tsx @@ -104,6 +104,7 @@ export const CommentCard: React.FC = observer((props) => { name="comment_html" render={({ field: { onChange, value } }) => ( = observer((props) => {

{}} + onClick={() => { }} className="relative grid place-items-center rounded p-1 text-custom-text-200 hover:text-custom-text-100 outline-none cursor-pointer hover:bg-custom-background-80" > @@ -173,9 +174,8 @@ export const CommentCard: React.FC = observer((props) => { onClick={() => { setIsEditing(true); }} - className={`w-full select-none truncate rounded px-1 py-1.5 text-left text-custom-text-200 hover:bg-custom-background-80 ${ - active ? "bg-custom-background-80" : "" - }`} + className={`w-full select-none truncate rounded px-1 py-1.5 text-left text-custom-text-200 hover:bg-custom-background-80 ${active ? "bg-custom-background-80" : "" + }`} > Edit @@ -188,9 +188,8 @@ export const CommentCard: React.FC = observer((props) => { diff --git a/web/components/issues/comment/add-comment.tsx b/web/components/issues/comment/add-comment.tsx index 4b0e92ba7e1..2fb3912d1eb 100644 --- a/web/components/issues/comment/add-comment.tsx +++ b/web/components/issues/comment/add-comment.tsx @@ -80,6 +80,7 @@ export const AddComment: React.FC = ({ control={control} render={({ field: { onChange: onCommentChange, value: commentValue } }) => ( = ({ >
Date: Tue, 3 Oct 2023 19:59:09 +0530 Subject: [PATCH 35/57] fixed modal form issue --- web/components/issues/form.tsx | 39 ++++++++++++++-------------------- 1 file changed, 16 insertions(+), 23 deletions(-) diff --git a/web/components/issues/form.tsx b/web/components/issues/form.tsx index 23ab8e7d331..881619d6517 100644 --- a/web/components/issues/form.tsx +++ b/web/components/issues/form.tsx @@ -379,30 +379,23 @@ export const IssueForm: FC = (props) => { { - if (!value && !watch("description_html")) return <>; - - return ( + render={({ field: { value, onChange } }) => ( { - onChange(description_html); - setValue("description", description); - }} - /> - ); - }} + uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)} + deleteFile={fileService.deleteImage} + ref={editorRef} + debouncedUpdatesEnabled={false} + value={!value || + value === "" || + (typeof value === "object" && Object.keys(value).length === 0) + ? watch("description_html") + : value} + customClassName="min-h-[150px]" + onChange={(description: Object, description_html: string) => { + onChange(description_html); + setValue("description", description); + } } /> + )} /> Date: Wed, 4 Oct 2023 01:06:16 +0530 Subject: [PATCH 36/57] added comment editor with fixed menu --- packages/editor/core/src/index.ts | 4 + .../editor/core/src/lib/editor-commands.ts | 36 ++++ .../core/src/ui/menus/fixed-menu/icon.tsx | 13 -- .../core/src/ui/menus/fixed-menu/index.tsx | 112 ------------ .../core/src/ui/menus/menu-items/index.tsx | 81 +++++++++ .../editor/lite-text-editor/src/ui/index.tsx | 2 +- .../src/ui/menus/fixed-menu/index.tsx | 163 ++++++++++++------ .../src/ui/extensions/slash-command.tsx | 1 + web/components/issues/description-form.tsx | 6 +- 9 files changed, 234 insertions(+), 184 deletions(-) create mode 100644 packages/editor/core/src/lib/editor-commands.ts delete mode 100644 packages/editor/core/src/ui/menus/fixed-menu/icon.tsx delete mode 100644 packages/editor/core/src/ui/menus/fixed-menu/index.tsx create mode 100644 packages/editor/core/src/ui/menus/menu-items/index.tsx diff --git a/packages/editor/core/src/index.ts b/packages/editor/core/src/index.ts index efab12eb180..bb381b3bcbb 100644 --- a/packages/editor/core/src/index.ts +++ b/packages/editor/core/src/index.ts @@ -14,3 +14,7 @@ export { EditorContentWrapper } from "./ui/components/editor-content"; // hooks export { useEditor } from "./ui/hooks/useEditor"; export { useReadOnlyEditor } from "./ui/hooks/useReadOnlyEditor"; + +// helper items +export * from "./ui/menus/menu-items"; +export * from "./lib/editor-commands"; diff --git a/packages/editor/core/src/lib/editor-commands.ts b/packages/editor/core/src/lib/editor-commands.ts new file mode 100644 index 00000000000..481160b9069 --- /dev/null +++ b/packages/editor/core/src/lib/editor-commands.ts @@ -0,0 +1,36 @@ +import { Editor } from "@tiptap/react"; +import { UploadImage } from "../types/upload-image"; +import { startImageUpload } from "../ui/plugins/upload-image"; + +export const toggleBold = (editor: Editor) => editor?.chain().focus().toggleBold().run(); + +export const toggleItalic = (editor: Editor) => editor?.chain().focus().toggleItalic().run(); + +export const toggleUnderline = (editor: Editor) => editor?.chain().focus().toggleUnderline().run(); + +export const toggleStrike = (editor: Editor) => editor?.chain().focus().toggleStrike().run(); + +export const toggleCode = (editor: Editor) => editor?.chain().focus().toggleCode().run(); + +export const toggleBulletList = (editor: Editor) => editor?.chain().focus().toggleBulletList().run(); + +export const toggleOrderedList = (editor: Editor) => editor?.chain().focus().toggleOrderedList().run(); + +export const toggleBlockquote = (editor: Editor) => editor?.chain().focus().toggleBlockquote().run(); + +export const insertTable = (editor: Editor) => editor?.chain().focus().insertTable().run(); + +export const insertImage = (editor: Editor, uploadFile: UploadImage, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void) => { + 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, uploadFile, setIsSubmitting); + } + }; + input.click(); +}; + diff --git a/packages/editor/core/src/ui/menus/fixed-menu/icon.tsx b/packages/editor/core/src/ui/menus/fixed-menu/icon.tsx deleted file mode 100644 index c0006b3f257..00000000000 --- a/packages/editor/core/src/ui/menus/fixed-menu/icon.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import React from "react"; - -type Props = { - iconName: string; - className?: string; -}; - -export const Icon: React.FC = ({ iconName, className = "" }) => ( - - {iconName} - -); - diff --git a/packages/editor/core/src/ui/menus/fixed-menu/index.tsx b/packages/editor/core/src/ui/menus/fixed-menu/index.tsx deleted file mode 100644 index c9b8cfcb151..00000000000 --- a/packages/editor/core/src/ui/menus/fixed-menu/index.tsx +++ /dev/null @@ -1,112 +0,0 @@ -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; - isActive: () => boolean; - command: () => void; - icon: typeof BoldIcon; -} - -type EditorBubbleMenuProps = { - editor: Editor; - accessValue: string; - onAccessChange: (accessKey: string) => void; - commentAccess: { - icon: string; - key: string; - label: "Private" | "Public"; - }[] | undefined; -} - -export const FixedMenu = (props: EditorBubbleMenuProps) => { - 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 handleAccessChange = (accessKey: string) => { - props.onAccessChange(accessKey); - }; - - - return ( -
-
-
- {props?.commentAccess?.map((access) => ( - - - - ))} -
- {items.map((item, index) => ( - - ))} -
-
- ); -}; diff --git a/packages/editor/core/src/ui/menus/menu-items/index.tsx b/packages/editor/core/src/ui/menus/menu-items/index.tsx new file mode 100644 index 00000000000..581404b52e4 --- /dev/null +++ b/packages/editor/core/src/ui/menus/menu-items/index.tsx @@ -0,0 +1,81 @@ +import { BoldIcon, QuoteIcon, ImageIcon, TableIcon, ListIcon, ListOrderedIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, CodeIcon } from "lucide-react"; +import { Editor } from "@tiptap/react"; +import { UploadImage } from "../../../types/upload-image"; +import { insertImage, insertTable, toggleBlockquote, toggleBold, toggleBulletList, toggleCode, toggleItalic, toggleOrderedList, toggleStrike } from "../../../lib/editor-commands"; + +export interface EditorMenuItem { + name: string; + isActive: () => boolean; + command: () => void; + icon: typeof BoldIcon; +} + +export const BoldItem = (editor: Editor): EditorMenuItem => ({ + name: "bold", + isActive: () => editor?.isActive("bold"), + command: () => toggleBold(editor), + icon: BoldIcon, +}) + +export const ItalicItem = (editor: Editor): EditorMenuItem => ({ + name: "italic", + isActive: () => editor?.isActive("italic"), + command: () => toggleItalic(editor), + icon: ItalicIcon, +}) + +export const UnderLineItem = (editor: Editor): EditorMenuItem => ({ + name: "underline", + isActive: () => editor?.isActive("underline"), + command: () => UnderLineItem(editor), + icon: UnderlineIcon, +}) + +export const StrikeThroughItem = (editor: Editor): EditorMenuItem => ({ + name: "strike", + isActive: () => editor?.isActive("strike"), + command: () => toggleStrike(editor), + icon: StrikethroughIcon, +}) + +export const CodeItem = (editor: Editor): EditorMenuItem => ({ + name: "code", + isActive: () => editor?.isActive("code"), + command: () => toggleCode(editor), + icon: CodeIcon, +}) + +export const BulletListItem = (editor: Editor): EditorMenuItem => ({ + name: "bullet-list", + isActive: () => editor?.isActive("bulletList"), + command: () => toggleBulletList(editor), + icon: ListIcon, +}) + +export const NumberedListItem = (editor: Editor): EditorMenuItem => ({ + name: "ordered-list", + isActive: () => editor?.isActive("orderedList"), + command: () => toggleOrderedList(editor), + icon: ListOrderedIcon +}) + +export const QuoteItem = (editor: Editor): EditorMenuItem => ({ + name: "quote", + isActive: () => editor?.isActive("quote"), + command: () => toggleBlockquote(editor), + icon: QuoteIcon +}) + +export const TableItem = (editor: Editor): EditorMenuItem => ({ + name: "quote", + isActive: () => editor?.isActive("table"), + command: () => insertTable(editor), + icon: TableIcon +}) + +export const ImageItem = (editor: Editor, uploadFile: UploadImage, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void): EditorMenuItem => ({ + name: "image", + isActive: () => editor?.isActive("image"), + command: () => insertImage(editor, uploadFile, setIsSubmitting), + icon: ImageIcon, +}) diff --git a/packages/editor/lite-text-editor/src/ui/index.tsx b/packages/editor/lite-text-editor/src/ui/index.tsx index 34edaf87842..0b938672476 100644 --- a/packages/editor/lite-text-editor/src/ui/index.tsx +++ b/packages/editor/lite-text-editor/src/ui/index.tsx @@ -83,7 +83,7 @@ const LiteTextEditor = ({ {(editable !== false) && (
- +
) }
diff --git a/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx b/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx index 60bc0bbda47..1a60683648c 100644 --- a/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx +++ b/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx @@ -1,9 +1,10 @@ import { Editor } from "@tiptap/react"; -import { BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, CodeIcon } from "lucide-react"; +import { BoldIcon } from "lucide-react"; -import { cn } from "@plane/editor-core"; +import { BoldItem, BulletListItem, cn, CodeItem, ImageItem, ItalicItem, NumberedListItem, QuoteItem, StrikeThroughItem, TableItem, UnderLineItem } from "@plane/editor-core"; import { Icon } from "./icon"; import { Tooltip } from "../../tooltip"; +import { UploadImage } from "../.."; export interface BubbleMenuItem { name: string; @@ -24,40 +25,31 @@ type EditorBubbleMenuProps = { label: "Private" | "Public"; }[] | undefined; } + uploadFile: UploadImage; + setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void; } export const FixedMenu = (props: EditorBubbleMenuProps) => { - 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 basicMarkItems: BubbleMenuItem[] = [ + BoldItem(props.editor), + ItalicItem(props.editor), + UnderLineItem(props.editor), + StrikeThroughItem(props.editor), + ]; + + const listItems: BubbleMenuItem[] = [ + BulletListItem(props.editor), + NumberedListItem(props.editor), + ]; + + const userActionItems: BubbleMenuItem[] = [ + QuoteItem(props.editor), + CodeItem(props.editor), + ]; + + const complexItems: BubbleMenuItem[] = [ + TableItem(props.editor), + ImageItem(props.editor, props.uploadFile, props.setIsSubmitting), ]; const handleAccessChange = (accessKey: string) => { @@ -69,28 +61,91 @@ export const FixedMenu = (props: EditorBubbleMenuProps) => {
-
- {props.commentAccessSpecifier && (
- {props?.commentAccessSpecifier.commentAccess?.map((access) => ( - - - - ))} -
)} - {items.map((item, index) => ( + /> + + + ))} +
)} +
+ {basicMarkItems.map((item, index) => ( + + ))} +
+
+ {listItems.map((item, index) => ( + + ))} +
+
+ {userActionItems.map((item, index) => ( + + ))} +
+
+ {complexItems.map((item, index) => (
, command: ({ editor, range }: CommandProps) => { - editor - .chain() - .focus() - .deleteRange(range) - .insertTable({ rows: 3, cols: 3, withHeaderRow: true }) - .run(); + insertTableCommand(editor, range); + // editor + // .chain() + // .focus() + // .deleteRange(range) + // .insertTable({ rows: 3, cols: 3, withHeaderRow: true }) + // .run(); }, }, { From 2fd9198fcf1559072443985d01d0c4226b9c63f1 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Wed, 4 Oct 2023 01:37:49 +0530 Subject: [PATCH 38/57] modified turbo config for build pipeline of space and web projects --- space/package.json | 3 ++- turbo.json | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/space/package.json b/space/package.json index 5f9c376185c..da1dfac8b6e 100644 --- a/space/package.json +++ b/space/package.json @@ -3,7 +3,8 @@ "version": "0.0.1", "private": true, "scripts": { - "dev": "next dev -p 4000", + "dev": "turbo run develop", + "develop": "next dev -p 4000", "build": "next build", "start": "next start -p 4000", "lint": "next lint" diff --git a/turbo.json b/turbo.json index 40f67bc05f2..2661f48e7e3 100644 --- a/turbo.json +++ b/turbo.json @@ -43,6 +43,41 @@ "web#develop": { "cache": false, "persistent": true, + "dependsOn": [ + "@plane/lite-text-editor#build", + "@plane/rich-text-editor#build" + ] + }, + "space#develop": { + "cache": false, + "persistent": true, + "dependsOn": [ + "@plane/lite-text-editor#build", + "@plane/rich-text-editor#build" + ] + }, + "web#build": { + "cache": true, + "dependsOn": [ + "@plane/lite-text-editor#build", + "@plane/rich-text-editor#build" + ] + }, + "space#build": { + "cache": true, + "dependsOn": [ + "@plane/lite-text-editor#build", + "@plane/rich-text-editor#build" + ] + }, + "@plane/lite-text-editor#build": { + "cache": true, + "dependsOn": [ + "@plane/editor-core#build" + ] + }, + "@plane/rich-text-editor#build": { + "cache": true, "dependsOn": [ "@plane/editor-core#build" ] From 696a2e92517089eb61ffbe9e05c8bf96321da075 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Wed, 4 Oct 2023 15:28:55 +0530 Subject: [PATCH 39/57] fixed shift enter behavior for lists --- .../core/src/ui/components/editor-content.tsx | 1 + packages/editor/lite-text-editor/package.json | 8 ++-- .../ui/extensions/custom-list-extension.tsx | 9 +++++ .../src/ui/extensions/index.tsx | 2 + yarn.lock | 39 ++++++++++++++++--- 5 files changed, 49 insertions(+), 10 deletions(-) create mode 100644 packages/editor/lite-text-editor/src/ui/extensions/custom-list-extension.tsx diff --git a/packages/editor/core/src/ui/components/editor-content.tsx b/packages/editor/core/src/ui/components/editor-content.tsx index 5ca07765767..0675a583437 100644 --- a/packages/editor/core/src/ui/components/editor-content.tsx +++ b/packages/editor/core/src/ui/components/editor-content.tsx @@ -11,6 +11,7 @@ interface EditorContentProps { export const EditorContentWrapper = ({ editor, editorContentCustomClassNames = '', children }: EditorContentProps) => (
+ {/* @ts-ignore */} {editor?.isActive("image") && } diff --git a/packages/editor/lite-text-editor/package.json b/packages/editor/lite-text-editor/package.json index 1f0321e594a..47ef154c69e 100644 --- a/packages/editor/lite-text-editor/package.json +++ b/packages/editor/lite-text-editor/package.json @@ -27,8 +27,10 @@ "react-dom": "18.2.0" }, "dependencies": { - "@types/react": "^18.2.5", + "@plane/editor-core": "*", + "@tiptap/extension-list-item": "^2.1.11", "@types/node": "18.15.3", + "@types/react": "^18.2.5", "@types/react-dom": "18.0.11", "class-variance-authority": "^0.7.0", "clsx": "^1.2.1", @@ -37,13 +39,11 @@ "eventsource-parser": "^0.1.0", "lowlight": "^2.9.0", "lucide-react": "^0.244.0", - "react-markdown": "^8.0.7", "tailwind-merge": "^1.14.0", "tippy.js": "^6.3.7", "tiptap-markdown": "^0.8.2", - "use-debounce": "^9.0.4", - "@plane/editor-core": "*" + "use-debounce": "^9.0.4" }, "devDependencies": { "eslint": "^7.32.0", diff --git a/packages/editor/lite-text-editor/src/ui/extensions/custom-list-extension.tsx b/packages/editor/lite-text-editor/src/ui/extensions/custom-list-extension.tsx new file mode 100644 index 00000000000..f0bc70cffd2 --- /dev/null +++ b/packages/editor/lite-text-editor/src/ui/extensions/custom-list-extension.tsx @@ -0,0 +1,9 @@ +import ListItem from '@tiptap/extension-list-item' + +export const CustomListItem = ListItem.extend({ + addKeyboardShortcuts() { + return { + 'Shift-Enter': () => this.editor.chain().focus().splitListItem('listItem').run(), + } + }, +}) diff --git a/packages/editor/lite-text-editor/src/ui/extensions/index.tsx b/packages/editor/lite-text-editor/src/ui/extensions/index.tsx index 358f15294f6..ccd04a395f9 100644 --- a/packages/editor/lite-text-editor/src/ui/extensions/index.tsx +++ b/packages/editor/lite-text-editor/src/ui/extensions/index.tsx @@ -1,5 +1,7 @@ +import { CustomListItem } from "./custom-list-extension"; import { EnterKeyExtension } from "./enter-key-extension"; export const LiteTextEditorExtensions = (onEnterKeyPress?: () => void) => [ + CustomListItem, EnterKeyExtension(onEnterKeyPress), ]; diff --git a/yarn.lock b/yarn.lock index ba954f99493..e3095db2c7e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2340,11 +2340,6 @@ resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.1.10.tgz#6d8f3c777f1700dcc6c903b1185576754175e366" integrity sha512-yhUKsac6nlqbPQfwQnp+4Jb110EqmzocXKoZacLwzHpM7JVsr2+LXMDu9kahtrvHNJErJljhnQvDHRsrrYeJkQ== -"@tiptap/core@^2.1.11": - version "2.1.11" - resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.1.11.tgz#06bbd189c6b2dffe58b1c80f848737d76fb012bd" - integrity sha512-1W2DdjpPwfphHgQ3Qm4s5wzCnEjiXm1TeZ+6/zBl89yKURXgv8Mw1JGdj/NcImQjtDcsNn97MscACK3GKbEJBA== - "@tiptap/extension-blockquote@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.1.10.tgz#dc475bef70dd460fc730a14b3b4cc18f37cd1b2d" @@ -2456,6 +2451,11 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.1.10.tgz#0615e4fb68161e6457e6041e195f454bfd537d44" integrity sha512-rRRyB14vOcSjTMAh8Y+50TRC/jO469CelGwFjOLrK1ZSEag5wmLDaqpWOOb52BFYnvCHuIm1HqZtdL5bTI/J1w== +"@tiptap/extension-list-item@^2.1.11": + version "2.1.11" + resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.1.11.tgz#466e4d1dcad153b4e52678b08d2bf073339c2dc9" + integrity sha512-YhwHaPGhffsFsg/zjCu1G24//j/BTRDRZbZXmMwp77m1yEqPULcWyoWrI+gUzetQxJRD/ruAucqjLtoLLfICmQ== + "@tiptap/extension-ordered-list@^2.1.10": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.1.10.tgz#ef5d5ba68baf86e9b66c1b2c1cec458aa111ad44" @@ -2805,7 +2805,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@18.0.15", "@types/react@18.0.28", "@types/react@18.2.0", "@types/react@^18.0.17", "@types/react@^18.2.5": +"@types/react@*", "@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== @@ -2814,6 +2814,33 @@ "@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/react@^18.2.5": + version "18.2.24" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.24.tgz#3c7d68c02e0205a472f04abe4a0c1df35d995c05" + integrity sha512-Ee0Jt4sbJxMu1iDcetZEIKQr99J1Zfb6D4F3qfUWoR1JpInkY1Wdg4WwCyBjL257D0+jGqSl1twBjV8iCaC0Aw== + 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" From a9d197cda7eb1b135df05aa8f38c687709ea9cdd Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Wed, 4 Oct 2023 21:47:42 +0530 Subject: [PATCH 40/57] removed extra margin from access specifiers --- .../editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx b/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx index 1a60683648c..72a537e7e37 100644 --- a/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx +++ b/packages/editor/lite-text-editor/src/ui/menus/fixed-menu/index.tsx @@ -72,7 +72,7 @@ export const FixedMenu = (props: EditorBubbleMenuProps) => { > Date: Wed, 4 Oct 2023 21:51:18 +0530 Subject: [PATCH 41/57] removed tiptap instance from web --- web/components/tiptap/index.tsx | 110 -------------------------------- 1 file changed, 110 deletions(-) delete mode 100644 web/components/tiptap/index.tsx diff --git a/web/components/tiptap/index.tsx b/web/components/tiptap/index.tsx deleted file mode 100644 index 44076234e60..00000000000 --- a/web/components/tiptap/index.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import { useImperativeHandle, useRef, forwardRef, useEffect } from "react"; -import { useEditor, EditorContent, Editor } from "@tiptap/react"; -import { useDebouncedCallback } from "use-debounce"; -// components -import { EditorBubbleMenu } from "./bubble-menu"; -import { TiptapExtensions } from "./extensions"; -import { TiptapEditorProps } from "./props"; -import { ImageResizer } from "./extensions/image-resize"; -import { TableMenu } from "./table-menu"; - -export interface ITipTapRichTextEditor { - value: string; - noBorder?: boolean; - borderOnFocus?: boolean; - customClassName?: string; - editorContentCustomClassNames?: string; - onChange?: (json: any, html: string) => void; - setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void; - setShouldShowAlert?: (showAlert: boolean) => void; - workspaceSlug: string; - editable?: boolean; - forwardedRef?: any; - debouncedUpdatesEnabled?: boolean; -} - -const Tiptap = (props: ITipTapRichTextEditor) => { - const { - onChange, - debouncedUpdatesEnabled, - forwardedRef, - editable, - setIsSubmitting, - setShouldShowAlert, - editorContentCustomClassNames, - value, - noBorder, - workspaceSlug, - borderOnFocus, - customClassName, - } = props; - - const editor = useEditor({ - editable: editable ?? true, - editorProps: TiptapEditorProps(workspaceSlug, setIsSubmitting), - extensions: TiptapExtensions(workspaceSlug, setIsSubmitting), - content: value, - onUpdate: async ({ editor }) => { - // for instant feedback loop - setIsSubmitting?.("submitting"); - setShouldShowAlert?.(true); - if (debouncedUpdatesEnabled) { - debouncedUpdates({ onChange, editor }); - } else { - onChange?.(editor.getJSON(), editor.getHTML()); - } - }, - }); - - const editorRef: React.MutableRefObject = useRef(null); - - useImperativeHandle(forwardedRef, () => ({ - clearEditor: () => { - editorRef.current?.commands.clearContent(); - }, - setEditorValue: (content: string) => { - editorRef.current?.commands.setContent(content); - }, - })); - - const debouncedUpdates = useDebouncedCallback(async ({ onChange, editor }) => { - setTimeout(async () => { - if (onChange) { - onChange(editor.getJSON(), editor.getHTML()); - } - }, 500); - }, 1000); - - const editorClassNames = `relative w-full max-w-full sm:rounded-lg mt-2 p-3 relative focus:outline-none rounded-md - ${noBorder ? "" : "border border-custom-border-200"} ${ - borderOnFocus ? "focus:border border-custom-border-300" : "focus:border-0" - } ${customClassName}`; - - if (!editor) return null; - editorRef.current = editor; - - return ( -
{ - editor?.chain().focus().run(); - }} - className={`tiptap-editor-container relative cursor-text ${editorClassNames}`} - > - {editor && } -
- - - {editor?.isActive("image") && } -
-
- ); -}; - -const TipTapEditor = forwardRef((props, ref) => ( - -)); - -TipTapEditor.displayName = "TipTapEditor"; - -export { TipTapEditor }; From cfadb5a79393f2287b61a1f29fa6d4b5b319fffb Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Wed, 4 Oct 2023 23:06:08 +0530 Subject: [PATCH 42/57] fixed bugs returning empty editor boxes --- web/components/issues/description-form.tsx | 43 ++++++--------- web/components/issues/draft-issue-form.tsx | 39 ++++++-------- .../web-view/issue-web-view-form.tsx | 54 ++++++++----------- 3 files changed, 55 insertions(+), 81 deletions(-) diff --git a/web/components/issues/description-form.tsx b/web/components/issues/description-form.tsx index 5050309452a..8596d5fe8a9 100644 --- a/web/components/issues/description-form.tsx +++ b/web/components/issues/description-form.tsx @@ -128,33 +128,24 @@ export const IssueDescriptionForm: FC = ({ { - if (!value) return <>; - - return ( + render={({ field: { value, onChange } }) => ( { - setShowAlert(true); - setIsSubmitting("submitting"); - onChange(description_html); - handleSubmit(handleDescriptionFormSubmit)().finally(() => - setIsSubmitting("submitted") - ); - }} - editable={isAllowed} - /> - ); - }} + uploadFile={fileService.getUploadFileFunction(workspaceSlug)} + deleteFile={fileService.deleteImage} + value={value} + debouncedUpdatesEnabled={true} + setShouldShowAlert={setShowAlert} + setIsSubmitting={setIsSubmitting} + customClassName={isAllowed ? "min-h-[150px] shadow-sm" : "!p-0 !pt-2 text-custom-text-200"} + noBorder={!isAllowed} + onChange={(description: Object, description_html: string) => { + setShowAlert(true); + setIsSubmitting("submitting"); + onChange(description_html); + handleSubmit(handleDescriptionFormSubmit)().finally(() => setIsSubmitting("submitted") + ); + } } /> + )} />
= (props) => { { - if (!value && !watch("description_html")) return <>; - - return ( + render={({ field: { value, onChange } }) => ( { - onChange(description_html); - setValue("description", description); - }} - /> - ); - }} + uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)} + deleteFile={fileService.deleteImage} + ref={editorRef} + debouncedUpdatesEnabled={false} + value={!value || + value === "" || + (typeof value === "object" && Object.keys(value).length === 0) + ? watch("description_html") + : value} + customClassName="min-h-[150px]" + onChange={(description: Object, description_html: string) => { + onChange(description_html); + setValue("description", description); + } } /> + )} /> = (props) => { { - if (!value) return <>; - - return ( + render={({ field: { value, onChange } }) => (

" - : value - } - debouncedUpdatesEnabled={true} - setShouldShowAlert={setShowAlert} - setIsSubmitting={setIsSubmitting} - customClassName={ - isAllowed ? "min-h-[150px] shadow-sm" : "!p-0 !pt-2 text-custom-text-200" - } - noBorder={!isAllowed} - onChange={(description: Object, description_html: string) => { - setShowAlert(true); - setIsSubmitting("submitting"); - onChange(description_html); - handleSubmit(handleDescriptionFormSubmit)().finally(() => - setIsSubmitting("submitted") - ); - }} - editable={isAllowed} - /> - ); - }} + uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)} + deleteFile={fileService.deleteImage} + value={!value || + value === "" || + (typeof value === "object" && Object.keys(value).length === 0) + ? "

" + : value} + debouncedUpdatesEnabled={true} + setShouldShowAlert={setShowAlert} + setIsSubmitting={setIsSubmitting} + customClassName={isAllowed ? "min-h-[150px] shadow-sm" : "!p-0 !pt-2 text-custom-text-200"} + noBorder={!isAllowed} + onChange={(description: Object, description_html: string) => { + setShowAlert(true); + setIsSubmitting("submitting"); + onChange(description_html); + handleSubmit(handleDescriptionFormSubmit)().finally(() => setIsSubmitting("submitted") + ); + } } + editable={isAllowed} /> + )} />
Date: Thu, 5 Oct 2023 10:32:24 +0530 Subject: [PATCH 43/57] fixed toggle Underline behvaiour --- packages/editor/core/src/ui/menus/menu-items/index.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/editor/core/src/ui/menus/menu-items/index.tsx b/packages/editor/core/src/ui/menus/menu-items/index.tsx index 2b84a21039a..dfef77e59dc 100644 --- a/packages/editor/core/src/ui/menus/menu-items/index.tsx +++ b/packages/editor/core/src/ui/menus/menu-items/index.tsx @@ -1,7 +1,7 @@ import { BoldIcon, QuoteIcon, ImageIcon, TableIcon, ListIcon, ListOrderedIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, CodeIcon } from "lucide-react"; import { Editor } from "@tiptap/react"; import { UploadImage } from "../../../types/upload-image"; -import { insertImageCommand, insertTableCommand, toggleBlockquote, toggleBold, toggleBulletList, toggleCode, toggleItalic, toggleOrderedList, toggleStrike, } from "../../../lib/editor-commands"; +import { insertImageCommand, insertTableCommand, toggleBlockquote, toggleBold, toggleBulletList, toggleCode, toggleItalic, toggleOrderedList, toggleStrike, toggleUnderline, } from "../../../lib/editor-commands"; export interface EditorMenuItem { name: string; @@ -27,7 +27,7 @@ export const ItalicItem = (editor: Editor): EditorMenuItem => ({ export const UnderLineItem = (editor: Editor): EditorMenuItem => ({ name: "underline", isActive: () => editor?.isActive("underline"), - command: () => UnderLineItem(editor), + command: () => toggleUnderline(editor), icon: UnderlineIcon, }) From 6cb9f730069ed5cd57cee2e6a818a16a1d6dca58 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Mon, 9 Oct 2023 17:19:02 +0530 Subject: [PATCH 44/57] updated bubble menu to use core package's utilities --- .../core/src/ui/menus/bubble-menu/index.tsx | 121 ---------------- .../ui/menus/bubble-menu/link-selector.tsx | 93 ------------- .../ui/menus/bubble-menu/node-selector.tsx | 130 ------------------ .../src/ui/menus/bubble-menu/utils/index.tsx | 11 -- .../src/ui/menus/bubble-menu/index.tsx | 39 +----- 5 files changed, 7 insertions(+), 387 deletions(-) delete mode 100644 packages/editor/core/src/ui/menus/bubble-menu/index.tsx delete mode 100644 packages/editor/core/src/ui/menus/bubble-menu/link-selector.tsx delete mode 100644 packages/editor/core/src/ui/menus/bubble-menu/node-selector.tsx delete mode 100644 packages/editor/core/src/ui/menus/bubble-menu/utils/index.tsx diff --git a/packages/editor/core/src/ui/menus/bubble-menu/index.tsx b/packages/editor/core/src/ui/menus/bubble-menu/index.tsx deleted file mode 100644 index 686cd919437..00000000000 --- a/packages/editor/core/src/ui/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/core/src/ui/menus/bubble-menu/link-selector.tsx b/packages/editor/core/src/ui/menus/bubble-menu/link-selector.tsx deleted file mode 100644 index 7060ff9d8e6..00000000000 --- a/packages/editor/core/src/ui/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 "./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/core/src/ui/menus/bubble-menu/node-selector.tsx b/packages/editor/core/src/ui/menus/bubble-menu/node-selector.tsx deleted file mode 100644 index c3003be2314..00000000000 --- a/packages/editor/core/src/ui/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/core/src/ui/menus/bubble-menu/utils/index.tsx b/packages/editor/core/src/ui/menus/bubble-menu/utils/index.tsx deleted file mode 100644 index b5add3f544e..00000000000 --- a/packages/editor/core/src/ui/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/rich-text-editor/src/ui/menus/bubble-menu/index.tsx b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/index.tsx index b9ce6159d72..14fd73a8338 100644 --- a/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/index.tsx +++ b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/index.tsx @@ -1,10 +1,10 @@ import { BubbleMenu, BubbleMenuProps } from "@tiptap/react"; import { FC, useState } from "react"; -import { BoldIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, CodeIcon } from "lucide-react"; +import { BoldIcon } from "lucide-react"; import { NodeSelector } from "./node-selector"; import { LinkSelector } from "./link-selector"; -import { cn } from "@plane/editor-core"; +import { BoldItem, cn, CodeItem, ItalicItem, StrikeThroughItem, UnderLineItem } from "@plane/editor-core"; export interface BubbleMenuItem { name: string; @@ -17,36 +17,11 @@ 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, - }, + BoldItem(props.editor), + ItalicItem(props.editor), + UnderLineItem(props.editor), + StrikeThroughItem(props.editor), + CodeItem(props.editor), ]; const bubbleMenuProps: EditorBubbleMenuProps = { From 8552ef24a60271958d7021a501ba98a050462f8a Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Mon, 9 Oct 2023 17:56:35 +0530 Subject: [PATCH 45/57] added editor/core readme and fixed imports --- packages/editor/core/Readme.md | 12 ++++ packages/editor/core/src/index.ts | 3 +- packages/editor/core/src/lib/utils.ts | 14 ++++- .../editor/core/src/ui/extensions/index.tsx | 2 +- .../core/src/ui/read-only/extensions.tsx | 2 +- packages/editor/lite-text-editor/Readme.md | 55 +++++++++++++++++++ packages/editor/rich-text-editor/Readme.md | 54 ++++++++++++++++++ .../ui/menus/bubble-menu/link-selector.tsx | 3 +- .../src/ui/menus/bubble-menu/utils/index.tsx | 11 ---- 9 files changed, 138 insertions(+), 18 deletions(-) create mode 100644 packages/editor/core/Readme.md create mode 100644 packages/editor/lite-text-editor/Readme.md create mode 100644 packages/editor/rich-text-editor/Readme.md delete mode 100644 packages/editor/rich-text-editor/src/ui/menus/bubble-menu/utils/index.tsx diff --git a/packages/editor/core/Readme.md b/packages/editor/core/Readme.md new file mode 100644 index 00000000000..fd82856f726 --- /dev/null +++ b/packages/editor/core/Readme.md @@ -0,0 +1,12 @@ +# README for @plane/editor-core + +## Description + +The `@plane/editor-core` package serves as the foundation for our editor system. It provides the base functionality for our other editor packages, but it will not be used directly in any of the projects. + +## Key Features + +- **Extensive Utilities**: We provide a wide range of utilities for extending the core itself. These include merging classes, adding new extensions, custom props, menu items, and their commands. This allows for extensive customization and flexibility in the Editors created using our `editor-core` package. +- **Content Trimming**: The Editor’s content is now automatically trimmed of empty line breaks from the start and end before submitting it to the backend. This ensures cleaner, more consistent data. +- **Value Cleaning**: The Editor’s value is cleaned at the editor core level, eliminating the need for additional validation before sending from our app. This results in cleaner code and less potential for errors. +- **Turbo Pipeline**: We have added a turbo pipeline for both dev and build tasks for the editor package. This results in faster, more efficient development and build processes. diff --git a/packages/editor/core/src/index.ts b/packages/editor/core/src/index.ts index bb381b3bcbb..590b17172f5 100644 --- a/packages/editor/core/src/index.ts +++ b/packages/editor/core/src/index.ts @@ -3,8 +3,7 @@ // import "./styles/editor.css"; // utils -export { cn } from "./lib/utils"; -export { getEditorClassNames } from "./lib/utils"; +export * from "./lib/utils"; export { startImageUpload } from "./ui/plugins/upload-image"; // components diff --git a/packages/editor/core/src/lib/utils.ts b/packages/editor/core/src/lib/utils.ts index 82618a4c6a5..48467478022 100644 --- a/packages/editor/core/src/lib/utils.ts +++ b/packages/editor/core/src/lib/utils.ts @@ -30,4 +30,16 @@ export const getTrimmedHTML = (html: string) => { html = html.replace(/^(

<\/p>)+/, ''); html = html.replace(/(

<\/p>)+$/, ''); return html; -} \ No newline at end of file +} + +export const 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/core/src/ui/extensions/index.tsx b/packages/editor/core/src/ui/extensions/index.tsx index acd60e63467..62d53e0e1dd 100644 --- a/packages/editor/core/src/ui/extensions/index.tsx +++ b/packages/editor/core/src/ui/extensions/index.tsx @@ -16,8 +16,8 @@ import { TableRow } from "@tiptap/extension-table-row"; import ImageExtension from "./image"; import { DeleteImage } from "../../types/delete-image"; +import { isValidHttpUrl } from "../../lib/utils"; -import isValidHttpUrl from "../menus/bubble-menu/utils" export const CoreEditorExtensions = ( deleteFile: DeleteImage, diff --git a/packages/editor/core/src/ui/read-only/extensions.tsx b/packages/editor/core/src/ui/read-only/extensions.tsx index e9fba4eab20..2246c64f9f8 100644 --- a/packages/editor/core/src/ui/read-only/extensions.tsx +++ b/packages/editor/core/src/ui/read-only/extensions.tsx @@ -13,8 +13,8 @@ import { Table } from "../extensions/table"; import { TableHeader } from "../extensions/table/table-header"; import { TableRow } from "@tiptap/extension-table-row"; -import isValidHttpUrl from "../menus/bubble-menu/utils"; import ReadOnlyImageExtension from "../extensions/image/read-only-image"; +import { isValidHttpUrl } from "../../lib/utils"; export const CoreReadOnlyEditorExtensions = [ StarterKit.configure({ diff --git a/packages/editor/lite-text-editor/Readme.md b/packages/editor/lite-text-editor/Readme.md new file mode 100644 index 00000000000..b6879f1a0d4 --- /dev/null +++ b/packages/editor/lite-text-editor/Readme.md @@ -0,0 +1,55 @@ +# @plane/rich-text-editor + +## Description + +The `@plane/lite-text-editor` package extends from the `editor-core` package, inheriting its base functionality while adding its own unique features and primarily powers the comment editor. + +## Key Features + +- **Comment Editor**: A new Comment editor (lite-text-editor). This editor includes a fixed menu and has built-in support for toggling access modifiers, adding marks, images, tables and lists. +- **Exported Components**: There are two components exported from each type of Editor (with and without Ref), you can choose to use the `withRef` instance whenever you want to control the Editor’s state via a side effect of some external action from within the application code. +- **Read Only Editor Instances**: We have added a really light weight `Read Only` Editor instance for both the Rich and Lite editor types. +- **WorkspaceSlug Removal**: There is no longer a need to pass in WorkspaceSlug to the Editor Instance. This simplifies the process of using our editor instances. + +## Props + +| Prop | Type | Description | +| --- | --- | --- | +| `uploadFile` | `UploadImage` | A function that handles file upload. It takes a file as input and handles the process of uploading that file. | +| `deleteFile` | `DeleteImage` | A function that handles deleting an image. It takes the workspaceImageIdSlug as input and handles the process of deleting that image. | +| `value` | `string` | The initial content of the editor. | +| `debouncedUpdatesEnabled` | `boolean` | If set to true, the `onChange` event handler is debounced, meaning it will only be invoked after the specified delay (default 1500ms) once the user has stopped typing. | +| `onChange` | `(json: any, html: string) => void` | This function is invoked whenever the content of the editor changes. It is passed the new content in both JSON and HTML formats. | +| `setIsSubmitting` | `(isSubmitting: "submitting" \| "submitted" \| "saved") => void` | This function is called to update the submission status. | +| `setShouldShowAlert` | `(showAlert: boolean) => void` | This function is used to show or hide an alert incase of content not being "saved". | +| `noBorder` | `boolean` | If set to true, the editor will not have a border. | +| `borderOnFocus` | `boolean` | If set to true, the editor will show a border when it is focused. | +| `customClassName` | `string` | This is a custom CSS class that can be applied to the editor. | +| `editorContentCustomClassNames` | `string` | This is a custom CSS class that can be applied to the editor content. | + +## Usage + +Here is an example of how to use the `LiteTextEditor` component: + +```jsx + { + setShowAlert(true); + setIsSubmitting("submitting"); + onChange(description_html); + handleSubmit(handleDescriptionFormSubmit)().finally(() => + setIsSubmitting("submitted") + ); + }} +/> +``` diff --git a/packages/editor/rich-text-editor/Readme.md b/packages/editor/rich-text-editor/Readme.md new file mode 100644 index 00000000000..fa56d6e141d --- /dev/null +++ b/packages/editor/rich-text-editor/Readme.md @@ -0,0 +1,54 @@ +# README for @plane/rich-text-editor + +## Description + +The `@plane/rich-text-editor` package extends from the `editor-core` package, inheriting its base functionality while adding its own unique features. + +## Key Features + +- **Comment Editor**: A new Comment editor (lite-text-editor). This editor includes a fixed menu and has built-in support for toggling access modifiers, adding marks, images, tables and lists. +- **Exported Components**: There are two components exported from each type of Editor (with and without Ref), you can choose to use the `withRef` instance whenever you want to control the Editor’s state via a side effect of some external action from within the application code. +- **Read Only Editor Instances**: We have added a really light weight `Read Only` Editor instance for both the Rich and Lite editor types. + +## Props + +| Prop | Type | Description | +| --- | --- | --- | +| `uploadFile` | `UploadImage` | A function that handles file upload. It takes a file as input and handles the process of uploading that file. | +| `deleteFile` | `DeleteImage` | A function that handles deleting an image. It takes the workspaceImageIdSlug as input and handles the process of deleting that image. | +| `value` | `string` | The initial content of the editor. | +| `debouncedUpdatesEnabled` | `boolean` | If set to true, the `onChange` event handler is debounced, meaning it will only be invoked after the specified delay (default 1500ms) once the user has stopped typing. | +| `onChange` | `(json: any, html: string) => void` | This function is invoked whenever the content of the editor changes. It is passed the new content in both JSON and HTML formats. | +| `setIsSubmitting` | `(isSubmitting: "submitting" \| "submitted" \| "saved") => void` | This function is called to update the submission status. | +| `setShouldShowAlert` | `(showAlert: boolean) => void` | This function is used to show or hide an alert incase of content not being "saved". | +| `noBorder` | `boolean` | If set to true, the editor will not have a border. | +| `borderOnFocus` | `boolean` | If set to true, the editor will show a border when it is focused. | +| `customClassName` | `string` | This is a custom CSS class that can be applied to the editor. | +| `editorContentCustomClassNames` | `string` | This is a custom CSS class that can be applied to the editor content. | + +## Usage + +Here is an example of how to use the `RichTextEditor` component: + +```jsx + { + setShowAlert(true); + setIsSubmitting("submitting"); + onChange(description_html); + handleSubmit(handleDescriptionFormSubmit)().finally(() => + setIsSubmitting("submitted") + ); + }} +/> +``` diff --git a/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/link-selector.tsx b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/link-selector.tsx index ba53608c54b..1bccaa1edb4 100644 --- a/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/link-selector.tsx +++ b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/link-selector.tsx @@ -1,8 +1,7 @@ import { Editor } from "@tiptap/core"; import { Check, Trash } from "lucide-react"; import { Dispatch, FC, SetStateAction, useCallback, useEffect, useRef } from "react"; -import isValidHttpUrl from "./utils"; -import { cn } from "@plane/editor-core"; +import { cn, isValidHttpUrl } from "@plane/editor-core"; interface LinkSelectorProps { editor: Editor; diff --git a/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/utils/index.tsx b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/utils/index.tsx deleted file mode 100644 index b5add3f544e..00000000000 --- a/packages/editor/rich-text-editor/src/ui/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:"; -} From d9c3407eeda0294fba5fe0b759f26a4f699e8abc Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Tue, 10 Oct 2023 14:35:07 +0530 Subject: [PATCH 46/57] fixed ts issues with link plugin --- packages/editor/core/Readme.md | 36 +++++++++++++++++-- .../editor/core/src/lib/editor-commands.ts | 9 +++++ .../ui/menus/bubble-menu/link-selector.tsx | 6 ++-- 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/packages/editor/core/Readme.md b/packages/editor/core/Readme.md index fd82856f726..ee272c348f1 100644 --- a/packages/editor/core/Readme.md +++ b/packages/editor/core/Readme.md @@ -2,11 +2,41 @@ ## Description -The `@plane/editor-core` package serves as the foundation for our editor system. It provides the base functionality for our other editor packages, but it will not be used directly in any of the projects. +The `@plane/editor-core` package serves as the foundation for our editor system. It provides the base functionality for our other editor packages, but it will not be used directly in any of the projects but only for extending other editors. -## Key Features +## Utilities + +We provide a wide range of utilities for extending the core itself. + +1. Merging classes and custom styling +2. Adding new extensions +3. Adding custom props +4. Base menu items, and their commands + +This allows for extensive customization and flexibility in the Editors created using our `editor-core` package. + +### Here's a detailed overview of what's exported + + +## Core features -- **Extensive Utilities**: We provide a wide range of utilities for extending the core itself. These include merging classes, adding new extensions, custom props, menu items, and their commands. This allows for extensive customization and flexibility in the Editors created using our `editor-core` package. - **Content Trimming**: The Editor’s content is now automatically trimmed of empty line breaks from the start and end before submitting it to the backend. This ensures cleaner, more consistent data. - **Value Cleaning**: The Editor’s value is cleaned at the editor core level, eliminating the need for additional validation before sending from our app. This results in cleaner code and less potential for errors. - **Turbo Pipeline**: We have added a turbo pipeline for both dev and build tasks for the editor package. This results in faster, more efficient development and build processes. + +## Base extensions included + +- BulletList +- OrderedList +- Blockquote +- Code +- Gapcursor +- Link +- Image +- Basic Marks + - Underline + - TextStyle + - Color +- TaskList +- Markdown +- Table \ No newline at end of file diff --git a/packages/editor/core/src/lib/editor-commands.ts b/packages/editor/core/src/lib/editor-commands.ts index d2ed73ae31e..e00146b6d20 100644 --- a/packages/editor/core/src/lib/editor-commands.ts +++ b/packages/editor/core/src/lib/editor-commands.ts @@ -46,6 +46,14 @@ export const insertTableCommand = (editor: Editor, range?: Range) => { else editor.chain().focus().insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run(); }; +export const unsetLinkEditor = (editor: Editor) => { + editor.chain().focus().unsetLink().run(); +}; + +export const setLinkEditor = (editor: Editor, url: string) => { + editor.chain().focus().setLink({ href: url }).run(); +}; + export const insertImageCommand = (editor: Editor, uploadFile: UploadImage, setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void, range?: Range) => { if (range) editor.chain().focus().deleteRange(range).run(); const input = document.createElement("input"); @@ -60,3 +68,4 @@ export const insertImageCommand = (editor: Editor, uploadFile: UploadImage, setI }; input.click(); }; + diff --git a/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/link-selector.tsx b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/link-selector.tsx index 1bccaa1edb4..7dddc9d984b 100644 --- a/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/link-selector.tsx +++ b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/link-selector.tsx @@ -1,7 +1,7 @@ import { Editor } from "@tiptap/core"; import { Check, Trash } from "lucide-react"; import { Dispatch, FC, SetStateAction, useCallback, useEffect, useRef } from "react"; -import { cn, isValidHttpUrl } from "@plane/editor-core"; +import { cn, isValidHttpUrl, setLinkEditor, unsetLinkEditor, } from "@plane/editor-core"; interface LinkSelectorProps { editor: Editor; @@ -16,7 +16,7 @@ export const LinkSelector: FC = ({ editor, isOpen, setIsOpen const input = inputRef.current; const url = input?.value; if (url && isValidHttpUrl(url)) { - editor.chain().focus().setLink({ href: url }).run(); + setLinkEditor(editor, url); setIsOpen(false); } }, [editor, inputRef, setIsOpen]); @@ -68,7 +68,7 @@ export const LinkSelector: FC = ({ editor, isOpen, setIsOpen type="button" className="flex items-center rounded-sm p-1 text-red-600 transition-all hover:bg-red-100 dark:hover:bg-red-800" onClick={() => { - editor.chain().focus().unsetLink().run(); + unsetLinkEditor(editor); setIsOpen(false); }} > From ede27b7b178bd3674ce27c7bc76a4f642643bec5 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Tue, 10 Oct 2023 16:17:26 +0530 Subject: [PATCH 47/57] added usage of common dependance for slash commands --- .../editor/core/src/lib/editor-commands.ts | 20 ++++++ .../core/src/ui/menus/menu-items/index.tsx | 32 ++++++++- .../src/ui/extensions/index.tsx | 1 - .../src/ui/extensions/slash-command.tsx | 39 +++-------- .../ui/menus/bubble-menu/node-selector.tsx | 68 +++---------------- 5 files changed, 69 insertions(+), 91 deletions(-) diff --git a/packages/editor/core/src/lib/editor-commands.ts b/packages/editor/core/src/lib/editor-commands.ts index e00146b6d20..497a63ca61a 100644 --- a/packages/editor/core/src/lib/editor-commands.ts +++ b/packages/editor/core/src/lib/editor-commands.ts @@ -2,6 +2,21 @@ import { Editor, Range } from "@tiptap/core"; import { UploadImage } from "../types/upload-image"; import { startImageUpload } from "../ui/plugins/upload-image"; +export const toggleHeadingOne = (editor: Editor, range?: Range) => { + if (range) editor.chain().focus().deleteRange(range).setNode("heading", { level: 1 }).run(); + else editor.chain().focus().toggleHeading({ level: 1 }).run() +}; + +export const toggleHeadingTwo = (editor: Editor, range?: Range) => { + if (range) editor.chain().focus().deleteRange(range).setNode("heading", { level: 2 }).run(); + else editor.chain().focus().toggleHeading({ level: 2 }).run() +}; + +export const toggleHeadingThree = (editor: Editor, range?: Range) => { + if (range) editor.chain().focus().deleteRange(range).setNode("heading", { level: 3 }).run(); + else editor.chain().focus().toggleHeading({ level: 3 }).run() +}; + export const toggleBold = (editor: Editor, range?: Range) => { if (range) editor.chain().focus().deleteRange(range).toggleBold().run(); else editor.chain().focus().toggleBold().run(); @@ -31,6 +46,11 @@ export const toggleBulletList = (editor: Editor, range?: Range) => { else editor.chain().focus().toggleBulletList().run(); }; +export const toggleTaskList = (editor: Editor, range?: Range) => { + if (range) editor.chain().focus().deleteRange(range).toggleTaskList().run(); + else editor.chain().focus().toggleTaskList().run() +}; + export const toggleStrike = (editor: Editor, range?: Range) => { if (range) editor.chain().focus().deleteRange(range).toggleStrike().run(); else editor.chain().focus().toggleStrike().run(); diff --git a/packages/editor/core/src/ui/menus/menu-items/index.tsx b/packages/editor/core/src/ui/menus/menu-items/index.tsx index dfef77e59dc..f31b6601e77 100644 --- a/packages/editor/core/src/ui/menus/menu-items/index.tsx +++ b/packages/editor/core/src/ui/menus/menu-items/index.tsx @@ -1,7 +1,7 @@ -import { BoldIcon, QuoteIcon, ImageIcon, TableIcon, ListIcon, ListOrderedIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, CodeIcon } from "lucide-react"; +import { BoldIcon, Heading1, CheckSquare, Heading2, Heading3, QuoteIcon, ImageIcon, TableIcon, ListIcon, ListOrderedIcon, ItalicIcon, UnderlineIcon, StrikethroughIcon, CodeIcon } from "lucide-react"; import { Editor } from "@tiptap/react"; import { UploadImage } from "../../../types/upload-image"; -import { insertImageCommand, insertTableCommand, toggleBlockquote, toggleBold, toggleBulletList, toggleCode, toggleItalic, toggleOrderedList, toggleStrike, toggleUnderline, } from "../../../lib/editor-commands"; +import { insertImageCommand, insertTableCommand, toggleBlockquote, toggleBold, toggleBulletList, toggleCode, toggleHeadingOne, toggleHeadingThree, toggleHeadingTwo, toggleItalic, toggleOrderedList, toggleStrike, toggleTaskList, toggleUnderline, } from "../../../lib/editor-commands"; export interface EditorMenuItem { name: string; @@ -10,6 +10,27 @@ export interface EditorMenuItem { icon: typeof BoldIcon; } +export const HeadingOneItem = (editor: Editor): EditorMenuItem => ({ + name: "H1", + isActive: () => editor.isActive("heading", { level: 1 }), + command: () => toggleHeadingOne(editor), + icon: Heading1, +}) + +export const HeadingTwoItem = (editor: Editor): EditorMenuItem => ({ + name: "H2", + isActive: () => editor.isActive("heading", { level: 2 }), + command: () => toggleHeadingTwo(editor), + icon: Heading2, +}) + +export const HeadingThreeItem = (editor: Editor): EditorMenuItem => ({ + name: "H3", + isActive: () => editor.isActive("heading", { level: 3 }), + command: () => toggleHeadingThree(editor), + icon: Heading3, +}) + export const BoldItem = (editor: Editor): EditorMenuItem => ({ name: "bold", isActive: () => editor?.isActive("bold"), @@ -52,6 +73,13 @@ export const BulletListItem = (editor: Editor): EditorMenuItem => ({ icon: ListIcon, }) +export const TodoListItem = (editor: Editor): EditorMenuItem => ({ + name: "To-do List", + isActive: () => editor.isActive("taskItem"), + command: () => toggleTaskList(editor), + icon: CheckSquare, +}) + export const NumberedListItem = (editor: Editor): EditorMenuItem => ({ name: "ordered-list", isActive: () => editor?.isActive("orderedList"), diff --git a/packages/editor/rich-text-editor/src/ui/extensions/index.tsx b/packages/editor/rich-text-editor/src/ui/extensions/index.tsx index e70fcc88d41..f0f3bed3423 100644 --- a/packages/editor/rich-text-editor/src/ui/extensions/index.tsx +++ b/packages/editor/rich-text-editor/src/ui/extensions/index.tsx @@ -6,7 +6,6 @@ import { InputRule } from "@tiptap/core"; import ts from "highlight.js/lib/languages/typescript"; -// import "highlight.js/styles/github-dark.css"; import SlashCommand from "./slash-command"; import { UploadImage } from "../"; diff --git a/packages/editor/rich-text-editor/src/ui/extensions/slash-command.tsx b/packages/editor/rich-text-editor/src/ui/extensions/slash-command.tsx index ff63b6abfc0..e00585dd82a 100644 --- a/packages/editor/rich-text-editor/src/ui/extensions/slash-command.tsx +++ b/packages/editor/rich-text-editor/src/ui/extensions/slash-command.tsx @@ -17,8 +17,8 @@ import { ImageIcon, Table, } from "lucide-react"; -import { UploadImage } from ".."; -import { cn, insertTableCommand, startImageUpload, toggleBulletList } from "@plane/editor-core"; +import { UploadImage } from "../"; +import { cn, insertTableCommand, toggleBlockquote, toggleBulletList, toggleOrderedList, toggleTaskList, insertImageCommand, toggleHeadingOne, toggleHeadingTwo, toggleHeadingThree } from "@plane/editor-core"; interface CommandItemProps { title: string; @@ -78,7 +78,7 @@ const getSuggestionItems = searchTerms: ["title", "big", "large"], icon: , command: ({ editor, range }: CommandProps) => { - editor.chain().focus().deleteRange(range).setNode("heading", { level: 1 }).run(); + toggleHeadingOne(editor, range); }, }, { @@ -87,7 +87,7 @@ const getSuggestionItems = searchTerms: ["subtitle", "medium"], icon: , command: ({ editor, range }: CommandProps) => { - editor.chain().focus().deleteRange(range).setNode("heading", { level: 2 }).run(); + toggleHeadingTwo(editor, range); }, }, { @@ -96,7 +96,7 @@ const getSuggestionItems = searchTerms: ["subtitle", "small"], icon: , command: ({ editor, range }: CommandProps) => { - editor.chain().focus().deleteRange(range).setNode("heading", { level: 3 }).run(); + toggleHeadingThree(editor, range); }, }, { @@ -105,7 +105,7 @@ const getSuggestionItems = searchTerms: ["todo", "task", "list", "check", "checkbox"], icon: , command: ({ editor, range }: CommandProps) => { - editor.chain().focus().deleteRange(range).toggleTaskList().run(); + toggleTaskList(editor, range) }, }, { @@ -114,7 +114,6 @@ const getSuggestionItems = searchTerms: ["unordered", "point"], icon: , command: ({ editor, range }: CommandProps) => { - // editor.chain().focus().deleteRange(range).toggleBulletList().run(); toggleBulletList(editor, range); }, }, @@ -134,12 +133,6 @@ const getSuggestionItems = icon:

, command: ({ editor, range }: CommandProps) => { insertTableCommand(editor, range); - // editor - // .chain() - // .focus() - // .deleteRange(range) - // .insertTable({ rows: 3, cols: 3, withHeaderRow: true }) - // .run(); }, }, { @@ -148,8 +141,7 @@ const getSuggestionItems = searchTerms: ["ordered"], icon: , command: ({ editor, range }: CommandProps) => { - // @ts-ignore - editor.chain().focus().deleteRange(range).toggleOrderedList().run(); + toggleOrderedList(editor, range) }, }, { @@ -158,8 +150,7 @@ const getSuggestionItems = searchTerms: ["blockquote"], icon: , command: ({ editor, range }: CommandProps) => - // @ts-ignore - editor.chain().focus().deleteRange(range).toggleNode("paragraph", "paragraph").toggleBlockquote().run(), + toggleBlockquote(editor, range) }, { title: "Code", @@ -175,19 +166,7 @@ const getSuggestionItems = 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, uploadFile, setIsSubmitting); - } - }; - input.click(); + insertImageCommand(editor, uploadFile, setIsSubmitting, range); }, }, ].filter((item) => { diff --git a/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/node-selector.tsx b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/node-selector.tsx index e1f8ce2111f..b8b7ffc58db 100644 --- a/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/node-selector.tsx +++ b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/node-selector.tsx @@ -1,16 +1,9 @@ -import { cn } from "@plane/editor-core"; -import { Editor } from "@tiptap/core"; +import { BulletListItem, cn, CodeItem, HeadingOneItem, HeadingThreeItem, HeadingTwoItem, NumberedListItem, QuoteItem, TodoListItem } from "@plane/editor-core"; +import { Editor } from "@tiptap/react"; import { Check, ChevronDown, - Heading1, - Heading2, - Heading3, - TextQuote, - ListOrdered, TextIcon, - Code, - CheckSquare, } from "lucide-react"; import { Dispatch, FC, SetStateAction } from "react"; @@ -33,55 +26,14 @@ export const NodeSelector: FC = ({ editor, isOpen, setIsOpen !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"), - }, + HeadingOneItem(editor), + HeadingTwoItem(editor), + HeadingThreeItem(editor), + TodoListItem(editor), + BulletListItem(editor), + NumberedListItem(editor), + QuoteItem(editor), + CodeItem(editor), ]; const activeItem = items.filter((item) => item.isActive()).pop() ?? { From 3ea7ab31516e5a7fe770b15272e11d73a592c211 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Tue, 10 Oct 2023 17:25:45 +0530 Subject: [PATCH 48/57] completed core package's documentation --- packages/editor/core/Readme.md | 74 ++++++++++++++++++- .../editor/core/src/ui/hooks/useEditor.tsx | 4 +- .../core/src/ui/hooks/useReadOnlyEditor.tsx | 12 ++- 3 files changed, 82 insertions(+), 8 deletions(-) diff --git a/packages/editor/core/Readme.md b/packages/editor/core/Readme.md index ee272c348f1..f5baf2d54b8 100644 --- a/packages/editor/core/Readme.md +++ b/packages/editor/core/Readme.md @@ -17,12 +17,82 @@ This allows for extensive customization and flexibility in the Editors created u ### Here's a detailed overview of what's exported +1. useEditor - A hook that you can use to extend the Plane editor. + + | Prop | Type | Description | + | --- | --- | --- | + | `extensions` | `Extension[]` | An array of custom extensions you want to add into the editor to extend it's core features | + | `editorProps` | `EditorProps` | Extend the editor props by passing in a custom props object | + | `uploadFile` | `(file: File) => Promise` | A function that handles file upload. It takes a file as input and handles the process of uploading that file. | + | `deleteFile` | `(assetUrlWithWorkspaceId: string) => Promise` | A function that handles deleting an image. It takes the asset url from your bucket and handles the process of deleting that image. | + | `value` | `string` | The initial content of the editor. | + | `debouncedUpdatesEnabled` | `boolean` | If set to true, the `onChange` event handler is debounced, meaning it will only be invoked after the specified delay (default 1500ms) once the user has stopped typing. | + | `onChange` | `(json: any, html: string) => void` | This function is invoked whenever the content of the editor changes. It is passed the new content in both JSON and HTML formats. | + | `setIsSubmitting` | `(isSubmitting: "submitting" \| "submitted" \| "saved") => void` | This function is called to update the submission status. | + | `setShouldShowAlert` | `(showAlert: boolean) => void` | This function is used to show or hide an alert in case of content not being "saved". | + | `forwardedRef` | `any` | Pass this in whenever you want to control the editor's state from an external component | + +2. useReadOnlyEditor - A hook that can be used to extend a Read Only instance of the core editor. + + | Prop | Type | Description | + | --- | --- | --- | + | `value` | `string` | The initial content of the editor. | + | `forwardedRef` | `any` | Pass this in whenever you want to control the editor's state from an external component | + | `extensions` | `Extension[]` | An array of custom extensions you want to add into the editor to extend it's core features | + | `editorProps` | `EditorProps` | Extend the editor props by passing in a custom props object | + +3. Items and Commands - H1, H2, H3, task list, quote, code block, etc's methods. + +4. UI Wrappers + +- `EditorContainer` - Wrap your Editor Container with this to apply base classes and styles. +- `EditorContentWrapper` - Use this to get Editor's Content and base menus. + +5. Extending with Custom Styles + +```ts +const customEditorClassNames = getEditorClassNames({ noBorder, borderOnFocus, customClassName }); +``` ## Core features - **Content Trimming**: The Editor’s content is now automatically trimmed of empty line breaks from the start and end before submitting it to the backend. This ensures cleaner, more consistent data. - **Value Cleaning**: The Editor’s value is cleaned at the editor core level, eliminating the need for additional validation before sending from our app. This results in cleaner code and less potential for errors. -- **Turbo Pipeline**: We have added a turbo pipeline for both dev and build tasks for the editor package. This results in faster, more efficient development and build processes. +- **Turbo Pipeline**: Added a turbo pipeline for both dev and build tasks for projects depending on the editor package. + +```json + "web#develop": { + "cache": false, + "persistent": true, + "dependsOn": [ + "@plane/lite-text-editor#build", + "@plane/rich-text-editor#build" + ] + }, + "space#develop": { + "cache": false, + "persistent": true, + "dependsOn": [ + "@plane/lite-text-editor#build", + "@plane/rich-text-editor#build" + ] + }, + "web#build": { + "cache": true, + "dependsOn": [ + "@plane/lite-text-editor#build", + "@plane/rich-text-editor#build" + ] + }, + "space#build": { + "cache": true, + "dependsOn": [ + "@plane/lite-text-editor#build", + "@plane/rich-text-editor#build" + ] + }, + +``` ## Base extensions included @@ -39,4 +109,4 @@ This allows for extensive customization and flexibility in the Editors created u - Color - TaskList - Markdown -- Table \ No newline at end of file +- Table diff --git a/packages/editor/core/src/ui/hooks/useEditor.tsx b/packages/editor/core/src/ui/hooks/useEditor.tsx index 9a3f4882af6..83770091511 100644 --- a/packages/editor/core/src/ui/hooks/useEditor.tsx +++ b/packages/editor/core/src/ui/hooks/useEditor.tsx @@ -11,7 +11,6 @@ import { UploadImage } from "../../types/upload-image"; const DEBOUNCE_DELAY = 1500; interface CustomEditorProps { - editable?: boolean; uploadFile: UploadImage; setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void; setShouldShowAlert?: (showAlert: boolean) => void; @@ -24,9 +23,8 @@ interface CustomEditorProps { forwardedRef?: any; } -export const useEditor = ({ uploadFile, editable, deleteFile, editorProps = {}, value, extensions = [], onChange, setIsSubmitting, debouncedUpdatesEnabled, forwardedRef, setShouldShowAlert, }: CustomEditorProps) => { +export const useEditor = ({ uploadFile, deleteFile, editorProps = {}, value, extensions = [], onChange, setIsSubmitting, debouncedUpdatesEnabled, forwardedRef, setShouldShowAlert, }: CustomEditorProps) => { const editor = useCustomEditor({ - editable: editable ?? true, editorProps: { ...CoreEditorProps(uploadFile, setIsSubmitting), ...editorProps, diff --git a/packages/editor/core/src/ui/hooks/useReadOnlyEditor.tsx b/packages/editor/core/src/ui/hooks/useReadOnlyEditor.tsx index a6130cff149..3791c4c5d2c 100644 --- a/packages/editor/core/src/ui/hooks/useReadOnlyEditor.tsx +++ b/packages/editor/core/src/ui/hooks/useReadOnlyEditor.tsx @@ -2,18 +2,24 @@ import { useEditor as useCustomEditor, Editor } from "@tiptap/react"; import { useImperativeHandle, useRef, MutableRefObject } from "react"; import { CoreReadOnlyEditorExtensions } from "../../ui/read-only/extensions"; import { CoreReadOnlyEditorProps } from "../../ui/read-only/props"; +import { EditorProps } from '@tiptap/pm/view'; interface CustomReadOnlyEditorProps { value: string; forwardedRef?: any; + extensions?: any; + editorProps?: EditorProps; } -export const useReadOnlyEditor = ({ value, forwardedRef }: CustomReadOnlyEditorProps) => { +export const useReadOnlyEditor = ({ value, forwardedRef, extensions, editorProps }: CustomReadOnlyEditorProps) => { const editor = useCustomEditor({ editable: false, content: (typeof value === "string" && value.trim() !== "") ? value : "

", - editorProps: CoreReadOnlyEditorProps, - extensions: CoreReadOnlyEditorExtensions, + editorProps: { + ...CoreReadOnlyEditorProps, + ...editorProps, + }, + extensions: [...CoreReadOnlyEditorExtensions, ...extensions], }); const editorRef: MutableRefObject = useRef(null); From 67fd3e296af8a8a0def09e6492ae8c8c6e90f6f0 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Tue, 10 Oct 2023 17:29:24 +0530 Subject: [PATCH 49/57] fixed tsconfig by removing path aliases --- packages/editor/core/tsconfig.json | 5 +---- packages/editor/lite-text-editor/tsconfig.json | 5 +---- packages/editor/rich-text-editor/tsconfig.json | 7 ++----- packages/tsconfig/base.json | 7 +------ 4 files changed, 5 insertions(+), 19 deletions(-) diff --git a/packages/editor/core/tsconfig.json b/packages/editor/core/tsconfig.json index c230b89afa4..61a60f3244c 100644 --- a/packages/editor/core/tsconfig.json +++ b/packages/editor/core/tsconfig.json @@ -8,8 +8,5 @@ "dist", "build", "node_modules" - ], - "compilerOptions": { - "baseUrl": "." - } + ] } diff --git a/packages/editor/lite-text-editor/tsconfig.json b/packages/editor/lite-text-editor/tsconfig.json index c230b89afa4..61a60f3244c 100644 --- a/packages/editor/lite-text-editor/tsconfig.json +++ b/packages/editor/lite-text-editor/tsconfig.json @@ -8,8 +8,5 @@ "dist", "build", "node_modules" - ], - "compilerOptions": { - "baseUrl": "." - } + ] } diff --git a/packages/editor/rich-text-editor/tsconfig.json b/packages/editor/rich-text-editor/tsconfig.json index c6fe47fe397..61a60f3244c 100644 --- a/packages/editor/rich-text-editor/tsconfig.json +++ b/packages/editor/rich-text-editor/tsconfig.json @@ -3,13 +3,10 @@ "include": [ "src/**/*", "index.d.ts" -, "../lite-text-editor/src/ui/extensions/enter-key-extension.tsx" ], + ], "exclude": [ "dist", "build", "node_modules" - ], - "compilerOptions": { - "baseUrl": "." - } + ] } diff --git a/packages/tsconfig/base.json b/packages/tsconfig/base.json index 0659d31a203..2825abe07ce 100644 --- a/packages/tsconfig/base.json +++ b/packages/tsconfig/base.json @@ -14,12 +14,7 @@ "noUnusedParameters": false, "preserveWatchOutput": true, "skipLibCheck": true, - "strict": true, - "paths": { - "@/*": [ - "./*" - ] - } + "strict": true }, "exclude": [ "node_modules" From 8ba39dc1ea6ed30be3d626d88a6c24b50839fab4 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Tue, 10 Oct 2023 17:48:26 +0530 Subject: [PATCH 50/57] Completed readme for rich-text-editor --- packages/editor/core/Readme.md | 2 +- packages/editor/rich-text-editor/Readme.md | 77 +++++++++++++++---- .../editor/rich-text-editor/src/ui/index.tsx | 3 - 3 files changed, 62 insertions(+), 20 deletions(-) diff --git a/packages/editor/core/Readme.md b/packages/editor/core/Readme.md index f5baf2d54b8..0cf6aeec329 100644 --- a/packages/editor/core/Readme.md +++ b/packages/editor/core/Readme.md @@ -25,7 +25,7 @@ This allows for extensive customization and flexibility in the Editors created u | `editorProps` | `EditorProps` | Extend the editor props by passing in a custom props object | | `uploadFile` | `(file: File) => Promise` | A function that handles file upload. It takes a file as input and handles the process of uploading that file. | | `deleteFile` | `(assetUrlWithWorkspaceId: string) => Promise` | A function that handles deleting an image. It takes the asset url from your bucket and handles the process of deleting that image. | - | `value` | `string` | The initial content of the editor. | + | `value` | `html string` | The initial content of the editor. | | `debouncedUpdatesEnabled` | `boolean` | If set to true, the `onChange` event handler is debounced, meaning it will only be invoked after the specified delay (default 1500ms) once the user has stopped typing. | | `onChange` | `(json: any, html: string) => void` | This function is invoked whenever the content of the editor changes. It is passed the new content in both JSON and HTML formats. | | `setIsSubmitting` | `(isSubmitting: "submitting" \| "submitted" \| "saved") => void` | This function is called to update the submission status. | diff --git a/packages/editor/rich-text-editor/Readme.md b/packages/editor/rich-text-editor/Readme.md index fa56d6e141d..a0dab0bbdbe 100644 --- a/packages/editor/rich-text-editor/Readme.md +++ b/packages/editor/rich-text-editor/Readme.md @@ -1,22 +1,25 @@ -# README for @plane/rich-text-editor +# @plane/rich-text-editor ## Description -The `@plane/rich-text-editor` package extends from the `editor-core` package, inheriting its base functionality while adding its own unique features. +The `@plane/rich-text-editor` package extends from the `editor-core` package, inheriting its base functionality while adding its own unique features of Slack Commands and many more. ## Key Features -- **Comment Editor**: A new Comment editor (lite-text-editor). This editor includes a fixed menu and has built-in support for toggling access modifiers, adding marks, images, tables and lists. -- **Exported Components**: There are two components exported from each type of Editor (with and without Ref), you can choose to use the `withRef` instance whenever you want to control the Editor’s state via a side effect of some external action from within the application code. -- **Read Only Editor Instances**: We have added a really light weight `Read Only` Editor instance for both the Rich and Lite editor types. +- **Exported Components**: There are two components exported from the Rich text editor (with and without Ref), you can choose to use the `withRef` instance whenever you want to control the Editor’s state via a side effect of some external action from within the application code. -## Props + `RichTextEditor` & `RichTextEditorWithRef` + +- **Read Only Editor Instances**: We have added a really light weight *Read Only* Editor instance for the Rich editor types (with and without Ref) + `RichReadOnlyEditor` &`RichReadOnlyEditorWithRef` + +## RichTextEditor | Prop | Type | Description | | --- | --- | --- | -| `uploadFile` | `UploadImage` | A function that handles file upload. It takes a file as input and handles the process of uploading that file. | -| `deleteFile` | `DeleteImage` | A function that handles deleting an image. It takes the workspaceImageIdSlug as input and handles the process of deleting that image. | -| `value` | `string` | The initial content of the editor. | +| `uploadFile` | `(file: File) => Promise` | A function that handles file upload. It takes a file as input and handles the process of uploading that file. | +| `deleteFile` | `(assetUrlWithWorkspaceId: string) => Promise` | A function that handles deleting an image. It takes the asset url from your bucket and handles the process of deleting that image. | +| `value` | `html string` | The initial content of the editor. | | `debouncedUpdatesEnabled` | `boolean` | If set to true, the `onChange` event handler is debounced, meaning it will only be invoked after the specified delay (default 1500ms) once the user has stopped typing. | | `onChange` | `(json: any, html: string) => void` | This function is invoked whenever the content of the editor changes. It is passed the new content in both JSON and HTML formats. | | `setIsSubmitting` | `(isSubmitting: "submitting" \| "submitted" \| "saved") => void` | This function is called to update the submission status. | @@ -26,13 +29,13 @@ The `@plane/rich-text-editor` package extends from the `editor-core` package, in | `customClassName` | `string` | This is a custom CSS class that can be applied to the editor. | | `editorContentCustomClassNames` | `string` | This is a custom CSS class that can be applied to the editor content. | -## Usage +### Usage -Here is an example of how to use the `RichTextEditor` component: +1. Here is an example of how to use the `RichTextEditor` component -```jsx +```tsx - setIsSubmitting("submitted") - ); + // custom stuff you want to do }} /> ``` + +2. Example of how to use the `RichTextEditorWithRef` component + +```tsx + const editorRef = useRef(null); + + // can use it to set the editor's value + editorRef.current?.setEditorValue(`${watch("description_html")}`); + + // can use it to clear the editor + editorRef?.current?.clearEditor(); + + return ( { + onChange(description_html); + // custom stuff you want to do + } } />) +``` + +## RichReadOnlyEditor + +| Prop | Type | Description | +| --- | --- | --- | +| `value` | `html string` | The initial content of the editor. | +| `noBorder` | `boolean` | If set to true, the editor will not have a border. | +| `borderOnFocus` | `boolean` | If set to true, the editor will show a border when it is focused. | +| `customClassName` | `string` | This is a custom CSS class that can be applied to the editor. | +| `editorContentCustomClassNames` | `string` | This is a custom CSS class that can be applied to the editor content. | + +### Usage + +Here is an example of how to use the `RichReadOnlyEditor` component + +```tsx + +``` diff --git a/packages/editor/rich-text-editor/src/ui/index.tsx b/packages/editor/rich-text-editor/src/ui/index.tsx index 8794822a057..ce14962c806 100644 --- a/packages/editor/rich-text-editor/src/ui/index.tsx +++ b/packages/editor/rich-text-editor/src/ui/index.tsx @@ -18,7 +18,6 @@ interface IRichTextEditor { onChange?: (json: any, html: string) => void; setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void; setShouldShowAlert?: (showAlert: boolean) => void; - editable?: boolean; forwardedRef?: any; debouncedUpdatesEnabled?: boolean; } @@ -35,7 +34,6 @@ interface EditorHandle { const RichTextEditor = ({ onChange, debouncedUpdatesEnabled, - editable, setIsSubmitting, setShouldShowAlert, editorContentCustomClassNames, @@ -50,7 +48,6 @@ const RichTextEditor = ({ const editor = useEditor({ onChange, debouncedUpdatesEnabled, - editable, setIsSubmitting, setShouldShowAlert, value, From 2ce9f3be98041473d789d116d2de10e0f8b91b8e Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Tue, 10 Oct 2023 18:07:24 +0530 Subject: [PATCH 51/57] Added rich text editor documentation --- packages/editor/lite-text-editor/Readme.md | 106 ++++++++++++------ .../editor/lite-text-editor/src/ui/index.tsx | 11 +- packages/editor/rich-text-editor/Readme.md | 2 +- .../peek-overview/comment/add-comment.tsx | 2 +- .../comment/comment-detail-card.tsx | 2 +- web/components/issues/comment/add-comment.tsx | 2 +- .../issues/comment/comment-card.tsx | 2 +- web/components/issues/draft-issue-form.tsx | 2 +- web/components/issues/form.tsx | 2 +- .../pages/create-update-block-inline.tsx | 2 +- web/components/pages/single-page-block.tsx | 2 +- web/components/web-view/add-comment.tsx | 42 +++---- .../web-view/issue-web-view-form.tsx | 2 +- web/pages/[workspaceSlug]/editor.tsx | 2 +- web/pages/m/[workspaceSlug]/editor.tsx | 2 +- 15 files changed, 110 insertions(+), 73 deletions(-) diff --git a/packages/editor/lite-text-editor/Readme.md b/packages/editor/lite-text-editor/Readme.md index b6879f1a0d4..948e2c34b2d 100644 --- a/packages/editor/lite-text-editor/Readme.md +++ b/packages/editor/lite-text-editor/Readme.md @@ -1,23 +1,26 @@ -# @plane/rich-text-editor +# @plane/lite-text-editor ## Description -The `@plane/lite-text-editor` package extends from the `editor-core` package, inheriting its base functionality while adding its own unique features and primarily powers the comment editor. +The `@plane/lite-text-editor` package extends from the `editor-core` package, inheriting its base functionality while adding its own unique features of Custom control over Enter key, etc. ## Key Features -- **Comment Editor**: A new Comment editor (lite-text-editor). This editor includes a fixed menu and has built-in support for toggling access modifiers, adding marks, images, tables and lists. -- **Exported Components**: There are two components exported from each type of Editor (with and without Ref), you can choose to use the `withRef` instance whenever you want to control the Editor’s state via a side effect of some external action from within the application code. -- **Read Only Editor Instances**: We have added a really light weight `Read Only` Editor instance for both the Rich and Lite editor types. -- **WorkspaceSlug Removal**: There is no longer a need to pass in WorkspaceSlug to the Editor Instance. This simplifies the process of using our editor instances. +- **Exported Components**: There are two components exported from the Lite text editor (with and without Ref), you can choose to use the `withRef` instance whenever you want to control the Editor’s state via a side effect of some external action from within the application code. -## Props + `LiteTextEditor` & `LiteTextEditorWithRef` + +- **Read Only Editor Instances**: We have added a really light weight *Read Only* Editor instance for the Lite editor types (with and without Ref) + `LiteReadOnlyEditor` &`LiteReadOnlyEditorWithRef` + +## LiteTextEditor | Prop | Type | Description | | --- | --- | --- | -| `uploadFile` | `UploadImage` | A function that handles file upload. It takes a file as input and handles the process of uploading that file. | -| `deleteFile` | `DeleteImage` | A function that handles deleting an image. It takes the workspaceImageIdSlug as input and handles the process of deleting that image. | -| `value` | `string` | The initial content of the editor. | +| `uploadFile` | `(file: File) => Promise` | A function that handles file upload. It takes a file as input and handles the process of uploading that file. | +| `deleteFile` | `(assetUrlWithWorkspaceId: string) => Promise` | A function that handles deleting an image. It takes the asset url from your bucket and handles the process of deleting that image. | +| `value` | `html string` | The initial content of the editor. | +| `onEnterKeyPress` | `(e) => void` | The event that happens on Enter key press | | `debouncedUpdatesEnabled` | `boolean` | If set to true, the `onChange` event handler is debounced, meaning it will only be invoked after the specified delay (default 1500ms) once the user has stopped typing. | | `onChange` | `(json: any, html: string) => void` | This function is invoked whenever the content of the editor changes. It is passed the new content in both JSON and HTML formats. | | `setIsSubmitting` | `(isSubmitting: "submitting" \| "submitted" \| "saved") => void` | This function is called to update the submission status. | @@ -27,29 +30,68 @@ The `@plane/lite-text-editor` package extends from the `editor-core` package, in | `customClassName` | `string` | This is a custom CSS class that can be applied to the editor. | | `editorContentCustomClassNames` | `string` | This is a custom CSS class that can be applied to the editor content. | -## Usage +### Usage -Here is an example of how to use the `LiteTextEditor` component: +1. Here is an example of how to use the `RichTextEditor` component -```jsx +```tsx { - setShowAlert(true); - setIsSubmitting("submitting"); - onChange(description_html); - handleSubmit(handleDescriptionFormSubmit)().finally(() => - setIsSubmitting("submitted") - ); - }} -/> + onEnterKeyPress={handleSubmit(handleCommentUpdate)} + uploadFile={fileService.getUploadFileFunction(workspaceSlug)} + deleteFile={fileService.deleteImage} + value={value} + debouncedUpdatesEnabled={false} + customClassName="min-h-[50px] p-3 shadow-sm" + onChange={(comment_json: Object, comment_html: string) => { + onChange(comment_html); + }} + /> +``` + +2. Example of how to use the `LiteTextEditorWithRef` component + +```tsx + const editorRef = useRef(null); + + // can use it to set the editor's value + editorRef.current?.setEditorValue(`${watch("description_html")}`); + + // can use it to clear the editor + editorRef?.current?.clearEditor(); + + return ( + { + onChange(comment_html); + }} + /> +) +``` + +## LiteReadOnlyEditor + +| Prop | Type | Description | +| --- | --- | --- | +| `value` | `html string` | The initial content of the editor. | +| `noBorder` | `boolean` | If set to true, the editor will not have a border. | +| `borderOnFocus` | `boolean` | If set to true, the editor will show a border when it is focused. | +| `customClassName` | `string` | This is a custom CSS class that can be applied to the editor. | +| `editorContentCustomClassNames` | `string` | This is a custom CSS class that can be applied to the editor content. | + +### Usage + +Here is an example of how to use the `RichReadOnlyEditor` component + +```tsx + ``` diff --git a/packages/editor/lite-text-editor/src/ui/index.tsx b/packages/editor/lite-text-editor/src/ui/index.tsx index 0b938672476..7a497d9aab8 100644 --- a/packages/editor/lite-text-editor/src/ui/index.tsx +++ b/packages/editor/lite-text-editor/src/ui/index.tsx @@ -18,7 +18,6 @@ interface ILiteTextEditor { onChange?: (json: any, html: string) => void; setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void; setShouldShowAlert?: (showAlert: boolean) => void; - editable?: boolean; forwardedRef?: any; debouncedUpdatesEnabled?: boolean; commentAccessSpecifier?: { @@ -46,7 +45,6 @@ interface EditorHandle { const LiteTextEditor = ({ onChange, debouncedUpdatesEnabled, - editable, setIsSubmitting, setShouldShowAlert, editorContentCustomClassNames, @@ -63,7 +61,6 @@ const LiteTextEditor = ({ const editor = useEditor({ onChange, debouncedUpdatesEnabled, - editable, setIsSubmitting, setShouldShowAlert, value, @@ -81,11 +78,9 @@ const LiteTextEditor = ({
- {(editable !== false) && - (
- -
) - } +
+ +
); diff --git a/packages/editor/rich-text-editor/Readme.md b/packages/editor/rich-text-editor/Readme.md index a0dab0bbdbe..c8414f62d6a 100644 --- a/packages/editor/rich-text-editor/Readme.md +++ b/packages/editor/rich-text-editor/Readme.md @@ -2,7 +2,7 @@ ## Description -The `@plane/rich-text-editor` package extends from the `editor-core` package, inheriting its base functionality while adding its own unique features of Slack Commands and many more. +The `@plane/rich-text-editor` package extends from the `editor-core` package, inheriting its base functionality while adding its own unique features of Slash Commands and many more. ## Key Features diff --git a/space/components/issues/peek-overview/comment/add-comment.tsx b/space/components/issues/peek-overview/comment/add-comment.tsx index c7852a47bb4..2595dab4283 100644 --- a/space/components/issues/peek-overview/comment/add-comment.tsx +++ b/space/components/issues/peek-overview/comment/add-comment.tsx @@ -12,8 +12,8 @@ import { SecondaryButton } from "components/ui"; import { Comment } from "types/issue"; // components import { LiteTextEditorWithRef } from "@plane/lite-text-editor"; +import fileService from "services/file.service"; // service -import fileService from "@/services/file.service"; const defaultValues: Partial = { comment_html: "", diff --git a/space/components/issues/peek-overview/comment/comment-detail-card.tsx b/space/components/issues/peek-overview/comment/comment-detail-card.tsx index 6857fca71bf..f6b4d9bf38b 100644 --- a/space/components/issues/peek-overview/comment/comment-detail-card.tsx +++ b/space/components/issues/peek-overview/comment/comment-detail-card.tsx @@ -18,8 +18,8 @@ import { ChatBubbleLeftEllipsisIcon, CheckIcon, XMarkIcon, EllipsisVerticalIcon import { timeAgo } from "helpers/date-time.helper"; // types import { Comment } from "types/issue"; +import fileService from "services/file.service"; // services -import fileService from "@/services/file.service"; type Props = { workspaceSlug: string; diff --git a/web/components/issues/comment/add-comment.tsx b/web/components/issues/comment/add-comment.tsx index 2fb3912d1eb..b5d91adee16 100644 --- a/web/components/issues/comment/add-comment.tsx +++ b/web/components/issues/comment/add-comment.tsx @@ -9,7 +9,7 @@ import { SecondaryButton } from "components/ui"; // types import type { IIssueComment } from "types"; // services -import fileService from "@/services/file.service"; +import fileService from "services/file.service"; const defaultValues: Partial = { access: "INTERNAL", diff --git a/web/components/issues/comment/comment-card.tsx b/web/components/issues/comment/comment-card.tsx index 89a65c2d370..29ba21cd293 100644 --- a/web/components/issues/comment/comment-card.tsx +++ b/web/components/issues/comment/comment-card.tsx @@ -14,8 +14,8 @@ import { LiteTextEditorWithRef, LiteReadOnlyEditorWithRef } from "@plane/lite-te import { timeAgo } from "helpers/date-time.helper"; // types import type { IIssueComment } from "types"; +import fileService from "services/file.service"; // services -import fileService from "@/services/file.service"; type Props = { comment: IIssueComment; diff --git a/web/components/issues/draft-issue-form.tsx b/web/components/issues/draft-issue-form.tsx index 49ef7eb0fdc..aa89a9f5ddc 100644 --- a/web/components/issues/draft-issue-form.tsx +++ b/web/components/issues/draft-issue-form.tsx @@ -31,8 +31,8 @@ import { RichTextEditorWithRef } from "@plane/rich-text-editor"; import { SparklesIcon, XMarkIcon } from "@heroicons/react/24/outline"; // types import type { ICurrentUserResponse, IIssue, ISearchIssueResponse } from "types"; +import fileService from "services/file.service"; // services -import fileService from "@/services/file.service"; const defaultValues: Partial = { project: "", diff --git a/web/components/issues/form.tsx b/web/components/issues/form.tsx index 1c8c39e49e6..cfa300b6caa 100644 --- a/web/components/issues/form.tsx +++ b/web/components/issues/form.tsx @@ -31,8 +31,8 @@ import { RichTextEditorWithRef } from "@plane/rich-text-editor"; import { SparklesIcon, XMarkIcon } from "@heroicons/react/24/outline"; // types import type { ICurrentUserResponse, IIssue, ISearchIssueResponse } from "types"; +import fileService from "services/file.service"; // services -import fileService from "@/services/file.service"; const defaultValues: Partial = { project: "", diff --git a/web/components/pages/create-update-block-inline.tsx b/web/components/pages/create-update-block-inline.tsx index 5f7fa0facbf..49d6fbeedf2 100644 --- a/web/components/pages/create-update-block-inline.tsx +++ b/web/components/pages/create-update-block-inline.tsx @@ -18,7 +18,7 @@ import { ICurrentUserResponse, IPageBlock } from "types"; // fetch-keys import { PAGE_BLOCKS_LIST } from "constants/fetch-keys"; // services -import fileService from "@/services/file.service"; +import fileService from "services/file.service"; type Props = { handleClose: () => void; diff --git a/web/components/pages/single-page-block.tsx b/web/components/pages/single-page-block.tsx index 356186882ef..e738c78e49b 100644 --- a/web/components/pages/single-page-block.tsx +++ b/web/components/pages/single-page-block.tsx @@ -39,7 +39,7 @@ import { copyTextToClipboard } from "helpers/string.helper"; import { ICurrentUserResponse, IIssue, IPageBlock, IProject } from "types"; // fetch-keys import { PAGE_BLOCKS_LIST } from "constants/fetch-keys"; -import fileService from "@/services/file.service"; +import fileService from "services/file.service"; type Props = { block: IPageBlock; diff --git a/web/components/web-view/add-comment.tsx b/web/components/web-view/add-comment.tsx index 4c8ae6fa964..fe7e3eb04d6 100644 --- a/web/components/web-view/add-comment.tsx +++ b/web/components/web-view/add-comment.tsx @@ -15,11 +15,11 @@ import { LiteTextEditorWithRef } from "@plane/lite-text-editor"; import { Send } from "lucide-react"; // ui -import { Icon, SecondaryButton, Tooltip, PrimaryButton } from "components/ui"; +import { PrimaryButton } from "components/ui"; // types import type { IIssueComment } from "types"; -import fileService from "@/services/file.service"; +import fileService from "services/file.service"; const defaultValues: Partial = { access: "INTERNAL", @@ -78,30 +78,30 @@ export const AddComment: React.FC = ({ disabled = false, onSubmit }) => { return (
-
+
+ ( ( - ( -

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

" : commentValue} + customClassName="p-3 min-h-[100px] shadow-sm" + debouncedUpdatesEnabled={false} + onChange={(comment_json: Object, comment_html: string) => onCommentChange(comment_html)} + commentAccessSpecifier={{ accessValue, onAccessChange, showAccessSpecifier, commentAccess }} /> )} /> -
+ )} + /> +
{ const [user, setUser] = useState(); diff --git a/web/pages/m/[workspaceSlug]/editor.tsx b/web/pages/m/[workspaceSlug]/editor.tsx index a79424fb7cd..e385eef9f3f 100644 --- a/web/pages/m/[workspaceSlug]/editor.tsx +++ b/web/pages/m/[workspaceSlug]/editor.tsx @@ -16,8 +16,8 @@ import WebViewLayout from "layouts/web-view-layout"; // components import { RichTextEditor } from "@plane/rich-text-editor"; import { PrimaryButton, Spinner } from "components/ui"; +import fileService from "services/file.service"; // services -import fileService from "@/services/file.service"; const Editor: NextPage = () => { const [isLoading, setIsLoading] = useState(false); From b6f1cb71d855bf6db20838b723b702fb654b730a Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Tue, 10 Oct 2023 18:18:46 +0530 Subject: [PATCH 52/57] changed readme title of core package --- packages/editor/core/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/editor/core/Readme.md b/packages/editor/core/Readme.md index 0cf6aeec329..56d1a502c79 100644 --- a/packages/editor/core/Readme.md +++ b/packages/editor/core/Readme.md @@ -1,4 +1,4 @@ -# README for @plane/editor-core +# @plane/editor-core ## Description From 020e5fe922f8882633869fd3c6b74adc784b7fd4 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Thu, 12 Oct 2023 21:27:20 +0530 Subject: [PATCH 53/57] working tables with row/column selectors --- packages/editor/core/package.json | 8 +- packages/editor/core/src/index.ts | 2 + packages/editor/core/src/styles/editor.css | 6 +- .../src/ui/components/editor-container.tsx | 2 +- .../core/src/ui/components/editor-content.tsx | 4 +- .../editor/core/src/ui/extensions/index.tsx | 18 +- .../ui/extensions/table-new/Table/Table.ts | 336 ++++++++++++ .../extensions/table-new/Table/TableView.ts | 500 ++++++++++++++++++ .../ui/extensions/table-new/Table/icons.ts | 11 + .../ui/extensions/table-new/Table/index.ts | 1 + .../table-new/Table/tableControls.ts | 118 +++++ .../table-new/Table/utilities/createCell.ts | 12 + .../table-new/Table/utilities/createTable.ts | 47 ++ .../deleteTableWhenAllCellsSelected.ts | 41 ++ .../Table/utilities/getTableNodeTypes.ts | 21 + .../Table/utilities/isCellSelection.ts | 5 + .../table-new/TableCell/TableCell.ts | 55 ++ .../extensions/table-new/TableCell/index.ts | 1 + .../table-new/TableHeader/TableHeader.ts | 54 ++ .../extensions/table-new/TableHeader/index.ts | 1 + .../extensions/table-new/TableRow/TableRow.ts | 31 ++ .../ui/extensions/table-new/TableRow/index.ts | 1 + .../core/src/ui/extensions/table/index.ts | 9 - .../src/ui/extensions/table/table-cell.ts | 32 -- .../src/ui/extensions/table/table-header.ts | 7 - .../core/src/ui/read-only/extensions.tsx | 16 +- .../issues/comment/comment-card.tsx | 2 +- web/pages/_app.tsx | 1 + web/styles/tables.css | 200 +++++++ yarn.lock | 70 +-- 30 files changed, 1490 insertions(+), 122 deletions(-) create mode 100644 packages/editor/core/src/ui/extensions/table-new/Table/Table.ts create mode 100644 packages/editor/core/src/ui/extensions/table-new/Table/TableView.ts create mode 100644 packages/editor/core/src/ui/extensions/table-new/Table/icons.ts create mode 100644 packages/editor/core/src/ui/extensions/table-new/Table/index.ts create mode 100644 packages/editor/core/src/ui/extensions/table-new/Table/tableControls.ts create mode 100644 packages/editor/core/src/ui/extensions/table-new/Table/utilities/createCell.ts create mode 100644 packages/editor/core/src/ui/extensions/table-new/Table/utilities/createTable.ts create mode 100644 packages/editor/core/src/ui/extensions/table-new/Table/utilities/deleteTableWhenAllCellsSelected.ts create mode 100644 packages/editor/core/src/ui/extensions/table-new/Table/utilities/getTableNodeTypes.ts create mode 100644 packages/editor/core/src/ui/extensions/table-new/Table/utilities/isCellSelection.ts create mode 100644 packages/editor/core/src/ui/extensions/table-new/TableCell/TableCell.ts create mode 100644 packages/editor/core/src/ui/extensions/table-new/TableCell/index.ts create mode 100644 packages/editor/core/src/ui/extensions/table-new/TableHeader/TableHeader.ts create mode 100644 packages/editor/core/src/ui/extensions/table-new/TableHeader/index.ts create mode 100644 packages/editor/core/src/ui/extensions/table-new/TableRow/TableRow.ts create mode 100644 packages/editor/core/src/ui/extensions/table-new/TableRow/index.ts delete mode 100644 packages/editor/core/src/ui/extensions/table/index.ts delete mode 100644 packages/editor/core/src/ui/extensions/table/table-cell.ts delete mode 100644 packages/editor/core/src/ui/extensions/table/table-header.ts create mode 100644 web/styles/tables.css diff --git a/packages/editor/core/package.json b/packages/editor/core/package.json index 78bf59db767..86921af0cd8 100644 --- a/packages/editor/core/package.json +++ b/packages/editor/core/package.json @@ -32,10 +32,6 @@ "@tiptap/extension-color": "^2.1.11", "@tiptap/extension-image": "^2.1.7", "@tiptap/extension-link": "^2.1.7", - "@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.1.7", "@tiptap/extension-task-list": "^2.1.7", "@tiptap/extension-text-style": "^2.1.11", @@ -56,7 +52,9 @@ "tailwind-merge": "^1.14.0", "tippy.js": "^6.3.7", "tiptap-markdown": "^0.8.2", - "use-debounce": "^9.0.4" + "use-debounce": "^9.0.4", + "@tiptap/prosemirror-tables": "^1.1.4", + "jsx-dom-cjs": "^8.0.3" }, "devDependencies": { "eslint": "^7.32.0", diff --git a/packages/editor/core/src/index.ts b/packages/editor/core/src/index.ts index 590b17172f5..6268323e55a 100644 --- a/packages/editor/core/src/index.ts +++ b/packages/editor/core/src/index.ts @@ -2,6 +2,8 @@ // import "./styles/tailwind.css"; // import "./styles/editor.css"; +export * from "./ui/extensions/table-new/Table"; + // utils export * from "./lib/utils"; export { startImageUpload } from "./ui/plugins/upload-image"; diff --git a/packages/editor/core/src/styles/editor.css b/packages/editor/core/src/styles/editor.css index 85d881eeb46..9987c5f067c 100644 --- a/packages/editor/core/src/styles/editor.css +++ b/packages/editor/core/src/styles/editor.css @@ -212,9 +212,9 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p { } } -.tableWrapper { - overflow-x: auto; -} +/* .tableWrapper { */ +/* overflow-x: auto; */ +/* } */ .resize-cursor { cursor: ew-resize; diff --git a/packages/editor/core/src/ui/components/editor-container.tsx b/packages/editor/core/src/ui/components/editor-container.tsx index 8de6298b57e..bb35fef681a 100644 --- a/packages/editor/core/src/ui/components/editor-container.tsx +++ b/packages/editor/core/src/ui/components/editor-container.tsx @@ -13,7 +13,7 @@ export const EditorContainer = ({ editor, editorClassNames, children }: EditorCo onClick={() => { editor?.chain().focus().run(); }} - className={`cursor-text ${editorClassNames}`} + className={`cursor-text editorContainer ${editorClassNames}`} > {children}
diff --git a/packages/editor/core/src/ui/components/editor-content.tsx b/packages/editor/core/src/ui/components/editor-content.tsx index 0675a583437..11468e75737 100644 --- a/packages/editor/core/src/ui/components/editor-content.tsx +++ b/packages/editor/core/src/ui/components/editor-content.tsx @@ -10,10 +10,10 @@ interface EditorContentProps { } export const EditorContentWrapper = ({ editor, editorContentCustomClassNames = '', children }: EditorContentProps) => ( -
+
{/* @ts-ignore */} - + {/* */} {editor?.isActive("image") && } {children}
diff --git a/packages/editor/core/src/ui/extensions/index.tsx b/packages/editor/core/src/ui/extensions/index.tsx index 62d53e0e1dd..3c394205d31 100644 --- a/packages/editor/core/src/ui/extensions/index.tsx +++ b/packages/editor/core/src/ui/extensions/index.tsx @@ -8,15 +8,19 @@ import TaskList from "@tiptap/extension-task-list"; import { Markdown } from "tiptap-markdown"; import Gapcursor from "@tiptap/extension-gapcursor"; -import { CustomTableCell } from "./table/table-cell"; -import { Table } from "./table"; -import { TableHeader } from "./table/table-header"; -import { TableRow } from "@tiptap/extension-table-row"; +// import { CustomTableCell } from "./table/table-cell"; +// import { Table } from "./table"; +// import { TableHeader } from "./table/table-header"; +// import { TableRow } from "@tiptap/extension-table-row"; import ImageExtension from "./image"; import { DeleteImage } from "../../types/delete-image"; import { isValidHttpUrl } from "../../lib/utils"; +import Table from "./table-new/Table"; +import TableHeader from "./table-new/TableHeader"; +import TableCell from "./table-new/TableCell"; +import TableRow from "./table-new/TableRow"; export const CoreEditorExtensions = ( @@ -92,6 +96,10 @@ export const CoreEditorExtensions = ( }), Table, TableHeader, - CustomTableCell, + TableCell, TableRow, + // Table, + // TableHeader, + // CustomTableCell, + // TableRow, ]; diff --git a/packages/editor/core/src/ui/extensions/table-new/Table/Table.ts b/packages/editor/core/src/ui/extensions/table-new/Table/Table.ts new file mode 100644 index 00000000000..1bded42af57 --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table-new/Table/Table.ts @@ -0,0 +1,336 @@ +import { TextSelection } from "@tiptap/pm/state" + +import { callOrReturn, getExtensionField, mergeAttributes, Node, ParentConfig } from "@tiptap/core" +import { + addColumnAfter, + addColumnBefore, + addRowAfter, + addRowBefore, + CellSelection, + columnResizing, + deleteColumn, + deleteRow, + deleteTable, + fixTables, + goToNextCell, + mergeCells, + setCellAttr, + splitCell, + tableEditing, + toggleHeader, + toggleHeaderCell +} from "@tiptap/prosemirror-tables" + +import { tableControls } from "./tableControls" +import { TableView } from "./TableView" +import { createTable } from "./utilities/createTable" +import { deleteTableWhenAllCellsSelected } from "./utilities/deleteTableWhenAllCellsSelected" + +/** + * Extension based on: + * - Tiptap TableExtension (https://github.com/ueberdosis/tiptap/blob/main/packages/extension-table/src/table.ts) + */ + +export interface TableOptions { + HTMLAttributes: Record + resizable: boolean + handleWidth: number + cellMinWidth: number + lastColumnResizable: boolean + allowTableNodeSelection: boolean +} + +declare module "@tiptap/core" { + interface Commands { + table: { + insertTable: (options?: { + rows?: number + cols?: number + withHeaderRow?: boolean + }) => ReturnType + addColumnBefore: () => ReturnType + addColumnAfter: () => ReturnType + deleteColumn: () => ReturnType + addRowBefore: () => ReturnType + addRowAfter: () => ReturnType + deleteRow: () => ReturnType + deleteTable: () => ReturnType + mergeCells: () => ReturnType + splitCell: () => ReturnType + toggleHeaderColumn: () => ReturnType + toggleHeaderRow: () => ReturnType + toggleHeaderCell: () => ReturnType + mergeOrSplit: () => ReturnType + setCellAttribute: (name: string, value: any) => ReturnType + goToNextCell: () => ReturnType + goToPreviousCell: () => ReturnType + fixTables: () => ReturnType + setCellSelection: (position: { + anchorCell: number + headCell?: number + }) => ReturnType + } + } + + interface NodeConfig { + /** + * Table Role + */ + tableRole?: + | string + | ((this: { + name: string + options: Options + storage: Storage + parent: ParentConfig>["tableRole"] + }) => string) + } +} + +export default Node.create({ + name: "table", + + addOptions() { + return { + HTMLAttributes: {}, + resizable: true, + handleWidth: 5, + cellMinWidth: 100, + lastColumnResizable: true, + allowTableNodeSelection: true + } + }, + + content: "tableRow+", + + tableRole: "table", + + isolating: true, + + group: "block", + + allowGapCursor: false, + + parseHTML() { + return [{ tag: "table" }] + }, + + renderHTML({ HTMLAttributes }) { + return [ + "table", + mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), + ["tbody", 0] + ] + }, + + addCommands() { + return { + insertTable: + ({ rows = 3, cols = 3, withHeaderRow = true} = {}) => + ({ tr, dispatch, editor }) => { + const node = createTable( + editor.schema, + rows, + cols, + withHeaderRow + ) + + if (dispatch) { + const offset = tr.selection.anchor + 1 + + tr.replaceSelectionWith(node) + .scrollIntoView() + .setSelection( + TextSelection.near(tr.doc.resolve(offset)) + ) + } + + return true + }, + addColumnBefore: + () => + ({ state, dispatch }) => { + return addColumnBefore(state, dispatch) + }, + addColumnAfter: + () => + ({ state, dispatch }) => { + return addColumnAfter(state, dispatch) + }, + deleteColumn: + () => + ({ state, dispatch }) => { + return deleteColumn(state, dispatch) + }, + addRowBefore: + () => + ({ state, dispatch }) => { + return addRowBefore(state, dispatch) + }, + addRowAfter: + () => + ({ state, dispatch }) => { + return addRowAfter(state, dispatch) + }, + deleteRow: + () => + ({ state, dispatch }) => { + return deleteRow(state, dispatch) + }, + deleteTable: + () => + ({ state, dispatch }) => { + return deleteTable(state, dispatch) + }, + mergeCells: + () => + ({ state, dispatch }) => { + return mergeCells(state, dispatch) + }, + splitCell: + () => + ({ state, dispatch }) => { + return splitCell(state, dispatch) + }, + toggleHeaderColumn: + () => + ({ state, dispatch }) => { + return toggleHeader("column")(state, dispatch) + }, + toggleHeaderRow: + () => + ({ state, dispatch }) => { + return toggleHeader("row")(state, dispatch) + }, + toggleHeaderCell: + () => + ({ state, dispatch }) => { + return toggleHeaderCell(state, dispatch) + }, + mergeOrSplit: + () => + ({ state, dispatch }) => { + if (mergeCells(state, dispatch)) { + return true + } + + return splitCell(state, dispatch) + }, + setCellAttribute: + (name, value) => + ({ state, dispatch }) => { + return setCellAttr(name, value)(state, dispatch) + }, + goToNextCell: + () => + ({ state, dispatch }) => { + return goToNextCell(1)(state, dispatch) + }, + goToPreviousCell: + () => + ({ state, dispatch }) => { + return goToNextCell(-1)(state, dispatch) + }, + fixTables: + () => + ({ state, dispatch }) => { + if (dispatch) { + fixTables(state) + } + + return true + }, + setCellSelection: + (position) => + ({ tr, dispatch }) => { + if (dispatch) { + const selection = CellSelection.create( + tr.doc, + position.anchorCell, + position.headCell + ) + + // @ts-ignore + tr.setSelection(selection) + } + + return true + } + } + }, + + addKeyboardShortcuts() { + return { + Tab: () => { + if (this.editor.commands.goToNextCell()) { + return true + } + + if (!this.editor.can().addRowAfter()) { + return false + } + + return this.editor.chain().addRowAfter().goToNextCell().run() + }, + "Shift-Tab": () => this.editor.commands.goToPreviousCell(), + Backspace: deleteTableWhenAllCellsSelected, + "Mod-Backspace": deleteTableWhenAllCellsSelected, + Delete: deleteTableWhenAllCellsSelected, + "Mod-Delete": deleteTableWhenAllCellsSelected + } + }, + + addNodeView() { + return ({ editor, getPos, node, decorations }) => { + const { cellMinWidth } = this.options + + return new TableView( + node, + cellMinWidth, + decorations, + editor, + getPos as () => number + ) + } + }, + + addProseMirrorPlugins() { + const isResizable = this.options.resizable && this.editor.isEditable + + const plugins = [ + tableEditing({ + allowTableNodeSelection: this.options.allowTableNodeSelection + }), + tableControls() + ] + + if (isResizable) { + plugins.unshift( + columnResizing({ + handleWidth: this.options.handleWidth, + cellMinWidth: this.options.cellMinWidth, + // View: TableView, + + // @ts-ignore + lastColumnResizable: this.options.lastColumnResizable + }) + ) + } + + return plugins + }, + + extendNodeSchema(extension) { + const context = { + name: extension.name, + options: extension.options, + storage: extension.storage + } + + return { + tableRole: callOrReturn( + getExtensionField(extension, "tableRole", context) + ) + } + } +}) diff --git a/packages/editor/core/src/ui/extensions/table-new/Table/TableView.ts b/packages/editor/core/src/ui/extensions/table-new/Table/TableView.ts new file mode 100644 index 00000000000..c11a69e31e2 --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table-new/Table/TableView.ts @@ -0,0 +1,500 @@ +import { h } from "jsx-dom-cjs" +import { Node as ProseMirrorNode } from "@tiptap/pm/model" +import { Decoration, NodeView } from "@tiptap/pm/view" +import tippy, { Instance, Props, Tippy } from "tippy.js" + +import { Editor } from "@tiptap/core" +import { + CellSelection, + TableMap, + updateColumnsOnResize +} from "@tiptap/prosemirror-tables" + +import icons from "./icons" + +export function updateColumns( + node: ProseMirrorNode, + colgroup: HTMLElement, + table: HTMLElement, + cellMinWidth: number, + overrideCol?: number, + overrideValue?: any +) { + let totalWidth = 0 + let fixedWidth = true + let nextDOM = colgroup.firstChild as HTMLElement + const row = node.firstChild + + if (!row) return + + for (let i = 0, col = 0; i < row.childCount; i += 1) { + const { colspan, colwidth } = row.child(i).attrs + + for (let j = 0; j < colspan; j += 1, col += 1) { + const hasWidth = + overrideCol === col ? overrideValue : colwidth && colwidth[j] + const cssWidth = hasWidth ? `${hasWidth}px` : "" + + totalWidth += hasWidth || cellMinWidth + + if (!hasWidth) { + fixedWidth = false + } + + if (!nextDOM) { + colgroup.appendChild( + document.createElement("col") + ).style.width = cssWidth + } else { + if (nextDOM.style.width !== cssWidth) { + nextDOM.style.width = cssWidth + } + + nextDOM = nextDOM.nextSibling as HTMLElement + } + } + } + + while (nextDOM) { + const after = nextDOM.nextSibling + + nextDOM.parentNode?.removeChild(nextDOM) + nextDOM = after as HTMLElement + } + + if (fixedWidth) { + table.style.width = `${totalWidth}px` + table.style.minWidth = "" + } else { + table.style.width = "" + table.style.minWidth = `${totalWidth}px` + } +} + +const defaultTippyOptions: Partial = { + allowHTML: true, + arrow: false, + trigger: "click", + animation: "scale-subtle", + theme: "light-border no-padding", + interactive: true, + hideOnClick: true, + placement: "right" +} + +function setCellsBackgroundColor(editor: Editor, backgroundColor) { + return editor + .chain() + .focus() + .updateAttributes("tableCell", { + background: backgroundColor + }) + .updateAttributes("tableHeader", { + background: backgroundColor + }) + .run() +} + +const columnsToolboxItems = [ + { + label: "Add Column Before", + icon: icons.insertColumnLeft, + action: ({ editor }: { editor: Editor }) => editor.chain().focus().addColumnBefore().run() + }, + { + label: "Add Column After", + icon: icons.insertColumnRight, + action: ({ editor }: { editor: Editor }) => editor.chain().focus().addColumnAfter().run() + }, + { + label: "Pick Column Color", + icon: icons.colorPicker, + action: ({ editor, triggerButton, controlsContainer }) => { + createColorPickerToolbox({ + triggerButton, + tippyOptions: { + appendTo: controlsContainer + }, + onSelectColor: (color) => setCellsBackgroundColor(editor, color) + }) + } + }, + { + label: "Delete Column", + icon: icons.deleteColumn, + action: ({ editor }: { editor: Editor }) => editor.chain().focus().deleteColumn().run() + } +] + +const rowsToolboxItems = [ + { + label: "Add Row Above", + icon: icons.insertRowTop, + action: ({ editor }: { editor: Editor }) => editor.chain().focus().addRowBefore().run() + }, + { + label: "Add Row Below", + icon: icons.insertRowBottom, + action: ({ editor }: { editor: Editor }) => editor.chain().focus().addRowAfter().run() + }, + { + label: "Pick a Color", + icon: icons.colorPicker, + action: ({ editor, triggerButton, controlsContainer }: { editor: Editor, triggerButton: HTMLElement, controlsContainer: any }) => { + createColorPickerToolbox({ + triggerButton, + tippyOptions: { + appendTo: controlsContainer + }, + onSelectColor: (color) => setCellsBackgroundColor(editor, color) + }) + } + }, + { + label: "Delete Row", + icon: icons.deleteRow, + action: ({ editor }: { editor: Editor }) => editor.chain().focus().deleteRow().run() + } +] + +function createToolbox({ + triggerButton, + items, + tippyOptions, + onClickItem +}: { triggerButton: HTMLElement, items: { icon: string, label: string }[], tippyOptions: any, onClickItem: any }): Instance { + const toolbox = tippy(triggerButton, { + content: h( + "div", + { className: "tableToolbox" }, + items.map((item) => + h( + "div", + { + className: "toolboxItem", + onClick() { + onClickItem(item) + } + }, + [ + h("div", { + className: "iconContainer", + innerHTML: item.icon + }), + h("div", { className: "label" }, item.label) + ] + ) + ) + ), + ...tippyOptions + }) + + return Array.isArray(toolbox) ? toolbox[0] : toolbox +} + +function createColorPickerToolbox({ + triggerButton, + tippyOptions, + onSelectColor = () => { } +}: { + triggerButton: HTMLElement + tippyOptions: Partial + onSelectColor?: (color: string) => void +}) { + const items = { + "Fond par défault": "#ffffff", + "Fond gris clair": "#e7f3f8", + "Fond gris foncé": "#c7d2d7", + "Fond bleu": "#e7f3f8", + "Fond rouge": "#ffc4c7", + "Fond jaune": "#fbf3db" + } + + const colorPicker = tippy(triggerButton, { + ...defaultTippyOptions, + content: h( + "div", + { className: "tableColorPickerToolbox" }, + Object.entries(items).map(([key, value]) => + h( + "div", + { + className: "toolboxItem", + onClick: () => { + onSelectColor(value) + colorPicker.hide() + } + }, + [ + h("div", { + className: "colorContainer", + style: { + backgroundColor: value + } + }), + h( + "div", + { + className: "label" + }, + key + ) + ] + ) + ) + ), + onHidden: (instance) => { + instance.destroy() + }, + showOnCreate: true, + ...tippyOptions + }) + + return colorPicker +} + +export class TableView implements NodeView { + node: ProseMirrorNode + cellMinWidth: number + decorations: Decoration[] + editor: Editor + getPos: () => number + hoveredCell + map: TableMap + root: HTMLElement + table: HTMLElement + colgroup: HTMLElement + tbody: HTMLElement + rowsControl: HTMLElement + columnsControl: HTMLElement + columnsToolbox: Instance + rowsToolbox: Instance + controls: HTMLElement + + get dom() { + return this.root + } + + get contentDOM() { + return this.tbody + } + + constructor( + node: ProseMirrorNode, + cellMinWidth: number, + decorations: Decoration[], + editor: Editor, + getPos: () => number + ) { + this.node = node + this.cellMinWidth = cellMinWidth + this.decorations = decorations + this.editor = editor + this.getPos = getPos + this.hoveredCell = null + this.map = TableMap.get(node) + + /** + * DOM + */ + + // Controllers + if (editor.isEditable) { + this.rowsControl = h( + "div", + { className: "rowsControl" }, + h("button", { + onClick: () => this.selectRow() + }) + ) + + this.columnsControl = h( + "div", + { className: "columnsControl" }, + h("button", { + onClick: () => this.selectColumn() + }) + ) + + this.controls = h( + "div", + { className: "tableControls", contentEditable: "false" }, + this.rowsControl, + this.columnsControl + ) + + this.columnsToolbox = createToolbox({ + triggerButton: this.columnsControl.querySelector("button"), + items: columnsToolboxItems, + tippyOptions: { + ...defaultTippyOptions, + appendTo: this.controls + }, + onClickItem: (item) => { + item.action({ + editor: this.editor, + triggerButton: this.columnsControl.firstElementChild, + controlsContainer: this.controls + }) + this.columnsToolbox.hide() + } + }) + + this.rowsToolbox = createToolbox({ + triggerButton: this.rowsControl.firstElementChild, + items: rowsToolboxItems, + tippyOptions: { + ...defaultTippyOptions, + appendTo: this.controls + }, + onClickItem: (item) => { + item.action({ + editor: this.editor, + triggerButton: this.rowsControl.firstElementChild, + controlsContainer: this.controls + }) + this.rowsToolbox.hide() + } + }) + } + + // Table + + this.colgroup = h( + "colgroup", + null, + Array.from({ length: this.map.width }, () => 1).map(() => h("col")) + ) + this.tbody = h("tbody") + this.table = h("table", null, this.colgroup, this.tbody) + + this.root = h( + "div", + { + className: "tableWrapper controls--disabled" + }, + this.controls, + this.table + ) + + this.render() + } + + update(node: ProseMirrorNode, decorations) { + if (node.type !== this.node.type) { + return false + } + + this.node = node + this.decorations = decorations + this.map = TableMap.get(this.node) + + if (this.editor.isEditable) { + this.updateControls() + } + + this.render() + + return true + } + + render() { + if (this.colgroup.children.length !== this.map.width) { + const cols = Array.from({ length: this.map.width }, () => 1).map( + () => h("col") + ) + this.colgroup.replaceChildren(...cols) + } + + updateColumnsOnResize( + this.node, + this.colgroup, + this.table, + this.cellMinWidth + ) + } + + ignoreMutation() { + return true + } + + updateControls() { + const { hoveredTable: table, hoveredCell: cell } = Object.values( + this.decorations + ).reduce((acc, curr) => { + if (curr.spec.hoveredCell !== undefined) { + acc["hoveredCell"] = curr.spec.hoveredCell + } + + if (curr.spec.hoveredTable !== undefined) { + acc["hoveredTable"] = curr.spec.hoveredTable + } + return acc + }, {}) as any + + if (table === undefined || cell === undefined) { + return this.root.classList.add("controls--disabled") + } + + this.root.classList.remove("controls--disabled") + this.hoveredCell = cell + + const cellDom = this.editor.view.nodeDOM(cell.pos) as HTMLElement + + const tableRect = this.table.getBoundingClientRect() + const cellRect = cellDom.getBoundingClientRect() + + this.columnsControl.style.left = `${cellRect.left - + tableRect.left - + this.table.parentElement!.scrollLeft + }px` + this.columnsControl.style.width = `${cellRect.width}px` + + this.rowsControl.style.top = `${cellRect.top - tableRect.top}px` + this.rowsControl.style.height = `${cellRect.height}px` + } + + selectColumn() { + if (!this.hoveredCell) return + + const colIndex = this.map.colCount( + this.hoveredCell.pos - (this.getPos() + 1) + ) + const anchorCellPos = this.hoveredCell.pos + const headCellPos = + this.map.map[colIndex + this.map.width * (this.map.height - 1)] + + (this.getPos() + 1) + + const cellSelection = CellSelection.create( + this.editor.view.state.doc, + anchorCellPos, + headCellPos + ) + this.editor.view.dispatch( + // @ts-ignore + this.editor.state.tr.setSelection(cellSelection) + ) + } + + selectRow() { + if (!this.hoveredCell) return + + const anchorCellPos = this.hoveredCell.pos + const anchorCellIndex = this.map.map.indexOf( + anchorCellPos - (this.getPos() + 1) + ) + const headCellPos = + this.map.map[anchorCellIndex + (this.map.width - 1)] + + (this.getPos() + 1) + + const cellSelection = CellSelection.create( + this.editor.state.doc, + anchorCellPos, + headCellPos + ) + this.editor.view.dispatch( + // @ts-ignore + this.editor.view.state.tr.setSelection(cellSelection) + ) + } +} diff --git a/packages/editor/core/src/ui/extensions/table-new/Table/icons.ts b/packages/editor/core/src/ui/extensions/table-new/Table/icons.ts new file mode 100644 index 00000000000..d24209c8ae1 --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table-new/Table/icons.ts @@ -0,0 +1,11 @@ +const icons = { + insertColumnLeft: ``, + insertColumnRight: ``, + insertRowTop: ``, + insertRowBottom: ``, + colorPicker: ``, + deleteColumn: ``, + deleteRow: `` +} + +export default icons diff --git a/packages/editor/core/src/ui/extensions/table-new/Table/index.ts b/packages/editor/core/src/ui/extensions/table-new/Table/index.ts new file mode 100644 index 00000000000..ccdae7fd2b7 --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table-new/Table/index.ts @@ -0,0 +1 @@ +export { default as default } from "./Table" diff --git a/packages/editor/core/src/ui/extensions/table-new/Table/tableControls.ts b/packages/editor/core/src/ui/extensions/table-new/Table/tableControls.ts new file mode 100644 index 00000000000..afcb9103e9f --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table-new/Table/tableControls.ts @@ -0,0 +1,118 @@ +import { Plugin, PluginKey, TextSelection } from "@tiptap/pm/state" +import { findParentNode } from "@tiptap/core" +import { DecorationSet, Decoration } from "@tiptap/pm/view" + +const key = new PluginKey("tableControls") + +export function tableControls() { + return new Plugin({ + key, + state: { + init() { + return new TableControlsState() + }, + apply(tr, prev) { + return prev.apply(tr) + } + }, + props: { + handleDOMEvents: { + mousemove: (view, event) => { + const pluginState = key.getState(view.state) + + if ( + !(event.target as HTMLElement).closest( + ".tableWrapper" + ) && + pluginState.values.hoveredTable + ) { + return view.dispatch( + view.state.tr.setMeta(key, { + setHoveredTable: null, + setHoveredCell: null + }) + ) + } + + const pos = view.posAtCoords({ + left: event.clientX, + top: event.clientY + }) + + if (!pos) return + + const table = findParentNode( + (node) => node.type.name === "table" + )(TextSelection.create(view.state.doc, pos.pos)) + const cell = findParentNode( + (node) => + node.type.name === "tableCell" || + node.type.name === "tableHeader" + )(TextSelection.create(view.state.doc, pos.pos)) + + if (!table || !cell) return + + if (pluginState.values.hoveredCell?.pos !== cell.pos) { + return view.dispatch( + view.state.tr.setMeta(key, { + setHoveredTable: table, + setHoveredCell: cell + }) + ) + } + } + }, + decorations: (state) => { + const pluginState = key.getState(state) + if (!pluginState) { + return null + } + + const { hoveredTable, hoveredCell } = pluginState.values + if (hoveredTable) { + const decorations = [ + Decoration.node( + hoveredTable.pos, + hoveredTable.pos + hoveredTable.node.nodeSize, + {}, + { + hoveredTable, + hoveredCell + } + ) + ] + + return DecorationSet.create(state.doc, decorations) + } + + return null + } + } + }) +} + +class TableControlsState { + values + + constructor(props = {}) { + this.values = { + hoveredTable: null, + hoveredCell: null, + ...props + } + } + + apply(tr: any) { + const actions = tr.getMeta(key) + + if (actions?.setHoveredTable !== undefined) { + this.values.hoveredTable = actions.setHoveredTable + } + + if (actions?.setHoveredCell !== undefined) { + this.values.hoveredCell = actions.setHoveredCell + } + + return this + } +} diff --git a/packages/editor/core/src/ui/extensions/table-new/Table/utilities/createCell.ts b/packages/editor/core/src/ui/extensions/table-new/Table/utilities/createCell.ts new file mode 100644 index 00000000000..a3d7f2da814 --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table-new/Table/utilities/createCell.ts @@ -0,0 +1,12 @@ +import { Fragment, Node as ProsemirrorNode, NodeType } from "prosemirror-model" + +export function createCell( + cellType: NodeType, + cellContent?: Fragment | ProsemirrorNode | Array +): ProsemirrorNode | null | undefined { + if (cellContent) { + return cellType.createChecked(null, cellContent) + } + + return cellType.createAndFill() +} diff --git a/packages/editor/core/src/ui/extensions/table-new/Table/utilities/createTable.ts b/packages/editor/core/src/ui/extensions/table-new/Table/utilities/createTable.ts new file mode 100644 index 00000000000..c59aadac1e2 --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table-new/Table/utilities/createTable.ts @@ -0,0 +1,47 @@ +import { Fragment, Node as ProsemirrorNode, Schema } from "@tiptap/pm/model" + +import { ReactNodeViewRenderer } from "@tiptap/react" + +import { createCell } from "./createCell" +import { getTableNodeTypes } from "./getTableNodeTypes" + +export function createTable( + schema: Schema, + rowsCount: number, + colsCount: number, + withHeaderRow: boolean, + cellContent?: Fragment | ProsemirrorNode | Array +): ProsemirrorNode { + const types = getTableNodeTypes(schema) + const headerCells: ProsemirrorNode[] = [] + const cells: ProsemirrorNode[] = [] + + for (let index = 0; index < colsCount; index += 1) { + const cell = createCell(types.cell, cellContent) + + if (cell) { + cells.push(cell) + } + + if (withHeaderRow) { + const headerCell = createCell(types.header_cell, cellContent) + + if (headerCell) { + headerCells.push(headerCell) + } + } + } + + const rows: ProsemirrorNode[] = [] + + for (let index = 0; index < rowsCount; index += 1) { + rows.push( + types.row.createChecked( + null, + withHeaderRow && index === 0 ? headerCells : cells + ) + ) + } + + return types.table.createChecked(null, rows) +} diff --git a/packages/editor/core/src/ui/extensions/table-new/Table/utilities/deleteTableWhenAllCellsSelected.ts b/packages/editor/core/src/ui/extensions/table-new/Table/utilities/deleteTableWhenAllCellsSelected.ts new file mode 100644 index 00000000000..b76cdca5d9a --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table-new/Table/utilities/deleteTableWhenAllCellsSelected.ts @@ -0,0 +1,41 @@ +import { findParentNodeClosestToPos, KeyboardShortcutCommand } from "@tiptap/core" + +import { isCellSelection } from "./isCellSelection" + +export const deleteTableWhenAllCellsSelected: KeyboardShortcutCommand = ({ + editor +}) => { + const { selection } = editor.state + + if (!isCellSelection(selection)) { + return false + } + + let cellCount = 0 + const table = findParentNodeClosestToPos( + selection.ranges[0].$from, + (node) => { + return node.type.name === "table" + } + ) + + table?.node.descendants((node) => { + if (node.type.name === "table") { + return false + } + + if (["tableCell", "tableHeader"].includes(node.type.name)) { + cellCount += 1 + } + }) + + const allCellsSelected = cellCount === selection.ranges.length + + if (!allCellsSelected) { + return false + } + + editor.commands.deleteTable() + + return true +} diff --git a/packages/editor/core/src/ui/extensions/table-new/Table/utilities/getTableNodeTypes.ts b/packages/editor/core/src/ui/extensions/table-new/Table/utilities/getTableNodeTypes.ts new file mode 100644 index 00000000000..293878cb0a4 --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table-new/Table/utilities/getTableNodeTypes.ts @@ -0,0 +1,21 @@ +import { NodeType, Schema } from "prosemirror-model" + +export function getTableNodeTypes(schema: Schema): { [key: string]: NodeType } { + if (schema.cached.tableNodeTypes) { + return schema.cached.tableNodeTypes + } + + const roles: { [key: string]: NodeType } = {} + + Object.keys(schema.nodes).forEach((type) => { + const nodeType = schema.nodes[type] + + if (nodeType.spec.tableRole) { + roles[nodeType.spec.tableRole] = nodeType + } + }) + + schema.cached.tableNodeTypes = roles + + return roles +} diff --git a/packages/editor/core/src/ui/extensions/table-new/Table/utilities/isCellSelection.ts b/packages/editor/core/src/ui/extensions/table-new/Table/utilities/isCellSelection.ts new file mode 100644 index 00000000000..3c36bf055e2 --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table-new/Table/utilities/isCellSelection.ts @@ -0,0 +1,5 @@ +import { CellSelection } from "@tiptap/prosemirror-tables" + +export function isCellSelection(value: unknown): value is CellSelection { + return value instanceof CellSelection +} diff --git a/packages/editor/core/src/ui/extensions/table-new/TableCell/TableCell.ts b/packages/editor/core/src/ui/extensions/table-new/TableCell/TableCell.ts new file mode 100644 index 00000000000..dfa25c94d3c --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table-new/TableCell/TableCell.ts @@ -0,0 +1,55 @@ +import { mergeAttributes, Node } from "@tiptap/core" + +export interface TableCellOptions { + HTMLAttributes: Record +} + +export default Node.create({ + name: "tableCell", + + addOptions() { + return { + HTMLAttributes: {} + } + }, + + content: "paragraph+", + + addAttributes() { + return { + colspan: { + default: 1 + }, + rowspan: { + default: 1 + }, + colwidth: { + default: null, + parseHTML: (element) => { + const colwidth = element.getAttribute("colwidth") + const value = colwidth ? [parseInt(colwidth, 10)] : null + + return value + } + } + } + }, + + tableRole: "cell", + + isolating: true, + + parseHTML() { + return [{ tag: "td" }] + }, + + renderHTML({ node, HTMLAttributes }) { + return [ + "td", + mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { + style: `background-color: ${node.attrs.background}` + }), + 0 + ] + } +}) diff --git a/packages/editor/core/src/ui/extensions/table-new/TableCell/index.ts b/packages/editor/core/src/ui/extensions/table-new/TableCell/index.ts new file mode 100644 index 00000000000..e4acbea9ef7 --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table-new/TableCell/index.ts @@ -0,0 +1 @@ +export { default as default } from "./TableCell" diff --git a/packages/editor/core/src/ui/extensions/table-new/TableHeader/TableHeader.ts b/packages/editor/core/src/ui/extensions/table-new/TableHeader/TableHeader.ts new file mode 100644 index 00000000000..8e8d0f1d4ed --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table-new/TableHeader/TableHeader.ts @@ -0,0 +1,54 @@ +import { mergeAttributes, Node } from "@tiptap/core" + +export interface TableHeaderOptions { + HTMLAttributes: Record +} +export default Node.create({ + name: "tableHeader", + + addOptions() { + return { + HTMLAttributes: {} + } + }, + + content: "paragraph+", + + addAttributes() { + return { + colspan: { + default: 1 + }, + rowspan: { + default: 1 + }, + colwidth: { + default: null, + parseHTML: (element) => { + const colwidth = element.getAttribute("colwidth") + const value = colwidth ? [parseInt(colwidth, 10)] : null + + return value + } + } + } + }, + + tableRole: "header_cell", + + isolating: true, + + parseHTML() { + return [{ tag: "th" }] + }, + + renderHTML({ node, HTMLAttributes }) { + return [ + "th", + mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { + style: `background-color: ${node.attrs.background}` + }), + 0 + ] + } +}) diff --git a/packages/editor/core/src/ui/extensions/table-new/TableHeader/index.ts b/packages/editor/core/src/ui/extensions/table-new/TableHeader/index.ts new file mode 100644 index 00000000000..f260509cfa0 --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table-new/TableHeader/index.ts @@ -0,0 +1 @@ +export { default as default } from "./TableHeader" diff --git a/packages/editor/core/src/ui/extensions/table-new/TableRow/TableRow.ts b/packages/editor/core/src/ui/extensions/table-new/TableRow/TableRow.ts new file mode 100644 index 00000000000..e922e7fa197 --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table-new/TableRow/TableRow.ts @@ -0,0 +1,31 @@ +import { mergeAttributes, Node } from "@tiptap/core" + +export interface TableRowOptions { + HTMLAttributes: Record +} + +export default Node.create({ + name: "tableRow", + + addOptions() { + return { + HTMLAttributes: {} + } + }, + + content: "(tableCell | tableHeader)*", + + tableRole: "row", + + parseHTML() { + return [{ tag: "tr" }] + }, + + renderHTML({ HTMLAttributes }) { + return [ + "tr", + mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), + 0 + ] + } +}) diff --git a/packages/editor/core/src/ui/extensions/table-new/TableRow/index.ts b/packages/editor/core/src/ui/extensions/table-new/TableRow/index.ts new file mode 100644 index 00000000000..f01744bf7cc --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table-new/TableRow/index.ts @@ -0,0 +1 @@ +export { default as default } from "./TableRow" diff --git a/packages/editor/core/src/ui/extensions/table/index.ts b/packages/editor/core/src/ui/extensions/table/index.ts deleted file mode 100644 index 9b727bb51bd..00000000000 --- a/packages/editor/core/src/ui/extensions/table/index.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/core/src/ui/extensions/table/table-cell.ts b/packages/editor/core/src/ui/extensions/table/table-cell.ts deleted file mode 100644 index 643cb8c64a7..00000000000 --- a/packages/editor/core/src/ui/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/core/src/ui/extensions/table/table-header.ts b/packages/editor/core/src/ui/extensions/table/table-header.ts deleted file mode 100644 index f23aa93ef55..00000000000 --- a/packages/editor/core/src/ui/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/core/src/ui/read-only/extensions.tsx b/packages/editor/core/src/ui/read-only/extensions.tsx index 2246c64f9f8..6837a3d772f 100644 --- a/packages/editor/core/src/ui/read-only/extensions.tsx +++ b/packages/editor/core/src/ui/read-only/extensions.tsx @@ -8,10 +8,10 @@ import TaskList from "@tiptap/extension-task-list"; import { Markdown } from "tiptap-markdown"; import Gapcursor from "@tiptap/extension-gapcursor"; -import { CustomTableCell } from "../extensions/table/table-cell"; -import { Table } from "../extensions/table"; -import { TableHeader } from "../extensions/table/table-header"; -import { TableRow } from "@tiptap/extension-table-row"; +// import { CustomTableCell } from "../extensions/table/table-cell"; +// import { Table } from "../extensions/table"; +// import { TableHeader } from "../extensions/table/table-header"; +// import { TableRow } from "@tiptap/extension-table-row"; import ReadOnlyImageExtension from "../extensions/image/read-only-image"; import { isValidHttpUrl } from "../../lib/utils"; @@ -85,8 +85,8 @@ export const CoreReadOnlyEditorExtensions = [ html: true, transformCopiedText: true, }), - Table, - TableHeader, - CustomTableCell, - TableRow, + // Table, + // TableHeader, + // CustomTableCell, + // TableRow, ]; diff --git a/web/components/issues/comment/comment-card.tsx b/web/components/issues/comment/comment-card.tsx index 29ba21cd293..d59dce7d32f 100644 --- a/web/components/issues/comment/comment-card.tsx +++ b/web/components/issues/comment/comment-card.tsx @@ -14,8 +14,8 @@ import { LiteTextEditorWithRef, LiteReadOnlyEditorWithRef } from "@plane/lite-te import { timeAgo } from "helpers/date-time.helper"; // types import type { IIssueComment } from "types"; -import fileService from "services/file.service"; // services +import fileService from "services/file.service"; type Props = { comment: IIssueComment; diff --git a/web/pages/_app.tsx b/web/pages/_app.tsx index b94e52d6bd8..53383fbe1ea 100644 --- a/web/pages/_app.tsx +++ b/web/pages/_app.tsx @@ -6,6 +6,7 @@ import NProgress from "nprogress"; // styles import "styles/globals.css"; import "styles/editor.css"; +import "styles/tables.css"; import "styles/command-pallette.css"; import "styles/nprogress.css"; import "styles/react-datepicker.css"; diff --git a/web/styles/tables.css b/web/styles/tables.css new file mode 100644 index 00000000000..f4339012080 --- /dev/null +++ b/web/styles/tables.css @@ -0,0 +1,200 @@ +.tableWrapper { + overflow-x: auto; + padding: 2px; + width: fit-content; + max-width: 100%; +} + +.tableWrapper table { + border-collapse: collapse; + table-layout: fixed; + margin: 0; + border: 1px solid rgb(var(--color-border-200)); + width: 100%; +} + +.tableWrapper table td, +.tableWrapper table th { + min-width: 1em; + border: 1px solid rgb(var(--color-border-200)); + padding: 10px 15px; + vertical-align: top; + box-sizing: border-box; + position: relative; + transition: background-color 0.3s ease; + + >* { + margin-bottom: 0; + } +} + +.tableWrapper table td>*, +.tableWrapper table th>* { + margin: 0 !important; + padding: 0.25rem 0 !important; +} + +.tableWrapper table td.has-focus, +.tableWrapper table th.has-focus { + box-shadow: rgba(var(--color-primary-300), 0.1) 0px 0px 0px 2px inset !important; +} + +.tableWrapper table th { + font-weight: bold; + text-align: left; + background-color: rgb(var(--color-primary-100)); +} + +.tableWrapper table td:hover{ + background-color: rgba(var(--color-primary-300), 0.1); +} + +.tableWrapper table th * { + font-weight: 600; +} + +.tableWrapper table .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; +} + +.tableWrapper table .column-resize-handle { + position: absolute; + right: -2px; + top: 0; + bottom: -2px; + width: 4px; + z-index: 99; + background-color: rgb(var(--color-primary-400)); + pointer-events: none; +} + +.tableWrapper .tableControls { + position: absolute; +} + +.tableWrapper .tableControls .columnsControl, +.tableWrapper .tableControls .rowsControl { + transition: opacity ease-in 100ms; + position: absolute; + z-index: 99; + display: flex; + justify-content: center; + align-items: center; +} + +.tableWrapper .tableControls .columnsControl { + height: 20px; + transform: translateY(-50%); +} + +.tableWrapper .tableControls .columnsControl>button { + color: white; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' d='M0 0h24v24H0z'/%3E%3Cpath fill='%238F95B2' d='M4.5 10.5c-.825 0-1.5.675-1.5 1.5s.675 1.5 1.5 1.5S6 12.825 6 12s-.675-1.5-1.5-1.5zm15 0c-.825 0-1.5.675-1.5 1.5s.675 1.5 1.5 1.5S21 12.825 21 12s-.675-1.5-1.5-1.5zm-7.5 0c-.825 0-1.5.675-1.5 1.5s.675 1.5 1.5 1.5 1.5-.675 1.5-1.5-.675-1.5-1.5-1.5z'/%3E%3C/svg%3E"); + width: 30px; + height: 15px; +} + +.tableWrapper .tableControls .rowsControl { + width: 20px; + transform: translateX(-50%); +} + +.tableWrapper .tableControls .rowsControl>button { + color: white; + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='24' height='24'%3E%3Cpath fill='none' d='M0 0h24v24H0z'/%3E%3Cpath fill='%238F95B2' d='M12 3c-.825 0-1.5.675-1.5 1.5S11.175 6 12 6s1.5-.675 1.5-1.5S12.825 3 12 3zm0 15c-.825 0-1.5.675-1.5 1.5S11.175 21 12 21s1.5-.675 1.5-1.5S12.825 18 12 18zm0-7.5c-.825 0-1.5.675-1.5 1.5s.675 1.5 1.5 1.5 1.5-.675 1.5-1.5-.675-1.5-1.5-1.5z'/%3E%3C/svg%3E"); + height: 30px; + width: 15px; +} + +.tableWrapper .tableControls button { + background-color: rgb(var(--color-primary-100)); + border: 1px solid rgb(var(--color-border-200)); + border-radius: 2px; + background-size: 1.25rem; + background-repeat: no-repeat; + background-position: center; + transition: transform ease-out 100ms, background-color ease-out 100ms; + outline: none; + box-shadow: #000 0px 2px 4px; + cursor: pointer; +} + +/* .tableWrapper .tableControls button:hover { */ +/* transform: scale(1.2, 1.2); */ +/* background-color: var(--color-n50); */ +/* } */ + +.tableWrapper .tableControls .tableToolbox, +.tableWrapper .tableControls .tableColorPickerToolbox { + padding: 0.25rem; + display: flex; + flex-direction: column; + width: 200px; + gap: 0.25rem; +} + +.tableWrapper .tableControls .tableToolbox .toolboxItem, +.tableWrapper .tableControls .tableColorPickerToolbox .toolboxItem { + background-color: rgb(var(--color-background-100)); + display: flex; + align-items: center; + gap: 0.5rem; + border: none; + padding: 0.1rem; + border-radius: 4px; + cursor: pointer; + transition: all 0.2s; +} + +.tableWrapper .tableControls .tableToolbox .toolboxItem:hover, +.tableWrapper .tableControls .tableColorPickerToolbox .toolboxItem:hover { + background-color: var(--color-n100); +} + +.tableWrapper .tableControls .tableToolbox .toolboxItem .iconContainer, +.tableWrapper .tableControls .tableColorPickerToolbox .toolboxItem .iconContainer, +.tableWrapper .tableControls .tableToolbox .toolboxItem .colorContainer, +.tableWrapper .tableControls .tableColorPickerToolbox .toolboxItem .colorContainer { + border: 1px solid #e6e8f0; + border-radius: 3px; + padding: 4px; + display: flex; + align-items: center; + justify-content: center; + width: 1.75rem; + height: 1.75rem; +} + +.tableWrapper .tableControls .tableToolbox .toolboxItem .iconContainer svg, +.tableWrapper .tableControls .tableColorPickerToolbox .toolboxItem .iconContainer svg, +.tableWrapper .tableControls .tableToolbox .toolboxItem .colorContainer svg, +.tableWrapper .tableControls .tableColorPickerToolbox .toolboxItem .colorContainer svg { + width: 1rem; + height: 1rem; +} + +.tableToolbox { + background-color: rgb(var(--color-background-100)); +} + +.tableWrapper .tableControls .tableToolbox .toolboxItem .label, +.tableWrapper .tableControls .tableColorPickerToolbox .toolboxItem .label { + font-size: 0.95rem; + color: var(--color-black); +} + +.resize-cursor .tableWrapper .tableControls .rowsControl, +.tableWrapper.controls--disabled .tableControls .rowsControl, +.resize-cursor .tableWrapper .tableControls .columnsControl, +.tableWrapper.controls--disabled .tableControls .columnsControl { + opacity: 0; + pointer-events: none; +} diff --git a/yarn.lock b/yarn.lock index e3095db2c7e..8d340b3ea5a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2476,26 +2476,6 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.1.10.tgz#ec311395d16af15345b63d2dac2d459b9ad5fa9e" integrity sha512-KW63lZLPFIir5AIeh2I7UK6Tx1O3jetD7JIPUzEqp1I1BfJlHGHVQxV8VXAmJl0hTOzjQBsHW42PmBxSC97NUg== -"@tiptap/extension-table-cell@^2.1.6": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-table-cell/-/extension-table-cell-2.1.10.tgz#e594b55622435c43a95edf6f2adfaca402f5cbed" - integrity sha512-NQOTKjPOTJrkI7VaR9wFF3UKB9N2THD8zJZJDcECKQxLR740udF6/6jWm1uwkTwdkBekVKHBMQvKKK9W1bOBiw== - -"@tiptap/extension-table-header@^2.1.6": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-table-header/-/extension-table-header-2.1.10.tgz#6250676a26946e5b7186198a06990ea70f578a87" - integrity sha512-NSC0Y10kXDvPGiJckJY/QU8VA7HHU0tI20Dj7/r1oD9itBWSnWP0zAOXzHVlQt9GpThhFNo2nu3fAaVQNfKoTg== - -"@tiptap/extension-table-row@^2.1.6": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-table-row/-/extension-table-row-2.1.10.tgz#e7a1ca8342b623a400848b437c82d57680e551e3" - integrity sha512-yMOnAaXE7vK7MwULuVUO8v6AYZu6wxTfHAWQe/FqPeMf9tG0HL6+gyt1audremw0xBFMGPx6v4t8vlqPXW9p2g== - -"@tiptap/extension-table@^2.1.6": - version "2.1.10" - resolved "https://registry.yarnpkg.com/@tiptap/extension-table/-/extension-table-2.1.10.tgz#5654426366b547631c647ffc5dacf040e65307e1" - integrity sha512-fsf0c6qA+R6NzbFx+tm1l5POZsgadHjREsedvq5q1i8rCq1Gt1AK+lR7WQsaXlSeIRsWtg4RT0eUjAYNCmKkug== - "@tiptap/extension-task-item@^2.1.7": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/extension-task-item/-/extension-task-item-2.1.10.tgz#8eb0d3e8b1234fa44205dd91619f3f1937ca3254" @@ -2545,6 +2525,11 @@ prosemirror-transform "^1.7.0" prosemirror-view "^1.28.2" +"@tiptap/prosemirror-tables@^1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@tiptap/prosemirror-tables/-/prosemirror-tables-1.1.4.tgz#e123978f13c9b5f980066ba660ec5df857755916" + integrity sha512-O2XnDhZV7xTHSFxMMl8Ei3UVeCxuMlbGYZ+J2QG8CzkK8mxDpBa66kFr5DdyAhvdi1ptpcH9u7/GMwItQpN4sA== + "@tiptap/react@^2.1.7": version "2.1.10" resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-2.1.10.tgz#51cd96462e61f6fffa0ca4eb359d8d7d15ebf422" @@ -2805,7 +2790,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", "@types/react@^18.2.5": version "18.2.0" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.0.tgz#15cda145354accfc09a18d2f2305f9fc099ada21" integrity sha512-0FLj93y5USLHdnhIhABk83rm8XEGA7kH3cr+YUlvxoUGp1xNt/DINUMvqPxLyOQMzLmZe8i4RTHbvb8MC7NmrA== @@ -2814,33 +2799,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/react@^18.2.5": - version "18.2.24" - resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.24.tgz#3c7d68c02e0205a472f04abe4a0c1df35d995c05" - integrity sha512-Ee0Jt4sbJxMu1iDcetZEIKQr99J1Zfb6D4F3qfUWoR1JpInkY1Wdg4WwCyBjL257D0+jGqSl1twBjV8iCaC0Aw== - 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" @@ -5761,6 +5719,13 @@ jsonpointer@^5.0.0: object.assign "^4.1.4" object.values "^1.1.6" +jsx-dom-cjs@^8.0.3: + version "8.0.7" + resolved "https://registry.yarnpkg.com/jsx-dom-cjs/-/jsx-dom-cjs-8.0.7.tgz#098c54680ebf5bb6f6d12cdea5cde3799c172212" + integrity sha512-dQWnuQ+bTm7o72ZlJU4glzeMX8KLxx5U+ZwmEAzVP1+roL7BSM0MrkWdHjdsuNgmxobZCJ+qgiot9EgbJPOoEg== + dependencies: + csstype "^3.1.2" + keycode@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/keycode/-/keycode-2.2.1.tgz#09c23b2be0611d26117ea2501c2c391a01f39eff" @@ -7035,7 +7000,14 @@ prosemirror-menu@^1.2.1: prosemirror-history "^1.0.0" prosemirror-state "^1.0.0" -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== From 94ce5ce3325f9d1e4846d03bf7c6509f42513fb3 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Fri, 13 Oct 2023 14:41:34 +0530 Subject: [PATCH 54/57] color support added for row and columns and fixed naming conventions --- packages/editor/core/src/index.ts | 2 +- .../core/src/ui/components/editor-content.tsx | 3 - .../editor/core/src/ui/extensions/index.tsx | 18 +-- .../ui/extensions/table-new/Table/index.ts | 1 - .../table-new/TableCell/TableCell.ts | 55 -------- .../extensions/table-new/TableCell/index.ts | 1 - .../table-new/TableHeader/TableHeader.ts | 54 -------- .../extensions/table-new/TableHeader/index.ts | 1 - .../ui/extensions/table-new/TableRow/index.ts | 1 - .../ui/extensions/table/table-cell/index.ts | 1 + .../extensions/table/table-cell/table-cell.ts | 58 +++++++++ .../ui/extensions/table/table-header/index.ts | 1 + .../table/table-header/table-header.ts | 57 +++++++++ .../ui/extensions/table/table-row/index.ts | 1 + .../table-row/table-row.ts} | 0 .../{table-new/Table => table/table}/icons.ts | 0 .../src/ui/extensions/table/table/index.ts | 1 + .../table/table-controls.ts} | 0 .../table/table-view.tsx} | 36 +++--- .../Table/Table.ts => table/table/table.ts} | 76 +++-------- .../table/utilities/create-cell.ts} | 0 .../table/utilities/create-table.ts} | 6 +- .../delete-table-when-all-cells-selected.ts} | 6 +- .../table/utilities/get-table-node-types.ts} | 0 .../table/utilities/is-cell-selection.ts} | 0 .../core/src/ui/hooks/useReadOnlyEditor.tsx | 2 +- .../table-menu/InsertBottomTableIcon.tsx | 16 --- .../menus/table-menu/InsertLeftTableIcon.tsx | 15 --- .../menus/table-menu/InsertRightTableIcon.tsx | 16 --- .../menus/table-menu/InsertTopTableIcon.tsx | 15 --- .../core/src/ui/menus/table-menu/index.tsx | 120 ------------------ .../core/src/ui/menus/table-menu/tooltip.tsx | 77 ----------- web/styles/tables.css | 6 +- 33 files changed, 169 insertions(+), 477 deletions(-) delete mode 100644 packages/editor/core/src/ui/extensions/table-new/Table/index.ts delete mode 100644 packages/editor/core/src/ui/extensions/table-new/TableCell/TableCell.ts delete mode 100644 packages/editor/core/src/ui/extensions/table-new/TableCell/index.ts delete mode 100644 packages/editor/core/src/ui/extensions/table-new/TableHeader/TableHeader.ts delete mode 100644 packages/editor/core/src/ui/extensions/table-new/TableHeader/index.ts delete mode 100644 packages/editor/core/src/ui/extensions/table-new/TableRow/index.ts create mode 100644 packages/editor/core/src/ui/extensions/table/table-cell/index.ts create mode 100644 packages/editor/core/src/ui/extensions/table/table-cell/table-cell.ts create mode 100644 packages/editor/core/src/ui/extensions/table/table-header/index.ts create mode 100644 packages/editor/core/src/ui/extensions/table/table-header/table-header.ts create mode 100644 packages/editor/core/src/ui/extensions/table/table-row/index.ts rename packages/editor/core/src/ui/extensions/{table-new/TableRow/TableRow.ts => table/table-row/table-row.ts} (100%) rename packages/editor/core/src/ui/extensions/{table-new/Table => table/table}/icons.ts (100%) create mode 100644 packages/editor/core/src/ui/extensions/table/table/index.ts rename packages/editor/core/src/ui/extensions/{table-new/Table/tableControls.ts => table/table/table-controls.ts} (100%) rename packages/editor/core/src/ui/extensions/{table-new/Table/TableView.ts => table/table/table-view.tsx} (92%) rename packages/editor/core/src/ui/extensions/{table-new/Table/Table.ts => table/table/table.ts} (77%) rename packages/editor/core/src/ui/extensions/{table-new/Table/utilities/createCell.ts => table/table/utilities/create-cell.ts} (100%) rename packages/editor/core/src/ui/extensions/{table-new/Table/utilities/createTable.ts => table/table/utilities/create-table.ts} (88%) rename packages/editor/core/src/ui/extensions/{table-new/Table/utilities/deleteTableWhenAllCellsSelected.ts => table/table/utilities/delete-table-when-all-cells-selected.ts} (86%) rename packages/editor/core/src/ui/extensions/{table-new/Table/utilities/getTableNodeTypes.ts => table/table/utilities/get-table-node-types.ts} (100%) rename packages/editor/core/src/ui/extensions/{table-new/Table/utilities/isCellSelection.ts => table/table/utilities/is-cell-selection.ts} (100%) delete mode 100644 packages/editor/core/src/ui/menus/table-menu/InsertBottomTableIcon.tsx delete mode 100644 packages/editor/core/src/ui/menus/table-menu/InsertLeftTableIcon.tsx delete mode 100644 packages/editor/core/src/ui/menus/table-menu/InsertRightTableIcon.tsx delete mode 100644 packages/editor/core/src/ui/menus/table-menu/InsertTopTableIcon.tsx delete mode 100644 packages/editor/core/src/ui/menus/table-menu/index.tsx delete mode 100644 packages/editor/core/src/ui/menus/table-menu/tooltip.tsx diff --git a/packages/editor/core/src/index.ts b/packages/editor/core/src/index.ts index 6268323e55a..13fb14297d5 100644 --- a/packages/editor/core/src/index.ts +++ b/packages/editor/core/src/index.ts @@ -2,7 +2,7 @@ // import "./styles/tailwind.css"; // import "./styles/editor.css"; -export * from "./ui/extensions/table-new/Table"; +export * from "./ui/extensions/table/table"; // utils export * from "./lib/utils"; diff --git a/packages/editor/core/src/ui/components/editor-content.tsx b/packages/editor/core/src/ui/components/editor-content.tsx index 11468e75737..80c3a8cadcf 100644 --- a/packages/editor/core/src/ui/components/editor-content.tsx +++ b/packages/editor/core/src/ui/components/editor-content.tsx @@ -1,7 +1,6 @@ import { Editor, EditorContent } from "@tiptap/react"; import { ReactNode } from "react"; import { ImageResizer } from "../extensions/image/image-resize"; -import { TableMenu } from "../menus/table-menu"; interface EditorContentProps { editor: Editor | null; @@ -11,9 +10,7 @@ interface EditorContentProps { export const EditorContentWrapper = ({ editor, editorContentCustomClassNames = '', children }: EditorContentProps) => (
- {/* @ts-ignore */} - {/* */} {editor?.isActive("image") && } {children}
diff --git a/packages/editor/core/src/ui/extensions/index.tsx b/packages/editor/core/src/ui/extensions/index.tsx index 3c394205d31..fc2b6393c90 100644 --- a/packages/editor/core/src/ui/extensions/index.tsx +++ b/packages/editor/core/src/ui/extensions/index.tsx @@ -8,20 +8,14 @@ import TaskList from "@tiptap/extension-task-list"; import { Markdown } from "tiptap-markdown"; import Gapcursor from "@tiptap/extension-gapcursor"; -// import { CustomTableCell } from "./table/table-cell"; -// import { Table } from "./table"; -// import { TableHeader } from "./table/table-header"; -// import { TableRow } from "@tiptap/extension-table-row"; - import ImageExtension from "./image"; import { DeleteImage } from "../../types/delete-image"; import { isValidHttpUrl } from "../../lib/utils"; -import Table from "./table-new/Table"; -import TableHeader from "./table-new/TableHeader"; -import TableCell from "./table-new/TableCell"; -import TableRow from "./table-new/TableRow"; - +import TableHeader from "./table/table-header/table-header"; +import Table from "./table/table"; +import TableCell from "./table/table-cell/table-cell"; +import TableRow from "./table/table-row/table-row"; export const CoreEditorExtensions = ( deleteFile: DeleteImage, @@ -98,8 +92,4 @@ export const CoreEditorExtensions = ( TableHeader, TableCell, TableRow, - // Table, - // TableHeader, - // CustomTableCell, - // TableRow, ]; diff --git a/packages/editor/core/src/ui/extensions/table-new/Table/index.ts b/packages/editor/core/src/ui/extensions/table-new/Table/index.ts deleted file mode 100644 index ccdae7fd2b7..00000000000 --- a/packages/editor/core/src/ui/extensions/table-new/Table/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as default } from "./Table" diff --git a/packages/editor/core/src/ui/extensions/table-new/TableCell/TableCell.ts b/packages/editor/core/src/ui/extensions/table-new/TableCell/TableCell.ts deleted file mode 100644 index dfa25c94d3c..00000000000 --- a/packages/editor/core/src/ui/extensions/table-new/TableCell/TableCell.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { mergeAttributes, Node } from "@tiptap/core" - -export interface TableCellOptions { - HTMLAttributes: Record -} - -export default Node.create({ - name: "tableCell", - - addOptions() { - return { - HTMLAttributes: {} - } - }, - - content: "paragraph+", - - addAttributes() { - return { - colspan: { - default: 1 - }, - rowspan: { - default: 1 - }, - colwidth: { - default: null, - parseHTML: (element) => { - const colwidth = element.getAttribute("colwidth") - const value = colwidth ? [parseInt(colwidth, 10)] : null - - return value - } - } - } - }, - - tableRole: "cell", - - isolating: true, - - parseHTML() { - return [{ tag: "td" }] - }, - - renderHTML({ node, HTMLAttributes }) { - return [ - "td", - mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { - style: `background-color: ${node.attrs.background}` - }), - 0 - ] - } -}) diff --git a/packages/editor/core/src/ui/extensions/table-new/TableCell/index.ts b/packages/editor/core/src/ui/extensions/table-new/TableCell/index.ts deleted file mode 100644 index e4acbea9ef7..00000000000 --- a/packages/editor/core/src/ui/extensions/table-new/TableCell/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as default } from "./TableCell" diff --git a/packages/editor/core/src/ui/extensions/table-new/TableHeader/TableHeader.ts b/packages/editor/core/src/ui/extensions/table-new/TableHeader/TableHeader.ts deleted file mode 100644 index 8e8d0f1d4ed..00000000000 --- a/packages/editor/core/src/ui/extensions/table-new/TableHeader/TableHeader.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { mergeAttributes, Node } from "@tiptap/core" - -export interface TableHeaderOptions { - HTMLAttributes: Record -} -export default Node.create({ - name: "tableHeader", - - addOptions() { - return { - HTMLAttributes: {} - } - }, - - content: "paragraph+", - - addAttributes() { - return { - colspan: { - default: 1 - }, - rowspan: { - default: 1 - }, - colwidth: { - default: null, - parseHTML: (element) => { - const colwidth = element.getAttribute("colwidth") - const value = colwidth ? [parseInt(colwidth, 10)] : null - - return value - } - } - } - }, - - tableRole: "header_cell", - - isolating: true, - - parseHTML() { - return [{ tag: "th" }] - }, - - renderHTML({ node, HTMLAttributes }) { - return [ - "th", - mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { - style: `background-color: ${node.attrs.background}` - }), - 0 - ] - } -}) diff --git a/packages/editor/core/src/ui/extensions/table-new/TableHeader/index.ts b/packages/editor/core/src/ui/extensions/table-new/TableHeader/index.ts deleted file mode 100644 index f260509cfa0..00000000000 --- a/packages/editor/core/src/ui/extensions/table-new/TableHeader/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as default } from "./TableHeader" diff --git a/packages/editor/core/src/ui/extensions/table-new/TableRow/index.ts b/packages/editor/core/src/ui/extensions/table-new/TableRow/index.ts deleted file mode 100644 index f01744bf7cc..00000000000 --- a/packages/editor/core/src/ui/extensions/table-new/TableRow/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as default } from "./TableRow" diff --git a/packages/editor/core/src/ui/extensions/table/table-cell/index.ts b/packages/editor/core/src/ui/extensions/table/table-cell/index.ts new file mode 100644 index 00000000000..b39fe7104e5 --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table/table-cell/index.ts @@ -0,0 +1 @@ +export { default as default } from "./table-cell" diff --git a/packages/editor/core/src/ui/extensions/table/table-cell/table-cell.ts b/packages/editor/core/src/ui/extensions/table/table-cell/table-cell.ts new file mode 100644 index 00000000000..ac43875dac8 --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table/table-cell/table-cell.ts @@ -0,0 +1,58 @@ +import { mergeAttributes, Node } from "@tiptap/core" + +export interface TableCellOptions { + HTMLAttributes: Record +} + +export default Node.create({ + name: "tableCell", + + addOptions() { + return { + HTMLAttributes: {} + } + }, + + content: "paragraph+", + + addAttributes() { + return { + colspan: { + default: 1 + }, + rowspan: { + default: 1 + }, + colwidth: { + default: null, + parseHTML: (element) => { + const colwidth = element.getAttribute("colwidth") + const value = colwidth ? [parseInt(colwidth, 10)] : null + + return value + } + }, + background: { + default: "none" + } + } + }, + + tableRole: "cell", + + isolating: true, + + parseHTML() { + return [{ tag: "td" }] + }, + + renderHTML({ node, HTMLAttributes }) { + return [ + "td", + mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { + style: `background-color: ${node.attrs.background}` + }), + 0 + ] + } +}) diff --git a/packages/editor/core/src/ui/extensions/table/table-header/index.ts b/packages/editor/core/src/ui/extensions/table/table-header/index.ts new file mode 100644 index 00000000000..57137dedd43 --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table/table-header/index.ts @@ -0,0 +1 @@ +export { default as default } from "./table-header" diff --git a/packages/editor/core/src/ui/extensions/table/table-header/table-header.ts b/packages/editor/core/src/ui/extensions/table/table-header/table-header.ts new file mode 100644 index 00000000000..712ca65f073 --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table/table-header/table-header.ts @@ -0,0 +1,57 @@ +import { mergeAttributes, Node } from "@tiptap/core" + +export interface TableHeaderOptions { + HTMLAttributes: Record +} +export default Node.create({ + name: "tableHeader", + + addOptions() { + return { + HTMLAttributes: {} + } + }, + + content: "paragraph+", + + addAttributes() { + return { + colspan: { + default: 1 + }, + rowspan: { + default: 1 + }, + colwidth: { + default: null, + parseHTML: (element) => { + const colwidth = element.getAttribute("colwidth") + const value = colwidth ? [parseInt(colwidth, 10)] : null + + return value + } + }, + background: { + default: "rgb(var(--color-primary-100))" + } + } + }, + + tableRole: "header_cell", + + isolating: true, + + parseHTML() { + return [{ tag: "th" }] + }, + + renderHTML({ node, HTMLAttributes }) { + return [ + "th", + mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { + style: `background-color: ${node.attrs.background}` + }), + 0 + ] + } +}) diff --git a/packages/editor/core/src/ui/extensions/table/table-row/index.ts b/packages/editor/core/src/ui/extensions/table/table-row/index.ts new file mode 100644 index 00000000000..9ecc2c0ae57 --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table/table-row/index.ts @@ -0,0 +1 @@ +export { default as default } from "./table-row" diff --git a/packages/editor/core/src/ui/extensions/table-new/TableRow/TableRow.ts b/packages/editor/core/src/ui/extensions/table/table-row/table-row.ts similarity index 100% rename from packages/editor/core/src/ui/extensions/table-new/TableRow/TableRow.ts rename to packages/editor/core/src/ui/extensions/table/table-row/table-row.ts diff --git a/packages/editor/core/src/ui/extensions/table-new/Table/icons.ts b/packages/editor/core/src/ui/extensions/table/table/icons.ts similarity index 100% rename from packages/editor/core/src/ui/extensions/table-new/Table/icons.ts rename to packages/editor/core/src/ui/extensions/table/table/icons.ts diff --git a/packages/editor/core/src/ui/extensions/table/table/index.ts b/packages/editor/core/src/ui/extensions/table/table/index.ts new file mode 100644 index 00000000000..5dbd0f38a45 --- /dev/null +++ b/packages/editor/core/src/ui/extensions/table/table/index.ts @@ -0,0 +1 @@ +export { default as default } from "./table" diff --git a/packages/editor/core/src/ui/extensions/table-new/Table/tableControls.ts b/packages/editor/core/src/ui/extensions/table/table/table-controls.ts similarity index 100% rename from packages/editor/core/src/ui/extensions/table-new/Table/tableControls.ts rename to packages/editor/core/src/ui/extensions/table/table/table-controls.ts diff --git a/packages/editor/core/src/ui/extensions/table-new/Table/TableView.ts b/packages/editor/core/src/ui/extensions/table/table/table-view.tsx similarity index 92% rename from packages/editor/core/src/ui/extensions/table-new/Table/TableView.ts rename to packages/editor/core/src/ui/extensions/table/table/table-view.tsx index c11a69e31e2..14f75efe798 100644 --- a/packages/editor/core/src/ui/extensions/table-new/Table/TableView.ts +++ b/packages/editor/core/src/ui/extensions/table/table/table-view.tsx @@ -1,7 +1,7 @@ import { h } from "jsx-dom-cjs" import { Node as ProseMirrorNode } from "@tiptap/pm/model" import { Decoration, NodeView } from "@tiptap/pm/view" -import tippy, { Instance, Props, Tippy } from "tippy.js" +import tippy, { Instance, Props } from "tippy.js" import { Editor } from "@tiptap/core" import { @@ -109,7 +109,7 @@ const columnsToolboxItems = [ { label: "Pick Column Color", icon: icons.colorPicker, - action: ({ editor, triggerButton, controlsContainer }) => { + action: ({ editor, triggerButton, controlsContainer }: { editor: Editor, triggerButton: HTMLElement, controlsContainer }) => { createColorPickerToolbox({ triggerButton, tippyOptions: { @@ -140,7 +140,7 @@ const rowsToolboxItems = [ { label: "Pick a Color", icon: icons.colorPicker, - action: ({ editor, triggerButton, controlsContainer }: { editor: Editor, triggerButton: HTMLElement, controlsContainer: any }) => { + action: ({ editor, triggerButton, controlsContainer }: { editor: Editor, triggerButton: HTMLButtonElement, controlsContainer: Element | "parent" | ((ref: Element) => Element) | undefined }) => { createColorPickerToolbox({ triggerButton, tippyOptions: { @@ -202,12 +202,12 @@ function createColorPickerToolbox({ onSelectColor?: (color: string) => void }) { const items = { - "Fond par défault": "#ffffff", - "Fond gris clair": "#e7f3f8", - "Fond gris foncé": "#c7d2d7", - "Fond bleu": "#e7f3f8", - "Fond rouge": "#ffc4c7", - "Fond jaune": "#fbf3db" + "Default": "rgb(var(--color-primary-100))", + "Light gray": "#e7f3f8", + "Dark gray": "#c7d2d7", + "Light blue": "#e7f3f8", + "Light red": "#ffc4c7", + "Light yellow": "#fbf3db" } const colorPicker = tippy(triggerButton, { @@ -265,11 +265,11 @@ export class TableView implements NodeView { table: HTMLElement colgroup: HTMLElement tbody: HTMLElement - rowsControl: HTMLElement - columnsControl: HTMLElement - columnsToolbox: Instance - rowsToolbox: Instance - controls: HTMLElement + rowsControl?: HTMLElement + columnsControl?: HTMLElement + columnsToolbox?: Instance + rowsToolbox?: Instance + controls?: HTMLElement get dom() { return this.root @@ -333,10 +333,10 @@ export class TableView implements NodeView { onClickItem: (item) => { item.action({ editor: this.editor, - triggerButton: this.columnsControl.firstElementChild, + triggerButton: this.columnsControl?.firstElementChild, controlsContainer: this.controls }) - this.columnsToolbox.hide() + this.columnsToolbox?.hide() } }) @@ -350,10 +350,10 @@ export class TableView implements NodeView { onClickItem: (item) => { item.action({ editor: this.editor, - triggerButton: this.rowsControl.firstElementChild, + triggerButton: this.rowsControl?.firstElementChild, controlsContainer: this.controls }) - this.rowsToolbox.hide() + this.rowsToolbox?.hide() } }) } diff --git a/packages/editor/core/src/ui/extensions/table-new/Table/Table.ts b/packages/editor/core/src/ui/extensions/table/table/table.ts similarity index 77% rename from packages/editor/core/src/ui/extensions/table-new/Table/Table.ts rename to packages/editor/core/src/ui/extensions/table/table/table.ts index 1bded42af57..eab3cad92e0 100644 --- a/packages/editor/core/src/ui/extensions/table-new/Table/Table.ts +++ b/packages/editor/core/src/ui/extensions/table/table/table.ts @@ -21,15 +21,10 @@ import { toggleHeaderCell } from "@tiptap/prosemirror-tables" -import { tableControls } from "./tableControls" -import { TableView } from "./TableView" -import { createTable } from "./utilities/createTable" -import { deleteTableWhenAllCellsSelected } from "./utilities/deleteTableWhenAllCellsSelected" - -/** - * Extension based on: - * - Tiptap TableExtension (https://github.com/ueberdosis/tiptap/blob/main/packages/extension-table/src/table.ts) - */ +import { tableControls } from "./table-controls" +import { TableView } from "./table-view" +import { createTable } from "./utilities/create-table" +import { deleteTableWhenAllCellsSelected } from "./utilities/delete-table-when-all-cells-selected" export interface TableOptions { HTMLAttributes: Record @@ -73,9 +68,6 @@ declare module "@tiptap/core" { } interface NodeConfig { - /** - * Table Role - */ tableRole?: | string | ((this: { @@ -149,64 +141,40 @@ export default Node.create({ }, addColumnBefore: () => - ({ state, dispatch }) => { - return addColumnBefore(state, dispatch) - }, + ({ state, dispatch }) => addColumnBefore(state, dispatch), addColumnAfter: () => - ({ state, dispatch }) => { - return addColumnAfter(state, dispatch) - }, + ({ state, dispatch }) => addColumnAfter(state, dispatch), deleteColumn: () => - ({ state, dispatch }) => { - return deleteColumn(state, dispatch) - }, + ({ state, dispatch }) => deleteColumn(state, dispatch), addRowBefore: () => - ({ state, dispatch }) => { - return addRowBefore(state, dispatch) - }, + ({ state, dispatch }) => addRowBefore(state, dispatch), addRowAfter: () => - ({ state, dispatch }) => { - return addRowAfter(state, dispatch) - }, + ({ state, dispatch }) => addRowAfter(state, dispatch), deleteRow: () => - ({ state, dispatch }) => { - return deleteRow(state, dispatch) - }, + ({ state, dispatch }) => deleteRow(state, dispatch), deleteTable: () => - ({ state, dispatch }) => { - return deleteTable(state, dispatch) - }, + ({ state, dispatch }) => deleteTable(state, dispatch), mergeCells: () => - ({ state, dispatch }) => { - return mergeCells(state, dispatch) - }, + ({ state, dispatch }) => mergeCells(state, dispatch), splitCell: () => - ({ state, dispatch }) => { - return splitCell(state, dispatch) - }, + ({ state, dispatch }) => splitCell(state, dispatch), toggleHeaderColumn: () => - ({ state, dispatch }) => { - return toggleHeader("column")(state, dispatch) - }, + ({ state, dispatch }) => toggleHeader("column")(state, dispatch), toggleHeaderRow: () => - ({ state, dispatch }) => { - return toggleHeader("row")(state, dispatch) - }, + ({ state, dispatch }) => toggleHeader("row")(state, dispatch), toggleHeaderCell: () => - ({ state, dispatch }) => { - return toggleHeaderCell(state, dispatch) - }, + ({ state, dispatch }) => toggleHeaderCell(state, dispatch), mergeOrSplit: () => ({ state, dispatch }) => { @@ -218,19 +186,13 @@ export default Node.create({ }, setCellAttribute: (name, value) => - ({ state, dispatch }) => { - return setCellAttr(name, value)(state, dispatch) - }, + ({ state, dispatch }) => setCellAttr(name, value)(state, dispatch), goToNextCell: () => - ({ state, dispatch }) => { - return goToNextCell(1)(state, dispatch) - }, + ({ state, dispatch }) => goToNextCell(1)(state, dispatch), goToPreviousCell: () => - ({ state, dispatch }) => { - return goToNextCell(-1)(state, dispatch) - }, + ({ state, dispatch }) => goToNextCell(-1)(state, dispatch), fixTables: () => ({ state, dispatch }) => { diff --git a/packages/editor/core/src/ui/extensions/table-new/Table/utilities/createCell.ts b/packages/editor/core/src/ui/extensions/table/table/utilities/create-cell.ts similarity index 100% rename from packages/editor/core/src/ui/extensions/table-new/Table/utilities/createCell.ts rename to packages/editor/core/src/ui/extensions/table/table/utilities/create-cell.ts diff --git a/packages/editor/core/src/ui/extensions/table-new/Table/utilities/createTable.ts b/packages/editor/core/src/ui/extensions/table/table/utilities/create-table.ts similarity index 88% rename from packages/editor/core/src/ui/extensions/table-new/Table/utilities/createTable.ts rename to packages/editor/core/src/ui/extensions/table/table/utilities/create-table.ts index c59aadac1e2..75bf7cb41db 100644 --- a/packages/editor/core/src/ui/extensions/table-new/Table/utilities/createTable.ts +++ b/packages/editor/core/src/ui/extensions/table/table/utilities/create-table.ts @@ -1,9 +1,7 @@ import { Fragment, Node as ProsemirrorNode, Schema } from "@tiptap/pm/model" -import { ReactNodeViewRenderer } from "@tiptap/react" - -import { createCell } from "./createCell" -import { getTableNodeTypes } from "./getTableNodeTypes" +import { createCell } from "./create-cell" +import { getTableNodeTypes } from "./get-table-node-types" export function createTable( schema: Schema, diff --git a/packages/editor/core/src/ui/extensions/table-new/Table/utilities/deleteTableWhenAllCellsSelected.ts b/packages/editor/core/src/ui/extensions/table/table/utilities/delete-table-when-all-cells-selected.ts similarity index 86% rename from packages/editor/core/src/ui/extensions/table-new/Table/utilities/deleteTableWhenAllCellsSelected.ts rename to packages/editor/core/src/ui/extensions/table/table/utilities/delete-table-when-all-cells-selected.ts index b76cdca5d9a..dcb20b3239f 100644 --- a/packages/editor/core/src/ui/extensions/table-new/Table/utilities/deleteTableWhenAllCellsSelected.ts +++ b/packages/editor/core/src/ui/extensions/table/table/utilities/delete-table-when-all-cells-selected.ts @@ -1,6 +1,6 @@ import { findParentNodeClosestToPos, KeyboardShortcutCommand } from "@tiptap/core" -import { isCellSelection } from "./isCellSelection" +import { isCellSelection } from "./is-cell-selection" export const deleteTableWhenAllCellsSelected: KeyboardShortcutCommand = ({ editor @@ -14,9 +14,7 @@ export const deleteTableWhenAllCellsSelected: KeyboardShortcutCommand = ({ let cellCount = 0 const table = findParentNodeClosestToPos( selection.ranges[0].$from, - (node) => { - return node.type.name === "table" - } + (node) => node.type.name === "table" ) table?.node.descendants((node) => { diff --git a/packages/editor/core/src/ui/extensions/table-new/Table/utilities/getTableNodeTypes.ts b/packages/editor/core/src/ui/extensions/table/table/utilities/get-table-node-types.ts similarity index 100% rename from packages/editor/core/src/ui/extensions/table-new/Table/utilities/getTableNodeTypes.ts rename to packages/editor/core/src/ui/extensions/table/table/utilities/get-table-node-types.ts diff --git a/packages/editor/core/src/ui/extensions/table-new/Table/utilities/isCellSelection.ts b/packages/editor/core/src/ui/extensions/table/table/utilities/is-cell-selection.ts similarity index 100% rename from packages/editor/core/src/ui/extensions/table-new/Table/utilities/isCellSelection.ts rename to packages/editor/core/src/ui/extensions/table/table/utilities/is-cell-selection.ts diff --git a/packages/editor/core/src/ui/hooks/useReadOnlyEditor.tsx b/packages/editor/core/src/ui/hooks/useReadOnlyEditor.tsx index 3791c4c5d2c..3e32c5044c8 100644 --- a/packages/editor/core/src/ui/hooks/useReadOnlyEditor.tsx +++ b/packages/editor/core/src/ui/hooks/useReadOnlyEditor.tsx @@ -11,7 +11,7 @@ interface CustomReadOnlyEditorProps { editorProps?: EditorProps; } -export const useReadOnlyEditor = ({ value, forwardedRef, extensions, editorProps }: CustomReadOnlyEditorProps) => { +export const useReadOnlyEditor = ({ value, forwardedRef, extensions = [], editorProps = {} }: CustomReadOnlyEditorProps) => { const editor = useCustomEditor({ editable: false, content: (typeof value === "string" && value.trim() !== "") ? value : "

", diff --git a/packages/editor/core/src/ui/menus/table-menu/InsertBottomTableIcon.tsx b/packages/editor/core/src/ui/menus/table-menu/InsertBottomTableIcon.tsx deleted file mode 100644 index 0e42ba64824..00000000000 --- a/packages/editor/core/src/ui/menus/table-menu/InsertBottomTableIcon.tsx +++ /dev/null @@ -1,16 +0,0 @@ -const InsertBottomTableIcon = (props: any) => ( - - - -); - -export default InsertBottomTableIcon; diff --git a/packages/editor/core/src/ui/menus/table-menu/InsertLeftTableIcon.tsx b/packages/editor/core/src/ui/menus/table-menu/InsertLeftTableIcon.tsx deleted file mode 100644 index 1fd75fe8754..00000000000 --- a/packages/editor/core/src/ui/menus/table-menu/InsertLeftTableIcon.tsx +++ /dev/null @@ -1,15 +0,0 @@ -const InsertLeftTableIcon = (props: any) => ( - - - -); -export default InsertLeftTableIcon; diff --git a/packages/editor/core/src/ui/menus/table-menu/InsertRightTableIcon.tsx b/packages/editor/core/src/ui/menus/table-menu/InsertRightTableIcon.tsx deleted file mode 100644 index 1a65709694b..00000000000 --- a/packages/editor/core/src/ui/menus/table-menu/InsertRightTableIcon.tsx +++ /dev/null @@ -1,16 +0,0 @@ -const InsertRightTableIcon = (props: any) => ( - - - -); - -export default InsertRightTableIcon; diff --git a/packages/editor/core/src/ui/menus/table-menu/InsertTopTableIcon.tsx b/packages/editor/core/src/ui/menus/table-menu/InsertTopTableIcon.tsx deleted file mode 100644 index 8f04f4f6126..00000000000 --- a/packages/editor/core/src/ui/menus/table-menu/InsertTopTableIcon.tsx +++ /dev/null @@ -1,15 +0,0 @@ -const InsertTopTableIcon = (props: any) => ( - - - -); -export default InsertTopTableIcon; diff --git a/packages/editor/core/src/ui/menus/table-menu/index.tsx b/packages/editor/core/src/ui/menus/table-menu/index.tsx deleted file mode 100644 index c115196db74..00000000000 --- a/packages/editor/core/src/ui/menus/table-menu/index.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import { useState, useEffect } from "react"; -import { Rows, Columns, ToggleRight } from "lucide-react"; -import InsertLeftTableIcon from "./InsertLeftTableIcon"; -import InsertRightTableIcon from "./InsertRightTableIcon"; -import InsertTopTableIcon from "./InsertTopTableIcon"; -import InsertBottomTableIcon from "./InsertBottomTableIcon"; -import { cn, findTableAncestor } from "../../../lib/utils"; -import { Tooltip } from "./tooltip"; - -interface TableMenuItem { - command: () => void; - icon: any; - key: string; - name: string; -} - - - -export const TableMenu = ({ editor }: { editor: any }) => { - const [tableLocation, setTableLocation] = useState({ bottom: 0, left: 0 }); - const isOpen = editor?.isActive("table"); - - const items: TableMenuItem[] = [ - { - command: () => editor.chain().focus().addColumnBefore().run(), - icon: InsertLeftTableIcon, - key: "insert-column-left", - name: "Insert 1 column left", - }, - { - command: () => editor.chain().focus().addColumnAfter().run(), - icon: InsertRightTableIcon, - key: "insert-column-right", - name: "Insert 1 column right", - }, - { - command: () => editor.chain().focus().addRowBefore().run(), - icon: InsertTopTableIcon, - key: "insert-row-above", - name: "Insert 1 row above", - }, - { - command: () => editor.chain().focus().addRowAfter().run(), - icon: InsertBottomTableIcon, - key: "insert-row-below", - name: "Insert 1 row below", - }, - { - command: () => editor.chain().focus().deleteColumn().run(), - icon: Columns, - key: "delete-column", - name: "Delete column", - }, - { - command: () => editor.chain().focus().deleteRow().run(), - icon: Rows, - key: "delete-row", - name: "Delete row", - }, - { - command: () => editor.chain().focus().toggleHeaderRow().run(), - icon: ToggleRight, - key: "toggle-header-row", - name: "Toggle header row", - }, - ]; - - useEffect(() => { - if (!window) return; - - const handleWindowClick = () => { - const selection: any = window?.getSelection(); - - if (selection.rangeCount !== 0) { - const range = selection.getRangeAt(0); - const tableNode = findTableAncestor(range.startContainer); - - if (tableNode) { - const tableRect = tableNode.getBoundingClientRect(); - const tableCenter = tableRect.left + tableRect.width / 2; - const menuWidth = 45; - const menuLeft = tableCenter - menuWidth / 2; - const tableBottom = tableRect.bottom; - - setTableLocation({ bottom: tableBottom, left: menuLeft }); - } - } - }; - - window.addEventListener("click", handleWindowClick); - - return () => { - window.removeEventListener("click", handleWindowClick); - }; - }, [tableLocation, editor]); - - return ( -
- {items.map((item, index) => ( - - - - ))} -
- ); -}; diff --git a/packages/editor/core/src/ui/menus/table-menu/tooltip.tsx b/packages/editor/core/src/ui/menus/table-menu/tooltip.tsx deleted file mode 100644 index f29d8a49177..00000000000 --- a/packages/editor/core/src/ui/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/web/styles/tables.css b/web/styles/tables.css index f4339012080..8b3f105f4cd 100644 --- a/web/styles/tables.css +++ b/web/styles/tables.css @@ -45,9 +45,9 @@ background-color: rgb(var(--color-primary-100)); } -.tableWrapper table td:hover{ - background-color: rgba(var(--color-primary-300), 0.1); -} +/* .tableWrapper table td:hover{ */ +/* background-color: rgba(var(--color-primary-300), 0.1); */ +/* } */ .tableWrapper table th * { font-weight: 600; From 0689d51a4b4a1948d6a8011a22899fa43d1201a9 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Thu, 19 Oct 2023 12:10:32 +0530 Subject: [PATCH 55/57] added drag drop support for tables and horizontal rule --- .../core/src/ui/extensions/drag-drop.tsx | 217 ++++++++++++++++++ .../editor/core/src/ui/extensions/index.tsx | 2 + .../core/src/ui/read-only/extensions.tsx | 1 + .../src/ui/extensions/index.tsx | 101 ++++---- web/styles/editor.css | 59 +++++ 5 files changed, 337 insertions(+), 43 deletions(-) create mode 100644 packages/editor/core/src/ui/extensions/drag-drop.tsx diff --git a/packages/editor/core/src/ui/extensions/drag-drop.tsx b/packages/editor/core/src/ui/extensions/drag-drop.tsx new file mode 100644 index 00000000000..4ed44bd955d --- /dev/null +++ b/packages/editor/core/src/ui/extensions/drag-drop.tsx @@ -0,0 +1,217 @@ +import { Extension } from "@tiptap/core"; + +import { NodeSelection, Plugin } from "@tiptap/pm/state"; +// @ts-ignore +import { __serializeForClipboard, EditorView } from "@tiptap/pm/view"; + +export interface DragHandleOptions { + /** + * The width of the drag handle + */ + dragHandleWidth: number; +} +function absoluteRect(node: Element) { + const data = node.getBoundingClientRect(); + + return { + top: data.top, + left: data.left, + width: data.width, + }; +} + +function nodeDOMAtCoords(coords: { x: number; y: number }) { + return document + .elementsFromPoint(coords.x, coords.y) + .find( + (elem: Element) => + elem.parentElement?.matches?.(".ProseMirror") || + elem.matches( + [ + "li", + "p:not(:first-child)", + "pre", + "code", + "blockquote", + "h1, h2, h3", + "hr", + "[data-type=horizontalRule]", + ".tableWrapper", + ].join(", "), + ), + ); +} + +function nodePosAtDOM(node: Element, view: EditorView) { + const boundingRect = node.getBoundingClientRect(); + + return view.posAtCoords({ + left: boundingRect.left + 1, + top: boundingRect.top + 1, + })?.inside; +} + +function DragHandle(options: DragHandleOptions) { + function handleDragStart(event: DragEvent, view: EditorView) { + view.focus(); + + if (!event.dataTransfer) return; + + const node = nodeDOMAtCoords({ + x: event.clientX + 50 + options.dragHandleWidth, + y: event.clientY, + }); + + if (!(node instanceof Element)) return; + + const nodePos = nodePosAtDOM(node, view); + if (nodePos == null || nodePos < 0) return; + + view.dispatch( + view.state.tr.setSelection(NodeSelection.create(view.state.doc, nodePos)), + ); + + const slice = view.state.selection.content(); + const { dom, text } = __serializeForClipboard(view, slice); + + event.dataTransfer.clearData(); + event.dataTransfer.setData("text/html", dom.innerHTML); + event.dataTransfer.setData("text/plain", text); + event.dataTransfer.effectAllowed = "copyMove"; + + event.dataTransfer.setDragImage(node, 0, 0); + + view.dragging = { slice, move: event.ctrlKey }; + } + + function handleClick(event: MouseEvent, view: EditorView) { + view.focus(); + + view.dom.classList.remove("dragging"); + + const node = nodeDOMAtCoords({ + x: event.clientX + 50 + options.dragHandleWidth, + y: event.clientY, + }); + + if (!(node instanceof Element)) return; + + const nodePos = nodePosAtDOM(node, view); + if (!nodePos) return; + + view.dispatch( + view.state.tr.setSelection(NodeSelection.create(view.state.doc, nodePos)), + ); + } + + let dragHandleElement: HTMLElement | null = null; + + function hideDragHandle() { + if (dragHandleElement) { + dragHandleElement.classList.add("hidden"); + } + } + + function showDragHandle() { + if (dragHandleElement) { + dragHandleElement.classList.remove("hidden"); + } + } + + return new Plugin({ + view: (view) => { + dragHandleElement = document.createElement("div"); + dragHandleElement.draggable = true; + dragHandleElement.dataset.dragHandle = ""; + dragHandleElement.classList.add("drag-handle"); + dragHandleElement.addEventListener("dragstart", (e) => { + handleDragStart(e, view); + }); + dragHandleElement.addEventListener("click", (e) => { + handleClick(e, view); + }); + + hideDragHandle(); + + view?.dom?.parentElement?.appendChild(dragHandleElement); + + return { + destroy: () => { + dragHandleElement?.remove?.(); + dragHandleElement = null; + }, + }; + }, + props: { + handleDOMEvents: { + mousemove: (view, event) => { + if (!view.editable) { + return; + } + + const node = nodeDOMAtCoords({ + x: event.clientX + 50 + options.dragHandleWidth, + y: event.clientY, + }); + + if (!(node instanceof Element) || node.matches("ul, ol")) { + hideDragHandle(); + return; + } + + const compStyle = window.getComputedStyle(node); + const lineHeight = parseInt(compStyle.lineHeight, 10); + const paddingTop = parseInt(compStyle.paddingTop, 10); + + const rect = absoluteRect(node); + + rect.top += (lineHeight - 24) / 2; + rect.top += paddingTop; + // Li markers + if (node.matches("ul:not([data-type=taskList]) li, ol li")) { + rect.left -= options.dragHandleWidth; + } + rect.width = options.dragHandleWidth; + + if (!dragHandleElement) return; + + dragHandleElement.style.left = `${rect.left - rect.width}px`; + dragHandleElement.style.top = `${rect.top}px`; + showDragHandle(); + }, + keydown: () => { + hideDragHandle(); + }, + mousewheel: () => { + hideDragHandle(); + }, + // dragging class is used for CSS + dragstart: (view) => { + view.dom.classList.add("dragging"); + }, + drop: (view) => { + view.dom.classList.remove("dragging"); + }, + dragend: (view) => { + view.dom.classList.remove("dragging"); + }, + }, + }, + }); +} + +interface DragAndDropOptions {} + +const DragAndDrop = Extension.create({ + name: "dragAndDrop", + + addProseMirrorPlugins() { + return [ + DragHandle({ + dragHandleWidth: 24, + }), + ]; + }, +}); + +export default DragAndDrop; diff --git a/packages/editor/core/src/ui/extensions/index.tsx b/packages/editor/core/src/ui/extensions/index.tsx index fc2b6393c90..147fc69d856 100644 --- a/packages/editor/core/src/ui/extensions/index.tsx +++ b/packages/editor/core/src/ui/extensions/index.tsx @@ -16,6 +16,7 @@ import TableHeader from "./table/table-header/table-header"; import Table from "./table/table"; import TableCell from "./table/table-cell/table-cell"; import TableRow from "./table/table-row/table-row"; +import DragAndDrop from "./drag-drop"; export const CoreEditorExtensions = ( deleteFile: DeleteImage, @@ -92,4 +93,5 @@ export const CoreEditorExtensions = ( TableHeader, TableCell, TableRow, + DragAndDrop, ]; diff --git a/packages/editor/core/src/ui/read-only/extensions.tsx b/packages/editor/core/src/ui/read-only/extensions.tsx index 6837a3d772f..1aad2afb1a4 100644 --- a/packages/editor/core/src/ui/read-only/extensions.tsx +++ b/packages/editor/core/src/ui/read-only/extensions.tsx @@ -84,6 +84,7 @@ export const CoreReadOnlyEditorExtensions = [ Markdown.configure({ html: true, transformCopiedText: true, + transformPastedText: true }), // Table, // TableHeader, diff --git a/packages/editor/rich-text-editor/src/ui/extensions/index.tsx b/packages/editor/rich-text-editor/src/ui/extensions/index.tsx index f0f3bed3423..1b5db0de30d 100644 --- a/packages/editor/rich-text-editor/src/ui/extensions/index.tsx +++ b/packages/editor/rich-text-editor/src/ui/extensions/index.tsx @@ -1,59 +1,74 @@ import HorizontalRule from "@tiptap/extension-horizontal-rule"; import Placeholder from "@tiptap/extension-placeholder"; import CodeBlockLowlight from "@tiptap/extension-code-block-lowlight"; -import { common, createLowlight } from 'lowlight' -import { InputRule } from "@tiptap/core"; +import { common, createLowlight } from "lowlight"; +import { InputRule, mergeAttributes } from "@tiptap/core"; import ts from "highlight.js/lib/languages/typescript"; import SlashCommand from "./slash-command"; import { UploadImage } from "../"; -const lowlight = createLowlight(common) +const lowlight = createLowlight(common); lowlight.register("ts", ts); export const RichTextEditorExtensions = ( uploadFile: UploadImage, - setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void + setIsSubmitting?: ( + isSubmitting: "submitting" | "submitted" | "saved", + ) => void, ) => [ - HorizontalRule.extend({ - addInputRules() { - return [ - new InputRule({ - find: /^(?:---|—-|___\s|\*\*\*\s)$/, - handler: ({ state, range, commands }) => { - commands.splitBlock(); + HorizontalRule.extend({ + parseHTML() { + return [ + { + tag: `div[data-type="${this.name}"]`, + }, + ]; + }, - const attributes = {}; - const { tr } = state; - const start = range.from; - const end = range.to; - // @ts-ignore - tr.replaceWith(start - 1, end, this.type.create(attributes)); - }, - }), - ]; - }, - }).configure({ - HTMLAttributes: { - class: "mb-6 border-t border-custom-border-300", - }, - }), - SlashCommand(uploadFile, setIsSubmitting), - CodeBlockLowlight.configure({ - lowlight, - }), - Placeholder.configure({ - placeholder: ({ node }) => { - if (node.type.name === "heading") { - return `Heading ${node.attrs.level}`; - } - if (node.type.name === "image" || node.type.name === "table") { - return ""; - } + renderHTML({ HTMLAttributes }) { + return [ + "div", + mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { + "data-type": this.name, + }), + ["div", {}], + ]; + }, + addInputRules() { + return [ + new InputRule({ + find: /^(?:---|—-|___\s|\*\*\*\s)$/, + handler: ({ state, range, commands }) => { + commands.splitBlock(); - return "Press '/' for commands..."; - }, - includeChildren: true, - }), - ]; + const attributes = {}; + const { tr } = state; + const start = range.from; + const end = range.to; + // @ts-ignore + tr.replaceWith(start - 1, end, this.type.create(attributes)); + }, + }), + ]; + }, + }), + SlashCommand(uploadFile, setIsSubmitting), + CodeBlockLowlight.configure({ + lowlight, + }), + Placeholder.configure({ + placeholder: ({ node }) => { + if (node.type.name === "heading") { + return `Heading ${node.attrs.level}`; + } + if (node.type.name === "image" || node.type.name === "table") { + return ""; + } + + return "Press '/' for commands..."; + }, + includeChildren: true, + }), +]; diff --git a/web/styles/editor.css b/web/styles/editor.css index 85d881eeb46..a3af9c045e2 100644 --- a/web/styles/editor.css +++ b/web/styles/editor.css @@ -229,3 +229,62 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p { .ProseMirror table * .is-empty::before { opacity: 0; } + +.ProseMirror:not(.dragging) .ProseMirror-selectednode { + outline: none !important; + border-radius: 0.2rem; + background-color: var(--novel-highlight-blue); + transition: background-color 0.2s; + box-shadow: none; +} + +.drag-handle { + position: fixed; + opacity: 1; + transition: opacity ease-in 0.2s; + border-radius: 0.25rem; + + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' style='fill: rgba(0, 0, 0, 0.5)'%3E%3Cpath d='M3,2 C2.44771525,2 2,1.55228475 2,1 C2,0.44771525 2.44771525,0 3,0 C3.55228475,0 4,0.44771525 4,1 C4,1.55228475 3.55228475,2 3,2 Z M3,6 C2.44771525,6 2,5.55228475 2,5 C2,4.44771525 2.44771525,4 3,4 C3.55228475,4 4,4.44771525 4,5 C4,5.55228475 3.55228475,6 3,6 Z M3,10 C2.44771525,10 2,9.55228475 2,9 C2,8.44771525 2.44771525,8 3,8 C3.55228475,8 4,8.44771525 4,9 C4,9.55228475 3.55228475,10 3,10 Z M7,2 C6.44771525,2 6,1.55228475 6,1 C6,0.44771525 6.44771525,0 7,0 C7.55228475,0 8,0.44771525 8,1 C8,1.55228475 7.55228475,2 7,2 Z M7,6 C6.44771525,6 6,5.55228475 6,5 C6,4.44771525 6.44771525,4 7,4 C7.55228475,4 8,4.44771525 8,5 C8,5.55228475 7.55228475,6 7,6 Z M7,10 C6.44771525,10 6,9.55228475 6,9 C6,8.44771525 6.44771525,8 7,8 C7.55228475,8 8,8.44771525 8,9 C8,9.55228475 7.55228475,10 7,10 Z'%3E%3C/path%3E%3C/svg%3E"); + background-size: calc(0.5em + 0.375rem) calc(0.5em + 0.375rem); + background-repeat: no-repeat; + background-position: center; + width: 1.2rem; + height: 1.5rem; + z-index: 50; + cursor: grab; + + &:hover { + background-color: var(--novel-stone-100); + transition: background-color 0.2s; + } + + &:active { + background-color: var(--novel-stone-200); + transition: background-color 0.2s; + } + + &.hide { + opacity: 0; + pointer-events: none; + } + + @media screen and (max-width: 600px) { + display: none; + pointer-events: none; + } +} + +.drag-handle { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' style='fill: rgba(255, 255, 255, 0.5)'%3E%3Cpath d='M3,2 C2.44771525,2 2,1.55228475 2,1 C2,0.44771525 2.44771525,0 3,0 C3.55228475,0 4,0.44771525 4,1 C4,1.55228475 3.55228475,2 3,2 Z M3,6 C2.44771525,6 2,5.55228475 2,5 C2,4.44771525 2.44771525,4 3,4 C3.55228475,4 4,4.44771525 4,5 C4,5.55228475 3.55228475,6 3,6 Z M3,10 C2.44771525,10 2,9.55228475 2,9 C2,8.44771525 2.44771525,8 3,8 C3.55228475,8 4,8.44771525 4,9 C4,9.55228475 3.55228475,10 3,10 Z M7,2 C6.44771525,2 6,1.55228475 6,1 C6,0.44771525 6.44771525,0 7,0 C7.55228475,0 8,0.44771525 8,1 C8,1.55228475 7.55228475,2 7,2 Z M7,6 C6.44771525,6 6,5.55228475 6,5 C6,4.44771525 6.44771525,4 7,4 C7.55228475,4 8,4.44771525 8,5 C8,5.55228475 7.55228475,6 7,6 Z M7,10 C6.44771525,10 6,9.55228475 6,9 C6,8.44771525 6.44771525,8 7,8 C7.55228475,8 8,8.44771525 8,9 C8,9.55228475 7.55228475,10 7,10 Z'%3E%3C/path%3E%3C/svg%3E"); +} + +div[data-type="horizontalRule"] { + line-height: 0; + padding: 0.25rem 0; + margin-top: 0; + margin-bottom: 0; + + & > div { + border-bottom: 1px solid rgb(var(--color-text-100)); + } +} From 796a95b75fbb05a77ec28a1dbcb9546ede282817 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Thu, 19 Oct 2023 12:54:39 +0530 Subject: [PATCH 56/57] added drag drop support for code blocks and images --- .../src/ui/extensions/drag-drop-older.tsx | 238 ++++++++++++++++++ .../core/src/ui/extensions/drag-drop.tsx | 44 +++- web/styles/editor.css | 9 + 3 files changed, 283 insertions(+), 8 deletions(-) create mode 100644 packages/editor/core/src/ui/extensions/drag-drop-older.tsx diff --git a/packages/editor/core/src/ui/extensions/drag-drop-older.tsx b/packages/editor/core/src/ui/extensions/drag-drop-older.tsx new file mode 100644 index 00000000000..1a9f68c192c --- /dev/null +++ b/packages/editor/core/src/ui/extensions/drag-drop-older.tsx @@ -0,0 +1,238 @@ +import { Extension } from "@tiptap/core"; + +import { NodeSelection, Plugin } from "@tiptap/pm/state"; +// @ts-ignore +import { __serializeForClipboard, EditorView } from "@tiptap/pm/view"; + +export interface DragHandleOptions { + /** + * The width of the drag handle + */ + dragHandleWidth: number; +} +function absoluteRect(node: Element) { + const data = node.getBoundingClientRect(); + + return { + top: data.top, + left: data.left, + width: data.width, + }; +} + +function nodeDOMAtCoords(coords: { x: number; y: number }) { + return document + .elementsFromPoint(coords.x, coords.y) + .find( + (elem: Element) => + elem.parentElement?.matches?.(".ProseMirror") || + elem.matches( + [ + "li", + "p:not(:first-child)", + "pre", + "code", + "blockquote", + "h1, h2, h3", + "hr", + "[data-type=horizontalRule]", + ".tableWrapper", + ].join(", "), + ), + ); +} + +function nodePosAtDOM(node: Element, view: EditorView) { + const boundingRect = node.getBoundingClientRect(); + + return view.posAtCoords({ + left: boundingRect.left + 1, + top: boundingRect.top + 1, + })?.inside; +} + +function DragHandle(options: DragHandleOptions) { + function handleDragStart(event: DragEvent, view: EditorView) { + view.focus(); + + if (!event.dataTransfer) return; + + const node = nodeDOMAtCoords({ + x: event.clientX + 50 + options.dragHandleWidth, + y: event.clientY, + }); + + if (!(node instanceof Element)) return; + + // const nodePos = nodePosAtDOM(node, view); + + let nodePos = view.posAtCoords({ + left: event.clientX + 50 + options.dragHandleWidth, + top: event.clientY, + })?.inside; + + if (nodePos === null) { + // Try positions to the right of the given coordinates + const offsets = [1, 2, 3, 4, 5]; + for (const offset of offsets) { + const pos = view.posAtCoords({ + left: event.clientX + 50 + options.dragHandleWidth + offset, + top: event.clientY, + })?.inside; + if (pos !== null && view.state.doc.nodeAt(pos as number) !== null) { + nodePos = pos; + break; + } + } + } + + if (nodePos == null || nodePos < 0) return; + + view.dispatch( + view.state.tr.setSelection(NodeSelection.create(view.state.doc, nodePos)), + ); + + const slice = view.state.selection.content(); + const { dom, text } = __serializeForClipboard(view, slice); + + event.dataTransfer.clearData(); + event.dataTransfer.setData("text/html", dom.innerHTML); + event.dataTransfer.setData("text/plain", text); + event.dataTransfer.effectAllowed = "copyMove"; + + event.dataTransfer.setDragImage(node, 0, 0); + + view.dragging = { slice, move: event.ctrlKey }; + } + + function handleClick(event: MouseEvent, view: EditorView) { + view.focus(); + + view.dom.classList.remove("dragging"); + + const node = nodeDOMAtCoords({ + x: event.clientX + 50 + options.dragHandleWidth, + y: event.clientY, + }); + + if (!(node instanceof Element)) return; + + const nodePos = nodePosAtDOM(node, view); + if (!nodePos) return; + + view.dispatch( + view.state.tr.setSelection(NodeSelection.create(view.state.doc, nodePos)), + ); + } + + let dragHandleElement: HTMLElement | null = null; + + function hideDragHandle() { + if (dragHandleElement) { + dragHandleElement.classList.add("hidden"); + } + } + + function showDragHandle() { + if (dragHandleElement) { + dragHandleElement.classList.remove("hidden"); + } + } + + return new Plugin({ + view: (view) => { + dragHandleElement = document.createElement("div"); + dragHandleElement.draggable = true; + dragHandleElement.dataset.dragHandle = ""; + dragHandleElement.classList.add("drag-handle"); + dragHandleElement.addEventListener("dragstart", (e) => { + handleDragStart(e, view); + }); + dragHandleElement.addEventListener("click", (e) => { + handleClick(e, view); + }); + + hideDragHandle(); + + view?.dom?.parentElement?.appendChild(dragHandleElement); + + return { + destroy: () => { + dragHandleElement?.remove?.(); + dragHandleElement = null; + }, + }; + }, + props: { + handleDOMEvents: { + mousemove: (view, event) => { + if (!view.editable) { + return; + } + + const node = nodeDOMAtCoords({ + x: event.clientX + 50 + options.dragHandleWidth, + y: event.clientY, + }); + + if (!(node instanceof Element) || node.matches("ul, ol")) { + hideDragHandle(); + return; + } + + const compStyle = window.getComputedStyle(node); + const lineHeight = parseInt(compStyle.lineHeight, 10); + const paddingTop = parseInt(compStyle.paddingTop, 10); + + const rect = absoluteRect(node); + + rect.top += (lineHeight - 24) / 2; + rect.top += paddingTop; + // Li markers + if (node.matches("ul:not([data-type=taskList]) li, ol li")) { + rect.left -= options.dragHandleWidth; + } + rect.width = options.dragHandleWidth; + + if (!dragHandleElement) return; + + dragHandleElement.style.left = `${rect.left - rect.width}px`; + dragHandleElement.style.top = `${rect.top}px`; + showDragHandle(); + }, + keydown: () => { + hideDragHandle(); + }, + mousewheel: () => { + hideDragHandle(); + }, + // dragging class is used for CSS + dragstart: (view) => { + view.dom.classList.add("dragging"); + }, + drop: (view) => { + view.dom.classList.remove("dragging"); + }, + dragend: (view) => { + view.dom.classList.remove("dragging"); + }, + }, + }, + }); +} + +interface DragAndDropOptions {} + +const DragAndDrop = Extension.create({ + name: "dragAndDrop", + + addProseMirrorPlugins() { + return [ + DragHandle({ + dragHandleWidth: 24, + }), + ]; + }, +}); + +export default DragAndDrop; diff --git a/packages/editor/core/src/ui/extensions/drag-drop.tsx b/packages/editor/core/src/ui/extensions/drag-drop.tsx index 4ed44bd955d..31f8469bb51 100644 --- a/packages/editor/core/src/ui/extensions/drag-drop.tsx +++ b/packages/editor/core/src/ui/extensions/drag-drop.tsx @@ -5,9 +5,6 @@ import { NodeSelection, Plugin } from "@tiptap/pm/state"; import { __serializeForClipboard, EditorView } from "@tiptap/pm/view"; export interface DragHandleOptions { - /** - * The width of the drag handle - */ dragHandleWidth: number; } function absoluteRect(node: Element) { @@ -64,8 +61,29 @@ function DragHandle(options: DragHandleOptions) { if (!(node instanceof Element)) return; - const nodePos = nodePosAtDOM(node, view); - if (nodePos == null || nodePos < 0) return; + // const nodePos = view.posAtCoords({ left: event.clientX + 50 + options.dragHandleWidth, top: event.clientY })?.inside; + let nodePos = view.posAtCoords({ + left: event.clientX + 50 + options.dragHandleWidth, + top: event.clientY, + })?.inside; + + if (nodePos === null) { + // Try positions to the right of the given coordinates + const offsets = [1, 2, 3, 4, 5]; + for (const offset of offsets) { + const pos = view.posAtCoords({ + left: event.clientX + 50 + options.dragHandleWidth + offset, + top: event.clientY, + })?.inside; + if (pos !== null && view.state.doc.nodeAt(pos as number) !== null) { + nodePos = pos; + break; + } + } + } + + // const nodePos = nodePosAtDOM(node, view); + if (!nodePos || nodePos < 0) return; view.dispatch( view.state.tr.setSelection(NodeSelection.create(view.state.doc, nodePos)), @@ -96,8 +114,18 @@ function DragHandle(options: DragHandleOptions) { if (!(node instanceof Element)) return; + // const nodePos = view.posAtCoords({ left: event.clientX + 50 + options.dragHandleWidth, top: event.clientY })?.inside; + // console.log("sadfa", pos) const nodePos = nodePosAtDOM(node, view); - if (!nodePos) return; + if (!nodePos || nodePos < 0) return; + console.log("nodePos:", nodePos); + console.log("content at nodePos:", view.state.doc.nodeAt(nodePos)); + + const parentPos = view.state.doc.resolve(nodePos).parentOffset; + const parentNode = view.state.doc.nodeAt(parentPos); + + console.log("parentNode:", parentNode); + console.log("parentNode content expression:", parentNode?.type); view.dispatch( view.state.tr.setSelection(NodeSelection.create(view.state.doc, nodePos)), @@ -150,11 +178,11 @@ function DragHandle(options: DragHandleOptions) { } const node = nodeDOMAtCoords({ - x: event.clientX + 50 + options.dragHandleWidth, + x: event.clientX + options.dragHandleWidth, y: event.clientY, }); - if (!(node instanceof Element) || node.matches("ul, ol")) { + if (!(node instanceof Element)) { hideDragHandle(); return; } diff --git a/web/styles/editor.css b/web/styles/editor.css index a3af9c045e2..0f4da3dff1d 100644 --- a/web/styles/editor.css +++ b/web/styles/editor.css @@ -14,6 +14,15 @@ height: 0; } +.ProseMirror pre { + background-color: rgb(var(--color-background-400)); + padding: 0.5rem; + border-radius: 0.25rem; + border: 1px solid rgb(var(--color-border-200)); + margin: 0.5rem 0; + overflow-x: auto; +} + /* Custom image styles */ .ProseMirror img { From 73a2fb649cab97f2db13b1bf7f16e3a6226baba4 Mon Sep 17 00:00:00 2001 From: Palanikannan1437 <73993394+Palanikannan1437@users.noreply.github.com> Date: Thu, 19 Oct 2023 23:22:08 +0530 Subject: [PATCH 57/57] fixed bubble menu showing up --- .../editor/core/src/ui/hooks/useEditor.tsx | 38 ++++++++++---- .../src/ui/menus/bubble-menu/index.tsx | 29 +++++++---- web/components/issues/description-form.tsx | 51 +++++++++++-------- 3 files changed, 77 insertions(+), 41 deletions(-) diff --git a/packages/editor/core/src/ui/hooks/useEditor.tsx b/packages/editor/core/src/ui/hooks/useEditor.tsx index 83770091511..7a6e68286ad 100644 --- a/packages/editor/core/src/ui/hooks/useEditor.tsx +++ b/packages/editor/core/src/ui/hooks/useEditor.tsx @@ -1,10 +1,10 @@ import { useEditor as useCustomEditor, Editor } from "@tiptap/react"; import { useImperativeHandle, useRef, MutableRefObject } from "react"; import { useDebouncedCallback } from "use-debounce"; -import { DeleteImage } from '../../types/delete-image'; +import { DeleteImage } from "../../types/delete-image"; import { CoreEditorProps } from "../props"; import { CoreEditorExtensions } from "../extensions"; -import { EditorProps } from '@tiptap/pm/view'; +import { EditorProps } from "@tiptap/pm/view"; import { getTrimmedHTML } from "../../lib/utils"; import { UploadImage } from "../../types/upload-image"; @@ -12,7 +12,9 @@ const DEBOUNCE_DELAY = 1500; interface CustomEditorProps { uploadFile: UploadImage; - setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void; + setIsSubmitting?: ( + isSubmitting: "submitting" | "submitted" | "saved", + ) => void; setShouldShowAlert?: (showAlert: boolean) => void; value: string; deleteFile: DeleteImage; @@ -23,14 +25,27 @@ interface CustomEditorProps { forwardedRef?: any; } -export const useEditor = ({ uploadFile, deleteFile, editorProps = {}, value, extensions = [], onChange, setIsSubmitting, debouncedUpdatesEnabled, forwardedRef, setShouldShowAlert, }: CustomEditorProps) => { +export const useEditor = ({ + uploadFile, + deleteFile, + editorProps = {}, + value, + extensions = [], + onChange, + setIsSubmitting, + debouncedUpdatesEnabled, + forwardedRef, + setShouldShowAlert, +}: CustomEditorProps) => { + console.log("useEditor", typeof value === "string" && value.trim() !== "" ? value : "

"); const editor = useCustomEditor({ editorProps: { ...CoreEditorProps(uploadFile, setIsSubmitting), ...editorProps, }, extensions: [...CoreEditorExtensions(deleteFile), ...extensions], - content: (typeof value === "string" && value.trim() !== "") ? value : "

", + content: + typeof value === "string" && value.trim() !== "" ? value : "

", onUpdate: async ({ editor }) => { // for instant feedback loop setIsSubmitting?.("submitting"); @@ -55,11 +70,14 @@ export const useEditor = ({ uploadFile, deleteFile, editorProps = {}, value, ext }, })); - const debouncedUpdates = useDebouncedCallback(async ({ onChange, editor }) => { - if (onChange) { - onChange(editor.getJSON(), getTrimmedHTML(editor.getHTML())); - } - }, DEBOUNCE_DELAY); + const debouncedUpdates = useDebouncedCallback( + async ({ onChange, editor }) => { + if (onChange) { + onChange(editor.getJSON(), getTrimmedHTML(editor.getHTML())); + } + }, + DEBOUNCE_DELAY, + ); if (!editor) { return null; diff --git a/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/index.tsx b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/index.tsx index 14fd73a8338..9f4ab6fe80e 100644 --- a/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/index.tsx +++ b/packages/editor/rich-text-editor/src/ui/menus/bubble-menu/index.tsx @@ -1,10 +1,17 @@ -import { BubbleMenu, BubbleMenuProps } from "@tiptap/react"; +import { BubbleMenu, BubbleMenuProps, isNodeSelection } from "@tiptap/react"; import { FC, useState } from "react"; import { BoldIcon } from "lucide-react"; import { NodeSelector } from "./node-selector"; import { LinkSelector } from "./link-selector"; -import { BoldItem, cn, CodeItem, ItalicItem, StrikeThroughItem, UnderLineItem } from "@plane/editor-core"; +import { + BoldItem, + cn, + CodeItem, + ItalicItem, + StrikeThroughItem, + UnderLineItem, +} from "@plane/editor-core"; export interface BubbleMenuItem { name: string; @@ -26,14 +33,18 @@ export const EditorBubbleMenu: FC = (props: any) => { const bubbleMenuProps: EditorBubbleMenuProps = { ...props, - shouldShow: ({ editor }) => { - if (!editor.isEditable) { - return false; - } - if (editor.isActive("image")) { + shouldShow: ({ state, editor }) => { + const { selection } = state; + const { empty } = selection; + + // don't show bubble menu if: + // - the selected node is an image + // - the selection is empty + // - the selection is a node selection (for drag handles) + if (editor.isActive("image") || !editor.isEditable || empty || isNodeSelection(selection)) { return false; } - return editor.view.state.selection.content().size > 0; + return true; }, tippyOptions: { moveTransition: "transform 0.15s ease-out", @@ -80,7 +91,7 @@ export const EditorBubbleMenu: FC = (props: any) => { "p-2 text-custom-text-300 hover:bg-custom-primary-100/5 active:bg-custom-primary-100/5 transition-colors", { "text-custom-text-100 bg-custom-primary-100/5": item.isActive(), - } + }, )} > = ({ {characterLimit && isAllowed && (
255 ? "text-red-500" : "" - }`} + className={`${ + watch("name").length === 0 || watch("name").length > 255 ? "text-red-500" : "" + }`} > {watch("name").length} @@ -128,28 +129,34 @@ export const IssueDescriptionForm: FC = ({ ( - { - setShowAlert(true); - setIsSubmitting("submitting"); - onChange(description_html); - handleSubmit(handleDescriptionFormSubmit)().finally(() => setIsSubmitting("submitted") - ); - } } /> - )} + render={({ field: { value, onChange } }) => { + console.log(value,'value'); + return ( { + setShowAlert(true); + setIsSubmitting("submitting"); + onChange(description_html); + handleSubmit(handleDescriptionFormSubmit)().finally(() => + setIsSubmitting("submitted") + ); + }} + />); + }} />
{isSubmitting === "submitting" ? "Saving..." : "Saved"}