Merge pull request #3232 from makeplane/release-0.15

fix: moving patch fixes from release 0.15 to 0.14.2
This commit is contained in:
sriram veeraghanta 2023-12-22 18:19:47 +05:30 committed by GitHub
commit dc131ee05b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
142 changed files with 650 additions and 1674 deletions

View File

@ -67,9 +67,7 @@ jobs:
steps: steps:
- name: Set Frontend Docker Tag - name: Set Frontend Docker Tag
run: | run: |
if [[ ${{ needs.branch_build_setup.outputs.gh_branch_name }} == release-* ]]; then if [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ] && [ "${{ github.event_name }}" == "release" ]; then
TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend${{ secrets.DOCKER_REPO_SUFFIX || '' }}-rel:${{ needs.branch_build_setup.outputs.gh_branch_name }}
elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ] && [ "${{ github.event_name }}" == "release" ]; then
TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:latest,${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:${{ github.event.release.tag_name }} TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:latest,${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:${{ github.event.release.tag_name }}
elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ]; then elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ]; then
TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:stable TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-frontend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:stable
@ -111,10 +109,6 @@ jobs:
steps: steps:
- name: Set Space Docker Tag - name: Set Space Docker Tag
run: | run: |
if [[ ${{ needs.branch_build_setup.outputs.gh_branch_name }} == release-* ]]; then
TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-space${{ secrets.DOCKER_REPO_SUFFIX || '' }}-rel:${{ needs.branch_build_setup.outputs.gh_branch_name }}
elif [[ ${{ needs.branch_build_setup.outputs.gh_branch_name }} == release-* ]]; then
TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-space${{ secrets.DOCKER_REPO_SUFFIX || '' }}-re:${{ needs.branch_build_setup.outputs.gh_branch_name }}
if [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ] && [ "${{ github.event_name }}" == "release" ]; then if [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ] && [ "${{ github.event_name }}" == "release" ]; then
TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-space${{ secrets.DOCKER_REPO_SUFFIX || '' }}:latest,${{ secrets.DOCKERHUB_USERNAME }}/plane-space${{ secrets.DOCKER_REPO_SUFFIX || '' }}:${{ github.event.release.tag_name }} TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-space${{ secrets.DOCKER_REPO_SUFFIX || '' }}:latest,${{ secrets.DOCKERHUB_USERNAME }}/plane-space${{ secrets.DOCKER_REPO_SUFFIX || '' }}:${{ github.event.release.tag_name }}
elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ]; then elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ]; then
@ -157,10 +151,6 @@ jobs:
steps: steps:
- name: Set Backend Docker Tag - name: Set Backend Docker Tag
run: | run: |
if [[ ${{ needs.branch_build_setup.outputs.gh_branch_name }} == release-* ]]; then
TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-backend${{ secrets.DOCKER_REPO_SUFFIX || '' }}-rel:${{ needs.branch_build_setup.outputs.gh_branch_name }}
elif [[ ${{ needs.branch_build_setup.outputs.gh_branch_name }} == release-* ]]; then
TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-backend${{ secrets.DOCKER_REPO_SUFFIX || '' }}-re:${{ needs.branch_build_setup.outputs.gh_branch_name }}
if [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ] && [ "${{ github.event_name }}" == "release" ]; then if [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ] && [ "${{ github.event_name }}" == "release" ]; then
TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-backend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:latest,${{ secrets.DOCKERHUB_USERNAME }}/plane-backend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:${{ github.event.release.tag_name }} TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-backend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:latest,${{ secrets.DOCKERHUB_USERNAME }}/plane-backend${{ secrets.DOCKER_REPO_SUFFIX || '' }}:${{ github.event.release.tag_name }}
elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ]; then elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ]; then
@ -203,10 +193,6 @@ jobs:
steps: steps:
- name: Set Proxy Docker Tag - name: Set Proxy Docker Tag
run: | run: |
if [[ ${{ needs.branch_build_setup.outputs.gh_branch_name }} == release-* ]]; then
TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy${{ secrets.DOCKER_REPO_SUFFIX || '' }}-rel:${{ needs.branch_build_setup.outputs.gh_branch_name }}
elif [[ ${{ needs.branch_build_setup.outputs.gh_branch_name }} == release-* ]]; then
TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy${{ secrets.DOCKER_REPO_SUFFIX || '' }}-re:${{ needs.branch_build_setup.outputs.gh_branch_name }}
if [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ] && [ "${{ github.event_name }}" == "release" ]; then if [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ] && [ "${{ github.event_name }}" == "release" ]; then
TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy${{ secrets.DOCKER_REPO_SUFFIX || '' }}:latest,${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy${{ secrets.DOCKER_REPO_SUFFIX || '' }}:${{ github.event.release.tag_name }} TAG=${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy${{ secrets.DOCKER_REPO_SUFFIX || '' }}:latest,${{ secrets.DOCKERHUB_USERNAME }}/plane-proxy${{ secrets.DOCKER_REPO_SUFFIX || '' }}:${{ github.event.release.tag_name }}
elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ]; then elif [ "${{ needs.branch_build_setup.outputs.gh_branch_name }}" == "master" ]; then

View File

@ -291,7 +291,9 @@ CELERY_IMPORTS = (
# Sentry Settings # Sentry Settings
# Enable Sentry Settings # Enable Sentry Settings
if bool(os.environ.get("SENTRY_DSN", False)) and os.environ.get("SENTRY_DSN").startswith("https://"): if bool(os.environ.get("SENTRY_DSN", False)) and os.environ.get(
"SENTRY_DSN"
).startswith("https://"):
sentry_sdk.init( sentry_sdk.init(
dsn=os.environ.get("SENTRY_DSN", ""), dsn=os.environ.get("SENTRY_DSN", ""),
integrations=[ integrations=[
@ -334,3 +336,5 @@ INSTANCE_KEY = os.environ.get(
# Skip environment variable configuration # Skip environment variable configuration
SKIP_ENV_VAR = os.environ.get("SKIP_ENV_VAR", "1") == "1" SKIP_ENV_VAR = os.environ.get("SKIP_ENV_VAR", "1") == "1"
DATA_UPLOAD_MAX_MEMORY_SIZE = int(os.environ.get("FILE_SIZE_LIMIT", 5242880))

View File

@ -28,28 +28,22 @@
"react-dom": "18.2.0" "react-dom": "18.2.0"
}, },
"dependencies": { "dependencies": {
"@plane/editor-types": "*", "@tiptap/core": "^2.1.13",
"@tiptap/core": "^2.1.7",
"@tiptap/extension-blockquote": "^2.1.13", "@tiptap/extension-blockquote": "^2.1.13",
"@tiptap/extension-code-block-lowlight": "^2.1.12", "@tiptap/extension-code-block-lowlight": "^2.1.13",
"@tiptap/extension-color": "^2.1.11", "@tiptap/extension-color": "^2.1.13",
"@tiptap/extension-image": "^2.1.7", "@tiptap/extension-image": "^2.1.13",
"@tiptap/extension-link": "^2.1.7", "@tiptap/extension-link": "^2.1.13",
"@tiptap/extension-list-item": "^2.1.12", "@tiptap/extension-list-item": "^2.1.13",
"@tiptap/extension-mention": "^2.1.12", "@tiptap/extension-mention": "^2.1.13",
"@tiptap/extension-table": "^2.1.6", "@tiptap/extension-task-item": "^2.1.13",
"@tiptap/extension-table-cell": "^2.1.6", "@tiptap/extension-task-list": "^2.1.13",
"@tiptap/extension-table-header": "^2.1.6", "@tiptap/extension-text-style": "^2.1.13",
"@tiptap/extension-table-row": "^2.1.6", "@tiptap/extension-underline": "^2.1.13",
"@tiptap/extension-task-item": "^2.1.7", "@tiptap/pm": "^2.1.13",
"@tiptap/extension-task-list": "^2.1.7", "@tiptap/react": "^2.1.13",
"@tiptap/extension-text-style": "^2.1.11", "@tiptap/starter-kit": "^2.1.13",
"@tiptap/extension-underline": "^2.1.7", "@tiptap/suggestion": "^2.0.13",
"@tiptap/pm": "^2.1.7",
"@tiptap/prosemirror-tables": "^1.1.4",
"@tiptap/react": "^2.1.7",
"@tiptap/starter-kit": "^2.1.10",
"@tiptap/suggestion": "^2.0.4",
"class-variance-authority": "^0.7.0", "class-variance-authority": "^0.7.0",
"clsx": "^1.2.1", "clsx": "^1.2.1",
"highlight.js": "^11.8.0", "highlight.js": "^11.8.0",

View File

@ -1,10 +1,13 @@
import { useEditor as useCustomEditor, Editor } from "@tiptap/react"; import { useEditor as useCustomEditor, Editor } from "@tiptap/react";
import { useImperativeHandle, useRef, MutableRefObject } from "react"; import { useImperativeHandle, useRef, MutableRefObject } from "react";
import { CoreEditorProps } from "../props"; import { CoreEditorProps } from "src/ui/props";
import { CoreEditorExtensions } from "../extensions"; import { CoreEditorExtensions } from "src/ui/extensions";
import { EditorProps } from "@tiptap/pm/view"; import { EditorProps } from "@tiptap/pm/view";
import { getTrimmedHTML } from "../../lib/utils"; import { getTrimmedHTML } from "src/lib/utils";
import { DeleteImage, IMentionSuggestion, RestoreImage, UploadImage } from "@plane/editor-types"; import { DeleteImage } from "src/types/delete-image";
import { IMentionSuggestion } from "src/types/mention-suggestion";
import { RestoreImage } from "src/types/restore-image";
import { UploadImage } from "src/types/upload-image";
interface CustomEditorProps { interface CustomEditorProps {
uploadFile: UploadImage; uploadFile: UploadImage;

View File

@ -1,9 +1,9 @@
import { useEditor as useCustomEditor, Editor } from "@tiptap/react"; import { useEditor as useCustomEditor, Editor } from "@tiptap/react";
import { useImperativeHandle, useRef, MutableRefObject } from "react"; import { useImperativeHandle, useRef, MutableRefObject } from "react";
import { CoreReadOnlyEditorExtensions } from "../read-only/extensions"; import { CoreReadOnlyEditorExtensions } from "src/ui/read-only/extensions";
import { CoreReadOnlyEditorProps } from "../read-only/props"; import { CoreReadOnlyEditorProps } from "src/ui/read-only/props";
import { EditorProps } from "@tiptap/pm/view"; import { EditorProps } from "@tiptap/pm/view";
import { IMentionSuggestion } from "@plane/editor-types"; import { IMentionSuggestion } from "src/types/mention-suggestion";
interface CustomReadOnlyEditorProps { interface CustomReadOnlyEditorProps {
value: string; value: string;

View File

@ -1,23 +1,32 @@
// styles // styles
// import "./styles/tailwind.css"; // import "./styles/tailwind.css";
// import "./styles/editor.css"; import "src/styles/editor.css";
import "./styles/github-dark.css"; import "src/styles/table.css";
import "src/styles/github-dark.css";
export { isCellSelection } from "./ui/extensions/table/table/utilities/is-cell-selection"; export { isCellSelection } from "src/ui/extensions/table/table/utilities/is-cell-selection";
// utils // utils
export * from "./lib/utils"; export * from "src/lib/utils";
export * from "./ui/extensions/table/table"; export * from "src/ui/extensions/table/table";
export { startImageUpload } from "./ui/plugins/upload-image"; export { startImageUpload } from "src/ui/plugins/upload-image";
// components // components
export { EditorContainer } from "./ui/components/editor-container"; export { EditorContainer } from "src/ui/components/editor-container";
export { EditorContentWrapper } from "./ui/components/editor-content"; export { EditorContentWrapper } from "src/ui/components/editor-content";
// hooks // hooks
export { useEditor } from "./ui/hooks/use-editor"; export { useEditor } from "src/hooks/use-editor";
export { useReadOnlyEditor } from "./ui/hooks/use-read-only-editor"; export { useReadOnlyEditor } from "src/hooks/use-read-only-editor";
// helper items // helper items
export * from "./ui/menus/menu-items"; export * from "src/ui/menus/menu-items";
export * from "./lib/editor-commands"; export * from "src/lib/editor-commands";
// types
export type { DeleteImage } from "src/types/delete-image";
export type { UploadImage } from "src/types/upload-image";
export type { RestoreImage } from "src/types/restore-image";
export type { IMentionHighlight, IMentionSuggestion } from "src/types/mention-suggestion";
export type { ISlashCommandItem, CommandProps } from "src/types/slash-commands-suggestion";
export type { LucideIconType } from "src/types/lucide-icon";

View File

@ -1,7 +1,7 @@
import { UploadImage } from "@plane/editor-types";
import { Editor, Range } from "@tiptap/core"; import { Editor, Range } from "@tiptap/core";
import { startImageUpload } from "../ui/plugins/upload-image"; import { startImageUpload } from "src/ui/plugins/upload-image";
import { findTableAncestor } from "./utils"; import { findTableAncestor } from "src/lib/utils";
import { UploadImage } from "src/types/upload-image";
export const toggleHeadingOne = (editor: Editor, range?: Range) => { export const toggleHeadingOne = (editor: Editor, range?: Range) => {
if (range) editor.chain().focus().deleteRange(range).setNode("heading", { level: 1 }).run(); if (range) editor.chain().focus().deleteRange(range).setNode("heading", { level: 1 }).run();

View File

@ -6,6 +6,12 @@
height: 0; height: 0;
} }
/* block quotes */
.ProseMirror blockquote p::before,
.ProseMirror blockquote p::after {
display: none;
}
.ProseMirror .is-empty::before { .ProseMirror .is-empty::before {
content: attr(data-placeholder); content: attr(data-placeholder);
float: left; float: left;
@ -15,9 +21,10 @@
} }
/* Custom image styles */ /* Custom image styles */
.ProseMirror img { .ProseMirror img {
transition: filter 0.1s ease-in-out; transition: filter 0.1s ease-in-out;
margin-top: 0 !important;
margin-bottom: 0 !important;
&:hover { &:hover {
cursor: pointer; cursor: pointer;
@ -53,11 +60,12 @@ ul[data-type="taskList"] li > label input[type="checkbox"] {
background-color: rgb(var(--color-background-100)); background-color: rgb(var(--color-background-100));
margin: 0; margin: 0;
cursor: pointer; cursor: pointer;
width: 1.2rem; width: 0.8rem;
height: 1.2rem; height: 0.8rem;
position: relative; position: relative;
border: 2px solid rgb(var(--color-text-100)); border: 1.5px solid rgb(var(--color-text-100));
margin-right: 0.3rem; margin-right: 0.2rem;
margin-top: 0.15rem;
display: grid; display: grid;
place-content: center; place-content: center;
@ -71,8 +79,8 @@ ul[data-type="taskList"] li > label input[type="checkbox"] {
&::before { &::before {
content: ""; content: "";
width: 0.65em; width: 0.5em;
height: 0.65em; height: 0.5em;
transform: scale(0); transform: scale(0);
transition: 120ms transform ease-in-out; transition: 120ms transform ease-in-out;
box-shadow: inset 1em 1em; box-shadow: inset 1em 1em;
@ -133,6 +141,8 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
.img-placeholder { .img-placeholder {
position: relative; position: relative;
width: 35%; width: 35%;
margin-top: 0 !important;
margin-bottom: 0 !important;
&:before { &:before {
content: ""; content: "";
@ -159,7 +169,8 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
table { table {
border-collapse: collapse; border-collapse: collapse;
table-layout: fixed; table-layout: fixed;
margin: 0; margin: 0.5em 0 0.5em 0;
border: 1px solid rgb(var(--color-border-200)); border: 1px solid rgb(var(--color-border-200));
width: 100%; width: 100%;
@ -229,3 +240,34 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
.ProseMirror table * .is-empty::before { .ProseMirror table * .is-empty::before {
opacity: 0; opacity: 0;
} }
.ProseMirror pre {
background: rgba(var(--color-background-80));
border-radius: 0.5rem;
color: rgba(var(--color-text-100));
font-family: "JetBrainsMono", monospace;
padding: 0.75rem 1rem;
}
.ProseMirror pre code {
background: none;
color: inherit;
font-size: 0.8rem;
padding: 0;
}
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));
}
}
/* image resizer */
.moveable-control-box {
z-index: 10 !important;
}

View File

@ -0,0 +1,3 @@
import { Smile } from "lucide-react";
export type LucideIconType = typeof Smile;

View File

@ -1,6 +1,6 @@
import { Editor, EditorContent } from "@tiptap/react"; import { Editor, EditorContent } from "@tiptap/react";
import { ReactNode } from "react"; import { ReactNode } from "react";
import { ImageResizer } from "../extensions/image/image-resize"; import { ImageResizer } from "src/ui/extensions/image/image-resize";
interface EditorContentProps { interface EditorContentProps {
editor: Editor | null; editor: Editor | null;

View File

@ -1,7 +1,7 @@
import { getNodeAtPosition } from "@tiptap/core"; import { getNodeAtPosition } from "@tiptap/core";
import { EditorState } from "@tiptap/pm/state"; import { EditorState } from "@tiptap/pm/state";
import { findListItemPos } from "./find-list-item-pos"; import { findListItemPos } from "src/ui/extensions/custom-list-keymap/list-helpers/find-list-item-pos";
export const getNextListDepth = (typeOrName: string, state: EditorState) => { export const getNextListDepth = (typeOrName: string, state: EditorState) => {
const listItemPos = findListItemPos(typeOrName, state); const listItemPos = findListItemPos(typeOrName, state);

View File

@ -1,8 +1,8 @@
import { Editor, isAtStartOfNode, isNodeActive } from "@tiptap/core"; import { Editor, isAtStartOfNode, isNodeActive } from "@tiptap/core";
import { Node } from "@tiptap/pm/model"; import { Node } from "@tiptap/pm/model";
import { findListItemPos } from "./find-list-item-pos"; import { findListItemPos } from "src/ui/extensions/custom-list-keymap/list-helpers/find-list-item-pos";
import { hasListBefore } from "./has-list-before"; import { hasListBefore } from "src/ui/extensions/custom-list-keymap/list-helpers/has-list-before";
export const handleBackspace = (editor: Editor, name: string, parentListTypes: string[]) => { export const handleBackspace = (editor: Editor, name: string, parentListTypes: string[]) => {
// this is required to still handle the undo handling // this is required to still handle the undo handling

View File

@ -1,7 +1,7 @@
import { Editor, isAtEndOfNode, isNodeActive } from "@tiptap/core"; import { Editor, isAtEndOfNode, isNodeActive } from "@tiptap/core";
import { nextListIsDeeper } from "./next-list-is-deeper"; import { nextListIsDeeper } from "src/ui/extensions/custom-list-keymap/list-helpers/next-list-is-deeper";
import { nextListIsHigher } from "./next-list-is-higher"; import { nextListIsHigher } from "src/ui/extensions/custom-list-keymap/list-helpers/next-list-is-higher";
export const handleDelete = (editor: Editor, name: string) => { export const handleDelete = (editor: Editor, name: string) => {
// if the cursor is not inside the current node type // if the cursor is not inside the current node type

View File

@ -1,7 +1,7 @@
import { EditorState } from "@tiptap/pm/state"; import { EditorState } from "@tiptap/pm/state";
import { findListItemPos } from "./find-list-item-pos"; import { findListItemPos } from "src/ui/extensions/custom-list-keymap/list-helpers/find-list-item-pos";
import { getNextListDepth } from "./get-next-list-depth"; import { getNextListDepth } from "src/ui/extensions/custom-list-keymap/list-helpers/get-next-list-depth";
export const nextListIsDeeper = (typeOrName: string, state: EditorState) => { export const nextListIsDeeper = (typeOrName: string, state: EditorState) => {
const listDepth = getNextListDepth(typeOrName, state); const listDepth = getNextListDepth(typeOrName, state);

View File

@ -1,7 +1,7 @@
import { EditorState } from "@tiptap/pm/state"; import { EditorState } from "@tiptap/pm/state";
import { findListItemPos } from "./find-list-item-pos"; import { findListItemPos } from "src/ui/extensions/custom-list-keymap/list-helpers/find-list-item-pos";
import { getNextListDepth } from "./get-next-list-depth"; import { getNextListDepth } from "src/ui/extensions/custom-list-keymap/list-helpers/get-next-list-depth";
export const nextListIsHigher = (typeOrName: string, state: EditorState) => { export const nextListIsHigher = (typeOrName: string, state: EditorState) => {
const listDepth = getNextListDepth(typeOrName, state); const listDepth = getNextListDepth(typeOrName, state);

View File

@ -1,6 +1,6 @@
import { Extension } from "@tiptap/core"; import { Extension } from "@tiptap/core";
import { handleBackspace, handleDelete } from "./list-helpers"; import { handleBackspace, handleDelete } from "src/ui/extensions/custom-list-keymap/list-helpers";
export type ListKeymapOptions = { export type ListKeymapOptions = {
listTypes: Array<{ listTypes: Array<{

View File

@ -22,7 +22,7 @@ declare module "@tiptap/core" {
} }
} }
export default Node.create<HorizontalRuleOptions>({ export const HorizontalRule = Node.create<HorizontalRuleOptions>({
name: "horizontalRule", name: "horizontalRule",
addOptions() { addOptions() {

View File

@ -1,9 +1,10 @@
import { EditorState, Plugin, PluginKey, Transaction } from "@tiptap/pm/state"; import { EditorState, Plugin, PluginKey, Transaction } from "@tiptap/pm/state";
import { Node as ProseMirrorNode } from "@tiptap/pm/model"; import { Node as ProseMirrorNode } from "@tiptap/pm/model";
import UploadImagesPlugin from "../../plugins/upload-image"; import { UploadImagesPlugin } from "src/ui/plugins/upload-image";
import ImageExt from "@tiptap/extension-image"; import ImageExt from "@tiptap/extension-image";
import { onNodeDeleted, onNodeRestored } from "../../plugins/delete-image"; import { onNodeDeleted, onNodeRestored } from "src/ui/plugins/delete-image";
import { DeleteImage, RestoreImage } from "@plane/editor-types"; import { DeleteImage } from "src/types/delete-image";
import { RestoreImage } from "src/types/restore-image";
interface ImageNode extends ProseMirrorNode { interface ImageNode extends ProseMirrorNode {
attrs: { attrs: {
@ -15,7 +16,7 @@ interface ImageNode extends ProseMirrorNode {
const deleteKey = new PluginKey("delete-image"); const deleteKey = new PluginKey("delete-image");
const IMAGE_NODE_TYPE = "image"; const IMAGE_NODE_TYPE = "image";
const ImageExtension = (deleteImage: DeleteImage, restoreFile: RestoreImage, cancelUploadImage?: () => any) => export const ImageExtension = (deleteImage: DeleteImage, restoreFile: RestoreImage, cancelUploadImage?: () => any) =>
ImageExt.extend({ ImageExt.extend({
addProseMirrorPlugins() { addProseMirrorPlugins() {
return [ return [
@ -130,5 +131,3 @@ const ImageExtension = (deleteImage: DeleteImage, restoreFile: RestoreImage, can
}; };
}, },
}); });
export default ImageExtension;

View File

@ -1,6 +1,6 @@
import Image from "@tiptap/extension-image"; import Image from "@tiptap/extension-image";
const ReadOnlyImageExtension = Image.extend({ export const ReadOnlyImageExtension = Image.extend({
addAttributes() { addAttributes() {
return { return {
...this.parent?.(), ...this.parent?.(),
@ -13,5 +13,3 @@ const ReadOnlyImageExtension = Image.extend({
}; };
}, },
}); });
export default ReadOnlyImageExtension;

View File

@ -7,22 +7,25 @@ import TaskItem from "@tiptap/extension-task-item";
import TaskList from "@tiptap/extension-task-list"; import TaskList from "@tiptap/extension-task-list";
import { Markdown } from "tiptap-markdown"; import { Markdown } from "tiptap-markdown";
import TableHeader from "./table/table-header/table-header"; import { TableHeader } from "src/ui/extensions/table/table-header/table-header";
import Table from "./table/table"; import { Table } from "src/ui/extensions/table/table";
import TableCell from "./table/table-cell/table-cell"; import { TableCell } from "src/ui/extensions/table/table-cell/table-cell";
import TableRow from "./table/table-row/table-row"; import { TableRow } from "src/ui/extensions/table/table-row/table-row";
import HorizontalRule from "./horizontal-rule"; import { HorizontalRule } from "src/ui/extensions/horizontal-rule";
import ImageExtension from "./image"; import { ImageExtension } from "src/ui/extensions/image";
import { isValidHttpUrl } from "../../lib/utils"; import { isValidHttpUrl } from "src/lib/utils";
import { Mentions } from "../mentions"; import { Mentions } from "src/ui/mentions";
import { CustomKeymap } from "./keymap"; import { CustomKeymap } from "src/ui/extensions/keymap";
import { CustomCodeBlock } from "./code"; import { CustomCodeBlock } from "src/ui/extensions/code";
import { CustomQuoteExtension } from "./quote"; import { CustomQuoteExtension } from "src/ui/extensions/quote";
import { ListKeymap } from "./custom-list-keymap"; import { ListKeymap } from "src/ui/extensions/custom-list-keymap";
import { IMentionSuggestion, DeleteImage, RestoreImage } from "@plane/editor-types";
import { DeleteImage } from "src/types/delete-image";
import { IMentionSuggestion } from "src/types/mention-suggestion";
import { RestoreImage } from "src/types/restore-image";
export const CoreEditorExtensions = ( export const CoreEditorExtensions = (
mentionConfig: { mentionConfig: {

View File

@ -1 +1 @@
export { default as default } from "./table-cell"; export { TableCell } from "./table-cell";

View File

@ -4,7 +4,7 @@ export interface TableCellOptions {
HTMLAttributes: Record<string, any>; HTMLAttributes: Record<string, any>;
} }
export default Node.create<TableCellOptions>({ export const TableCell = Node.create<TableCellOptions>({
name: "tableCell", name: "tableCell",
addOptions() { addOptions() {

View File

@ -1 +1 @@
export { default as default } from "./table-header"; export { TableHeader } from "./table-header";

View File

@ -3,7 +3,8 @@ import { mergeAttributes, Node } from "@tiptap/core";
export interface TableHeaderOptions { export interface TableHeaderOptions {
HTMLAttributes: Record<string, any>; HTMLAttributes: Record<string, any>;
} }
export default Node.create<TableHeaderOptions>({
export const TableHeader = Node.create<TableHeaderOptions>({
name: "tableHeader", name: "tableHeader",
addOptions() { addOptions() {

View File

@ -1 +1 @@
export { default as default } from "./table-row"; export { TableRow } from "./table-row";

View File

@ -4,7 +4,7 @@ export interface TableRowOptions {
HTMLAttributes: Record<string, any>; HTMLAttributes: Record<string, any>;
} }
export default Node.create<TableRowOptions>({ export const TableRow = Node.create<TableRowOptions>({
name: "tableRow", name: "tableRow",
addOptions() { addOptions() {

View File

@ -1,4 +1,4 @@
const icons = { export const icons = {
colorPicker: `<svg xmlns="http://www.w3.org/2000/svg" length="24" viewBox="0 0 24 24" style="transform: ;msFilter:;"><path fill="rgb(var(--color-text-300))" d="M20 14c-.092.064-2 2.083-2 3.5 0 1.494.949 2.448 2 2.5.906.044 2-.891 2-2.5 0-1.5-1.908-3.436-2-3.5zM9.586 20c.378.378.88.586 1.414.586s1.036-.208 1.414-.586l7-7-.707-.707L11 4.586 8.707 2.293 7.293 3.707 9.586 6 4 11.586c-.378.378-.586.88-.586 1.414s.208 1.036.586 1.414L9.586 20zM11 7.414 16.586 13H5.414L11 7.414z"></path></svg>`, colorPicker: `<svg xmlns="http://www.w3.org/2000/svg" length="24" viewBox="0 0 24 24" style="transform: ;msFilter:;"><path fill="rgb(var(--color-text-300))" d="M20 14c-.092.064-2 2.083-2 3.5 0 1.494.949 2.448 2 2.5.906.044 2-.891 2-2.5 0-1.5-1.908-3.436-2-3.5zM9.586 20c.378.378.88.586 1.414.586s1.036-.208 1.414-.586l7-7-.707-.707L11 4.586 8.707 2.293 7.293 3.707 9.586 6 4 11.586c-.378.378-.586.88-.586 1.414s.208 1.036.586 1.414L9.586 20zM11 7.414 16.586 13H5.414L11 7.414z"></path></svg>`,
deleteColumn: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" length="24"><path fill="#e53e3e" d="M0 0H24V24H0z"/><path d="M12 3c.552 0 1 .448 1 1v8c.835-.628 1.874-1 3-1 2.761 0 5 2.239 5 5s-2.239 5-5 5c-1.032 0-1.99-.313-2.787-.848L13 20c0 .552-.448 1-1 1H6c-.552 0-1-.448-1-1V4c0-.552.448-1 1-1h6zm-1 2H7v14h4V5zm8 10h-6v2h6v-2z"/></svg>`, deleteColumn: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" length="24"><path fill="#e53e3e" d="M0 0H24V24H0z"/><path d="M12 3c.552 0 1 .448 1 1v8c.835-.628 1.874-1 3-1 2.761 0 5 2.239 5 5s-2.239 5-5 5c-1.032 0-1.99-.313-2.787-.848L13 20c0 .552-.448 1-1 1H6c-.552 0-1-.448-1-1V4c0-.552.448-1 1-1h6zm-1 2H7v14h4V5zm8 10h-6v2h6v-2z"/></svg>`,
deleteRow: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" length="24"><path fill="#e53e3e" d="M0 0H24V24H0z"/><path d="M20 5c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1 .628.835 1 1.874 1 3 0 2.761-2.239 5-5 5s-5-2.239-5-5c0-1.126.372-2.165 1-3H4c-.552 0-1-.448-1-1V6c0-.552.448-1 1-1h16zm-7 10v2h6v-2h-6zm6-8H5v4h14V7z"/></svg>`, deleteRow: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" length="24"><path fill="#e53e3e" d="M0 0H24V24H0z"/><path d="M20 5c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1 .628.835 1 1.874 1 3 0 2.761-2.239 5-5 5s-5-2.239-5-5c0-1.126.372-2.165 1-3H4c-.552 0-1-.448-1-1V6c0-.552.448-1 1-1h16zm-7 10v2h6v-2h-6zm6-8H5v4h14V7z"/></svg>`,
@ -47,5 +47,3 @@ const icons = {
</svg> </svg>
`, `,
}; };
export default icons;

View File

@ -1 +1 @@
export { default as default } from "./table"; export { Table } from "./table";

View File

@ -4,9 +4,9 @@ import { Decoration, NodeView } from "@tiptap/pm/view";
import tippy, { Instance, Props } from "tippy.js"; import tippy, { Instance, Props } from "tippy.js";
import { Editor } from "@tiptap/core"; import { Editor } from "@tiptap/core";
import { CellSelection, TableMap, updateColumnsOnResize } from "@tiptap/prosemirror-tables"; import { CellSelection, TableMap, updateColumnsOnResize } from "@tiptap/pm/tables";
import icons from "./icons"; import { icons } from "src/ui/extensions/table/table/icons";
export function updateColumns( export function updateColumns(
node: ProseMirrorNode, node: ProseMirrorNode,

View File

@ -19,12 +19,12 @@ import {
tableEditing, tableEditing,
toggleHeader, toggleHeader,
toggleHeaderCell, toggleHeaderCell,
} from "@tiptap/prosemirror-tables"; } from "@tiptap/pm/tables";
import { tableControls } from "./table-controls"; import { tableControls } from "src/ui/extensions/table/table/table-controls";
import { TableView } from "./table-view"; import { TableView } from "src/ui/extensions/table/table/table-view";
import { createTable } from "./utilities/create-table"; import { createTable } from "src/ui/extensions/table/table/utilities/create-table";
import { deleteTableWhenAllCellsSelected } from "./utilities/delete-table-when-all-cells-selected"; import { deleteTableWhenAllCellsSelected } from "src/ui/extensions/table/table/utilities/delete-table-when-all-cells-selected";
export interface TableOptions { export interface TableOptions {
HTMLAttributes: Record<string, any>; HTMLAttributes: Record<string, any>;
@ -72,7 +72,7 @@ declare module "@tiptap/core" {
} }
} }
export default Node.create({ export const Table = Node.create({
name: "table", name: "table",
addOptions() { addOptions() {

View File

@ -1,7 +1,7 @@
import { Fragment, Node as ProsemirrorNode, Schema } from "@tiptap/pm/model"; import { Fragment, Node as ProsemirrorNode, Schema } from "@tiptap/pm/model";
import { createCell } from "./create-cell"; import { createCell } from "src/ui/extensions/table/table/utilities/create-cell";
import { getTableNodeTypes } from "./get-table-node-types"; import { getTableNodeTypes } from "src/ui/extensions/table/table/utilities/get-table-node-types";
export function createTable( export function createTable(
schema: Schema, schema: Schema,

View File

@ -1,6 +1,6 @@
import { findParentNodeClosestToPos, KeyboardShortcutCommand } from "@tiptap/core"; import { findParentNodeClosestToPos, KeyboardShortcutCommand } from "@tiptap/core";
import { isCellSelection } from "./is-cell-selection"; import { isCellSelection } from "src/ui/extensions/table/table/utilities/is-cell-selection";
export const deleteTableWhenAllCellsSelected: KeyboardShortcutCommand = ({ editor }) => { export const deleteTableWhenAllCellsSelected: KeyboardShortcutCommand = ({ editor }) => {
const { selection } = editor.state; const { selection } = editor.state;

View File

@ -1,4 +1,4 @@
import { CellSelection } from "@tiptap/prosemirror-tables"; import { CellSelection } from "@tiptap/pm/tables";
export function isCellSelection(value: unknown): value is CellSelection { export function isCellSelection(value: unknown): value is CellSelection {
return value instanceof CellSelection; return value instanceof CellSelection;

View File

@ -1,8 +1,8 @@
import { Mention, MentionOptions } from "@tiptap/extension-mention"; import { Mention, MentionOptions } from "@tiptap/extension-mention";
import { mergeAttributes } from "@tiptap/core"; import { mergeAttributes } from "@tiptap/core";
import { ReactNodeViewRenderer } from "@tiptap/react"; import { ReactNodeViewRenderer } from "@tiptap/react";
import mentionNodeView from "./mentionNodeView"; import { MentionNodeView } from "src/ui/mentions/mention-node-view";
import { IMentionHighlight } from "@plane/editor-types"; import { IMentionHighlight } from "src/types/mention-suggestion";
export interface CustomMentionOptions extends MentionOptions { export interface CustomMentionOptions extends MentionOptions {
mentionHighlights: IMentionHighlight[]; mentionHighlights: IMentionHighlight[];
@ -31,7 +31,7 @@ export const CustomMention = Mention.extend<CustomMentionOptions>({
}, },
addNodeView() { addNodeView() {
return ReactNodeViewRenderer(mentionNodeView); return ReactNodeViewRenderer(MentionNodeView);
}, },
parseHTML() { parseHTML() {

View File

@ -1,8 +1,8 @@
// @ts-nocheck // @ts-nocheck
import suggestion from "./suggestion"; import { Suggestion } from "src/ui/mentions/suggestion";
import { CustomMention } from "./custom"; import { CustomMention } from "src/ui/mentions/custom";
import { IMentionHighlight, IMentionSuggestion } from "@plane/editor-types"; import { IMentionHighlight } from "src/types/mention-suggestion";
export const Mentions = (mentionSuggestions: IMentionSuggestion[], mentionHighlights: IMentionHighlight[], readonly) => export const Mentions = (mentionSuggestions: IMentionSuggestion[], mentionHighlights: IMentionHighlight[], readonly) =>
CustomMention.configure({ CustomMention.configure({
@ -11,5 +11,5 @@ export const Mentions = (mentionSuggestions: IMentionSuggestion[], mentionHighli
}, },
readonly: readonly, readonly: readonly,
mentionHighlights: mentionHighlights, mentionHighlights: mentionHighlights,
suggestion: suggestion(mentionSuggestions), suggestion: Suggestion(mentionSuggestions),
}); });

View File

@ -1,6 +1,6 @@
import { IMentionSuggestion } from "@plane/editor-types";
import { Editor } from "@tiptap/react"; import { Editor } from "@tiptap/react";
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useState } from "react"; import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
import { IMentionSuggestion } from "src/types/mention-suggestion";
interface MentionListProps { interface MentionListProps {
items: IMentionSuggestion[]; items: IMentionSuggestion[];
@ -9,7 +9,7 @@ interface MentionListProps {
} }
// eslint-disable-next-line react/display-name // eslint-disable-next-line react/display-name
const MentionList = forwardRef((props: MentionListProps, ref) => { export const MentionList = forwardRef((props: MentionListProps, ref) => {
const [selectedIndex, setSelectedIndex] = useState(0); const [selectedIndex, setSelectedIndex] = useState(0);
const selectItem = (index: number) => { const selectItem = (index: number) => {
@ -98,5 +98,3 @@ const MentionList = forwardRef((props: MentionListProps, ref) => {
}); });
MentionList.displayName = "MentionList"; MentionList.displayName = "MentionList";
export default MentionList;

View File

@ -1,12 +1,12 @@
/* eslint-disable react/display-name */ /* eslint-disable react/display-name */
// @ts-nocheck // @ts-nocheck
import { NodeViewWrapper } from "@tiptap/react"; import { NodeViewWrapper } from "@tiptap/react";
import { cn } from "../../lib/utils"; import { cn } from "src/lib/utils";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { IMentionHighlight } from "@plane/editor-types"; import { IMentionHighlight } from "src/types/mention-suggestion";
// eslint-disable-next-line import/no-anonymous-default-export // eslint-disable-next-line import/no-anonymous-default-export
export default (props) => { export const MentionNodeView = (props) => {
const router = useRouter(); const router = useRouter();
const highlights = props.extension.options.mentionHighlights as IMentionHighlight[]; const highlights = props.extension.options.mentionHighlights as IMentionHighlight[];

View File

@ -2,10 +2,10 @@ import { ReactRenderer } from "@tiptap/react";
import { Editor } from "@tiptap/core"; import { Editor } from "@tiptap/core";
import tippy from "tippy.js"; import tippy from "tippy.js";
import MentionList from "./MentionList"; import { MentionList } from "src/ui/mentions/mention-list";
import { IMentionSuggestion } from "@plane/editor-types"; import { IMentionSuggestion } from "src/types/mention-suggestion";
const Suggestion = (suggestions: IMentionSuggestion[]) => ({ export const Suggestion = (suggestions: IMentionSuggestion[]) => ({
items: ({ query }: { query: string }) => items: ({ query }: { query: string }) =>
suggestions.filter((suggestion) => suggestion.title.toLowerCase().startsWith(query.toLowerCase())).slice(0, 5), suggestions.filter((suggestion) => suggestion.title.toLowerCase().startsWith(query.toLowerCase())).slice(0, 5),
render: () => { render: () => {
@ -55,5 +55,3 @@ const Suggestion = (suggestions: IMentionSuggestion[]) => ({
}; };
}, },
}); });
export default Suggestion;

View File

@ -30,14 +30,15 @@ import {
toggleStrike, toggleStrike,
toggleTaskList, toggleTaskList,
toggleUnderline, toggleUnderline,
} from "../../../lib/editor-commands"; } from "src/lib/editor-commands";
import { UploadImage } from "@plane/editor-types"; import { LucideIconType } from "src/types/lucide-icon";
import { UploadImage } from "src/types/upload-image";
export interface EditorMenuItem { export interface EditorMenuItem {
name: string; name: string;
isActive: () => boolean; isActive: () => boolean;
command: () => void; command: () => void;
icon: typeof BoldIcon; icon: LucideIconType;
} }
export const HeadingOneItem = (editor: Editor): EditorMenuItem => ({ export const HeadingOneItem = (editor: Editor): EditorMenuItem => ({

View File

@ -1,6 +1,7 @@
import { EditorState, Plugin, PluginKey, Transaction } from "@tiptap/pm/state"; import { EditorState, Plugin, PluginKey, Transaction } from "@tiptap/pm/state";
import { Node as ProseMirrorNode } from "@tiptap/pm/model"; import { Node as ProseMirrorNode } from "@tiptap/pm/model";
import { DeleteImage, RestoreImage } from "@plane/editor-types"; import { DeleteImage } from "src/types/delete-image";
import { RestoreImage } from "src/types/restore-image";
const deleteKey = new PluginKey("delete-image"); const deleteKey = new PluginKey("delete-image");
const IMAGE_NODE_TYPE = "image"; const IMAGE_NODE_TYPE = "image";
@ -12,7 +13,7 @@ interface ImageNode extends ProseMirrorNode {
}; };
} }
const TrackImageDeletionPlugin = (deleteImage: DeleteImage): Plugin => export const TrackImageDeletionPlugin = (deleteImage: DeleteImage): Plugin =>
new Plugin({ new Plugin({
key: deleteKey, key: deleteKey,
appendTransaction: (transactions: readonly Transaction[], oldState: EditorState, newState: EditorState) => { appendTransaction: (transactions: readonly Transaction[], oldState: EditorState, newState: EditorState) => {
@ -53,8 +54,6 @@ const TrackImageDeletionPlugin = (deleteImage: DeleteImage): Plugin =>
}, },
}); });
export default TrackImageDeletionPlugin;
export async function onNodeDeleted(src: string, deleteImage: DeleteImage): Promise<void> { export async function onNodeDeleted(src: string, deleteImage: DeleteImage): Promise<void> {
try { try {
const assetUrlWithWorkspaceId = new URL(src).pathname.substring(1); const assetUrlWithWorkspaceId = new URL(src).pathname.substring(1);

View File

@ -1,10 +1,10 @@
import { UploadImage } from "@plane/editor-types";
import { EditorState, Plugin, PluginKey } from "@tiptap/pm/state"; import { EditorState, Plugin, PluginKey } from "@tiptap/pm/state";
import { Decoration, DecorationSet, EditorView } from "@tiptap/pm/view"; import { Decoration, DecorationSet, EditorView } from "@tiptap/pm/view";
import { UploadImage } from "src/types/upload-image";
const uploadKey = new PluginKey("upload-image"); const uploadKey = new PluginKey("upload-image");
const UploadImagesPlugin = (cancelUploadImage?: () => any) => export const UploadImagesPlugin = (cancelUploadImage?: () => any) =>
new Plugin({ new Plugin({
key: uploadKey, key: uploadKey,
state: { state: {
@ -43,7 +43,7 @@ const UploadImagesPlugin = (cancelUploadImage?: () => any) =>
cancelButton.appendChild(svgElement); cancelButton.appendChild(svgElement);
placeholder.appendChild(cancelButton); placeholder.appendChild(cancelButton);
const deco = Decoration.widget(pos + 1, placeholder, { const deco = Decoration.widget(pos, placeholder, {
id, id,
}); });
set = set.add(tr.doc, [deco]); set = set.add(tr.doc, [deco]);
@ -60,8 +60,6 @@ const UploadImagesPlugin = (cancelUploadImage?: () => any) =>
}, },
}); });
export default UploadImagesPlugin;
function findPlaceholder(state: EditorState, id: {}) { function findPlaceholder(state: EditorState, id: {}) {
const decos = uploadKey.getState(state); const decos = uploadKey.getState(state);
const found = decos.find(undefined, undefined, (spec: { id: number | undefined }) => spec.id == id); const found = decos.find(undefined, undefined, (spec: { id: number | undefined }) => spec.id == id);
@ -133,7 +131,8 @@ export async function startImageUpload(
const imageSrc = typeof src === "object" ? reader.result : src; const imageSrc = typeof src === "object" ? reader.result : src;
const node = schema.nodes.image.create({ src: imageSrc }); const node = schema.nodes.image.create({ src: imageSrc });
const transaction = view.state.tr.replaceWith(pos, pos, node).setMeta(uploadKey, { remove: { id } }); const transaction = view.state.tr.insert(pos - 1, node).setMeta(uploadKey, { remove: { id } });
view.dispatch(transaction); view.dispatch(transaction);
} catch (error) { } catch (error) {
console.error("Upload error: ", error); console.error("Upload error: ", error);

View File

@ -1,7 +1,7 @@
import { UploadImage } from "@plane/editor-types";
import { EditorProps } from "@tiptap/pm/view"; import { EditorProps } from "@tiptap/pm/view";
import { findTableAncestor } from "../lib/utils"; import { findTableAncestor } from "src/lib/utils";
import { startImageUpload } from "./plugins/upload-image"; import { UploadImage } from "src/types/upload-image";
import { startImageUpload } from "src/ui/plugins/upload-image";
export function CoreEditorProps( export function CoreEditorProps(
uploadFile: UploadImage, uploadFile: UploadImage,

View File

@ -8,15 +8,16 @@ import TaskList from "@tiptap/extension-task-list";
import { Markdown } from "tiptap-markdown"; import { Markdown } from "tiptap-markdown";
import Gapcursor from "@tiptap/extension-gapcursor"; import Gapcursor from "@tiptap/extension-gapcursor";
import TableHeader from "../extensions/table/table-header/table-header"; import { TableHeader } from "src/ui/extensions/table/table-header/table-header";
import Table from "../extensions/table/table"; import { Table } from "src/ui/extensions/table/table";
import TableCell from "../extensions/table/table-cell/table-cell"; import { TableCell } from "src/ui/extensions/table/table-cell/table-cell";
import TableRow from "../extensions/table/table-row/table-row"; import { TableRow } from "src/ui/extensions/table/table-row/table-row";
import { HorizontalRule } from "src/ui/extensions/horizontal-rule";
import ReadOnlyImageExtension from "../extensions/image/read-only-image"; import { ReadOnlyImageExtension } from "src/ui/extensions/image/read-only-image";
import { isValidHttpUrl } from "../../lib/utils"; import { isValidHttpUrl } from "src/lib/utils";
import { Mentions } from "../mentions"; import { Mentions } from "src/ui/mentions";
import { IMentionSuggestion } from "@plane/editor-types"; import { IMentionSuggestion } from "src/types/mention-suggestion";
export const CoreReadOnlyEditorExtensions = (mentionConfig: { export const CoreReadOnlyEditorExtensions = (mentionConfig: {
mentionSuggestions: IMentionSuggestion[]; mentionSuggestions: IMentionSuggestion[];
@ -71,6 +72,7 @@ export const CoreReadOnlyEditorExtensions = (mentionConfig: {
class: "rounded-lg border border-custom-border-300", class: "rounded-lg border border-custom-border-300",
}, },
}), }),
HorizontalRule,
TiptapUnderline, TiptapUnderline,
TextStyle, TextStyle,
Color, Color,

View File

@ -1,5 +1,15 @@
{ {
"extends": "tsconfig/react-library.json", "extends": "tsconfig/react-library.json",
"include": ["src/**/*", "index.d.ts"], "include": [
"exclude": ["dist", "build", "node_modules"] "src/**/*",
"index.d.ts"
],
"exclude": [
"dist",
"build",
"node_modules"
],
"compilerOptions": {
"baseUrl": "."
}
} }

View File

@ -30,12 +30,11 @@
"dependencies": { "dependencies": {
"@plane/editor-core": "*", "@plane/editor-core": "*",
"@plane/editor-extensions": "*", "@plane/editor-extensions": "*",
"@plane/editor-types": "*",
"@plane/ui": "*", "@plane/ui": "*",
"@tiptap/core": "^2.1.7", "@tiptap/core": "^2.1.13",
"@tiptap/extension-placeholder": "^2.1.11", "@tiptap/extension-placeholder": "^2.1.13",
"@tiptap/pm": "^2.1.12", "@tiptap/pm": "^2.1.13",
"@tiptap/suggestion": "^2.1.12", "@tiptap/suggestion": "^2.1.13",
"eslint": "8.36.0", "eslint": "8.36.0",
"eslint-config-next": "13.2.4", "eslint-config-next": "13.2.4",
"react-popper": "^2.3.0", "react-popper": "^2.3.0",

View File

@ -1,6 +1,5 @@
import { Editor } from "@tiptap/react";
import { useState } from "react"; import { useState } from "react";
import { IMarking } from ".."; import { IMarking } from "src/types/editor-types";
export const useEditorMarkings = () => { export const useEditorMarkings = () => {
const [markings, setMarkings] = useState<IMarking[]>([]); const [markings, setMarkings] = useState<IMarking[]>([]);

View File

@ -1,3 +1,3 @@
export { DocumentEditor, DocumentEditorWithRef } from "./ui"; export { DocumentEditor, DocumentEditorWithRef } from "src/ui";
export { DocumentReadOnlyEditor, DocumentReadOnlyEditorWithRef } from "./ui/readonly"; export { DocumentReadOnlyEditor, DocumentReadOnlyEditorWithRef } from "src/ui/readonly";
export { FixedMenu } from "./ui/menu/fixed-menu"; export { FixedMenu } from "src/ui/menu/fixed-menu";

View File

@ -5,3 +5,9 @@ export interface DocumentDetails {
last_updated_by: string; last_updated_by: string;
last_updated_at: Date; last_updated_at: Date;
} }
export interface IMarking {
type: "heading";
level: number;
text: string;
sequence: number;
}

View File

@ -1,12 +1,11 @@
import { Icon } from "lucide-react"; import { LucideIconType } from "@plane/editor-core";
interface IAlertLabelProps { interface IAlertLabelProps {
Icon?: Icon; Icon?: LucideIconType;
backgroundColor: string; backgroundColor: string;
textColor?: string; textColor?: string;
label: string; label: string;
} }
export const AlertLabel = (props: IAlertLabelProps) => { export const AlertLabel = (props: IAlertLabelProps) => {
const { Icon, backgroundColor, textColor, label } = props; const { Icon, backgroundColor, textColor, label } = props;

View File

@ -1,7 +1,7 @@
import { HeadingComp, HeadingThreeComp, SubheadingComp } from "./heading-component"; import { HeadingComp, HeadingThreeComp, SubheadingComp } from "src/ui/components/heading-component";
import { IMarking } from ".."; import { IMarking } from "src/types/editor-types";
import { Editor } from "@tiptap/react"; import { Editor } from "@tiptap/react";
import { scrollSummary } from "../utils/editor-summary-utils"; import { scrollSummary } from "src/utils/editor-summary-utils";
interface ContentBrowserProps { interface ContentBrowserProps {
editor: Editor; editor: Editor;

View File

@ -1,13 +1,12 @@
import { Editor } from "@tiptap/react"; import { Editor } from "@tiptap/react";
import { Archive, RefreshCw, Lock } from "lucide-react"; import { Archive, RefreshCw, Lock } from "lucide-react";
import { IMarking } from ".."; import { IMarking, DocumentDetails } from "src/types/editor-types";
import { FixedMenu } from "../menu"; import { FixedMenu } from "src/ui/menu";
import { UploadImage } from "@plane/editor-types"; import { UploadImage } from "@plane/editor-core";
import { DocumentDetails } from "../types/editor-types"; import { AlertLabel } from "src/ui/components/alert-label";
import { AlertLabel } from "./alert-label"; import { IVerticalDropdownItemProps, VerticalDropdownMenu } from "src/ui/components/vertical-dropdown-menu";
import { IVerticalDropdownItemProps, VerticalDropdownMenu } from "./vertical-dropdown-menu"; import { SummaryPopover } from "src/ui/components/summary-popover";
import { SummaryPopover } from "./summary-popover"; import { InfoPopover } from "src/ui/components/info-popover";
import { InfoPopover } from "./info-popover";
interface IEditorHeader { interface IEditorHeader {
editor: Editor; editor: Editor;

View File

@ -2,7 +2,7 @@ import { useState } from "react";
import { usePopper } from "react-popper"; import { usePopper } from "react-popper";
import { Calendar, History, Info } from "lucide-react"; import { Calendar, History, Info } from "lucide-react";
// types // types
import { DocumentDetails } from "../types/editor-types"; import { DocumentDetails } from "src/types/editor-types";
type Props = { type Props = {
documentDetails: DocumentDetails; documentDetails: DocumentDetails;

View File

@ -1,7 +1,7 @@
import { EditorContainer, EditorContentWrapper } from "@plane/editor-core"; import { EditorContainer, EditorContentWrapper } from "@plane/editor-core";
import { Editor } from "@tiptap/react"; import { Editor } from "@tiptap/react";
import { useState } from "react"; import { useState } from "react";
import { DocumentDetails } from "../types/editor-types"; import { DocumentDetails } from "src/types/editor-types";
type IPageRenderer = { type IPageRenderer = {
documentDetails: DocumentDetails; documentDetails: DocumentDetails;

View File

@ -3,9 +3,9 @@ import { Editor } from "@tiptap/react";
import { usePopper } from "react-popper"; import { usePopper } from "react-popper";
import { List } from "lucide-react"; import { List } from "lucide-react";
// components // components
import { ContentBrowser } from "./content-browser"; import { ContentBrowser } from "src/ui/components/content-browser";
// types // types
import { IMarking } from ".."; import { IMarking } from "src/types/editor-types";
type Props = { type Props = {
editor: Editor; editor: Editor;

View File

@ -1,6 +1,6 @@
import { Editor } from "@tiptap/react"; import { Editor } from "@tiptap/react";
import { IMarking } from ".."; import { IMarking } from "src/types/editor-types";
import { ContentBrowser } from "./content-browser"; import { ContentBrowser } from "src/ui/components/content-browser";
interface ISummarySideBarProps { interface ISummarySideBarProps {
editor: Editor; editor: Editor;
@ -8,8 +8,7 @@ interface ISummarySideBarProps {
sidePeekVisible: boolean; sidePeekVisible: boolean;
} }
export const SummarySideBar = ({ editor, markings, sidePeekVisible }: ISummarySideBarProps) => { export const SummarySideBar = ({ editor, markings, sidePeekVisible }: ISummarySideBarProps) => (
return (
<div <div
className={`h-full transform overflow-hidden p-5 transition-all duration-200 ${ className={`h-full transform overflow-hidden p-5 transition-all duration-200 ${
sidePeekVisible ? "translate-x-0" : "-translate-x-full" sidePeekVisible ? "translate-x-0" : "-translate-x-full"
@ -17,5 +16,4 @@ export const SummarySideBar = ({ editor, markings, sidePeekVisible }: ISummarySi
> >
<ContentBrowser editor={editor} markings={markings} /> <ContentBrowser editor={editor} markings={markings} />
</div> </div>
); );
};

View File

@ -1,5 +1,6 @@
import { Button, CustomMenu } from "@plane/ui"; import { LucideIconType } from "@plane/editor-core";
import { ChevronUp, Icon, MoreVertical } from "lucide-react"; import { CustomMenu } from "@plane/ui";
import { MoreVertical } from "lucide-react";
type TMenuItems = type TMenuItems =
| "archive_page" | "archive_page"
@ -14,7 +15,7 @@ type TMenuItems =
export interface IVerticalDropdownItemProps { export interface IVerticalDropdownItemProps {
key: number; key: number;
type: TMenuItems; type: TMenuItems;
Icon: Icon; Icon: LucideIconType;
label: string; label: string;
action: () => Promise<void> | void; action: () => Promise<void> | void;
} }
@ -23,17 +24,14 @@ export interface IVerticalDropdownMenuProps {
items: IVerticalDropdownItemProps[]; items: IVerticalDropdownItemProps[];
} }
const VerticalDropdownItem = ({ Icon, label, action }: IVerticalDropdownItemProps) => { const VerticalDropdownItem = ({ Icon, label, action }: IVerticalDropdownItemProps) => (
return (
<CustomMenu.MenuItem onClick={action} className="flex items-center gap-2"> <CustomMenu.MenuItem onClick={action} className="flex items-center gap-2">
<Icon className="h-3 w-3" /> <Icon className="h-3 w-3" />
<div className="text-custom-text-300">{label}</div> <div className="text-custom-text-300">{label}</div>
</CustomMenu.MenuItem> </CustomMenu.MenuItem>
); );
};
export const VerticalDropdownMenu = ({ items }: IVerticalDropdownMenuProps) => { export const VerticalDropdownMenu = ({ items }: IVerticalDropdownMenuProps) => (
return (
<CustomMenu <CustomMenu
maxHeight={"md"} maxHeight={"md"}
className={"h-4.5 mt-1"} className={"h-4.5 mt-1"}
@ -41,9 +39,8 @@ export const VerticalDropdownMenu = ({ items }: IVerticalDropdownMenuProps) => {
optionsClassName={"border-custom-border border-r border-solid transition-all duration-200 ease-in-out "} optionsClassName={"border-custom-border border-r border-solid transition-all duration-200 ease-in-out "}
customButton={<MoreVertical size={14} />} customButton={<MoreVertical size={14} />}
> >
{items.map((item, index) => ( {items.map((item) => (
<VerticalDropdownItem key={index} type={item.type} Icon={item.Icon} label={item.label} action={item.action} /> <VerticalDropdownItem key={item.key} type={item.type} Icon={item.Icon} label={item.label} action={item.action} />
))} ))}
</CustomMenu> </CustomMenu>
); );
};

View File

@ -1,11 +1,11 @@
import Placeholder from "@tiptap/extension-placeholder"; import Placeholder from "@tiptap/extension-placeholder";
import { IssueWidgetExtension } from "./widgets/IssueEmbedWidget"; import { IssueWidgetExtension } from "src/ui/extensions/widgets/issue-embed-widget";
import { IIssueEmbedConfig } from "./widgets/IssueEmbedWidget/types"; import { IIssueEmbedConfig } from "src/ui/extensions/widgets/issue-embed-widget/types";
import { SlashCommand, DragAndDrop } from "@plane/editor-extensions"; import { SlashCommand, DragAndDrop } from "@plane/editor-extensions";
import { ISlashCommandItem, UploadImage } from "@plane/editor-types"; import { ISlashCommandItem, UploadImage } from "@plane/editor-core";
import { IssueSuggestions } from "./widgets/IssueEmbedSuggestionList"; import { IssueSuggestions } from "src/ui/extensions/widgets/issue-embed-suggestion-list";
import { LayersIcon } from "@plane/ui"; import { LayersIcon } from "@plane/ui";
export const DocumentEditorExtensions = ( export const DocumentEditorExtensions = (

View File

@ -1,16 +0,0 @@
import { IIssueListSuggestion } from ".";
export const getIssueSuggestionItems = (issueSuggestions: Array<IIssueListSuggestion>) => {
return ({ query }: { query: string }) => {
const search = query.toLowerCase();
const filteredSuggestions = issueSuggestions.filter((item) => {
return (
item.title.toLowerCase().includes(search) ||
item.identifier.toLowerCase().includes(search) ||
item.priority.toLowerCase().includes(search)
);
});
return filteredSuggestions;
};
};

View File

@ -1,7 +1,7 @@
import { Editor, Range } from "@tiptap/react"; import { Editor, Range } from "@tiptap/react";
import { IssueEmbedSuggestions } from "./issue-suggestion-extension"; import { IssueEmbedSuggestions } from "src/ui/extensions/widgets/issue-embed-suggestion-list/issue-suggestion-extension";
import { getIssueSuggestionItems } from "./issue-suggestion-items"; import { getIssueSuggestionItems } from "src/ui/extensions/widgets/issue-embed-suggestion-list/issue-suggestion-items";
import { IssueListRenderer } from "./issue-suggestion-renderer"; import { IssueListRenderer } from "src/ui/extensions/widgets/issue-embed-suggestion-list/issue-suggestion-renderer";
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
export type CommandProps = { export type CommandProps = {
@ -19,7 +19,7 @@ export interface IIssueListSuggestion {
export const IssueSuggestions = (suggestions: any[]) => { export const IssueSuggestions = (suggestions: any[]) => {
const mappedSuggestions: IIssueListSuggestion[] = suggestions.map((suggestion): IIssueListSuggestion => { const mappedSuggestions: IIssueListSuggestion[] = suggestions.map((suggestion): IIssueListSuggestion => {
let transactionId = uuidv4(); const transactionId = uuidv4();
return { return {
title: suggestion.name, title: suggestion.name,
priority: suggestion.priority.toString(), priority: suggestion.priority.toString(),

View File

@ -0,0 +1,15 @@
import { IIssueListSuggestion } from "src/ui/extensions/widgets/issue-embed-suggestion-list";
export const getIssueSuggestionItems =
(issueSuggestions: Array<IIssueListSuggestion>) =>
({ query }: { query: string }) => {
const search = query.toLowerCase();
const filteredSuggestions = issueSuggestions.filter(
(item) =>
item.title.toLowerCase().includes(search) ||
item.identifier.toLowerCase().includes(search) ||
item.priority.toLowerCase().includes(search)
);
return filteredSuggestions;
};

View File

@ -171,7 +171,7 @@ const IssueSuggestionList = ({
section === currentSection && index === selectedIndex, section === currentSection && index === selectedIndex,
} }
)} )}
key={index} key={item.identifier}
onClick={() => selectItem(index)} onClick={() => selectItem(index)}
> >
<h5 className="whitespace-nowrap text-xs text-custom-text-300">{item.identifier}</h5> <h5 className="whitespace-nowrap text-xs text-custom-text-300">{item.identifier}</h5>

View File

@ -1,5 +1,5 @@
import { IssueWidget } from "./issue-widget-node"; import { IssueWidget } from "src/ui/extensions/widgets/issue-embed-widget/issue-widget-node";
import { IIssueEmbedConfig } from "./types"; import { IIssueEmbedConfig } from "src/ui/extensions/widgets/issue-embed-widget/types";
interface IssueWidgetExtensionProps { interface IssueWidgetExtensionProps {
issueEmbedConfig?: IIssueEmbedConfig; issueEmbedConfig?: IIssueEmbedConfig;

View File

@ -4,7 +4,7 @@ import { NodeViewWrapper } from "@tiptap/react";
import { Avatar, AvatarGroup, Loader, PriorityIcon } from "@plane/ui"; import { Avatar, AvatarGroup, Loader, PriorityIcon } from "@plane/ui";
import { Calendar, AlertTriangle } from "lucide-react"; import { Calendar, AlertTriangle } from "lucide-react";
const IssueWidgetCard = (props) => { export const IssueWidgetCard = (props) => {
const [loading, setLoading] = useState<number>(1); const [loading, setLoading] = useState<number>(1);
const [issueDetails, setIssueDetails] = useState(); const [issueDetails, setIssueDetails] = useState();
@ -42,11 +42,9 @@ const IssueWidgetCard = (props) => {
</div> </div>
<div> <div>
<AvatarGroup size="sm"> <AvatarGroup size="sm">
{issueDetails.assignee_details.map((assignee) => { {issueDetails.assignee_details.map((assignee) => (
return (
<Avatar key={assignee.id} name={assignee.display_name} src={assignee.avatar} className={"m-0"} /> <Avatar key={assignee.id} name={assignee.display_name} src={assignee.avatar} className={"m-0"} />
); ))}
})}
</AvatarGroup> </AvatarGroup>
</div> </div>
{issueDetails.target_date && ( {issueDetails.target_date && (
@ -76,5 +74,3 @@ const IssueWidgetCard = (props) => {
</NodeViewWrapper> </NodeViewWrapper>
); );
}; };
export default IssueWidgetCard;

View File

@ -1,5 +1,5 @@
import { mergeAttributes, Node } from "@tiptap/core"; import { mergeAttributes, Node } from "@tiptap/core";
import IssueWidgetCard from "./issue-widget-card"; import { IssueWidgetCard } from "src/ui/extensions/widgets/issue-embed-widget/issue-widget-card";
import { ReactNodeViewRenderer } from "@tiptap/react"; import { ReactNodeViewRenderer } from "@tiptap/react";
export const IssueWidget = Node.create({ export const IssueWidget = Node.create({

View File

@ -1,17 +1,16 @@
"use client"; "use client";
import React, { useState } from "react"; import React, { useState } from "react";
import { getEditorClassNames, useEditor } from "@plane/editor-core"; import { UploadImage, DeleteImage, RestoreImage, getEditorClassNames, useEditor } from "@plane/editor-core";
import { DocumentEditorExtensions } from "./extensions"; import { DocumentEditorExtensions } from "src/ui/extensions";
import { IDuplicationConfig, IPageArchiveConfig, IPageLockConfig } from "./types/menu-actions"; import { IDuplicationConfig, IPageArchiveConfig, IPageLockConfig } from "src/types/menu-actions";
import { EditorHeader } from "./components/editor-header"; import { EditorHeader } from "src/ui/components/editor-header";
import { useEditorMarkings } from "./hooks/use-editor-markings"; import { useEditorMarkings } from "src/hooks/use-editor-markings";
import { SummarySideBar } from "./components/summary-side-bar"; import { SummarySideBar } from "src/ui/components/summary-side-bar";
import { DocumentDetails } from "./types/editor-types"; import { DocumentDetails } from "src/types/editor-types";
import { PageRenderer } from "./components/page-renderer"; import { PageRenderer } from "src/ui/components/page-renderer";
import { getMenuOptions } from "./utils/menu-options"; import { getMenuOptions } from "src/utils/menu-options";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { IEmbedConfig } from "./extensions/widgets/IssueEmbedWidget/types"; import { IEmbedConfig } from "src/ui/extensions/widgets/issue-embed-widget/types";
import { UploadImage, DeleteImage, RestoreImage } from "@plane/editor-types";
interface IDocumentEditor { interface IDocumentEditor {
// document info // document info
@ -59,13 +58,6 @@ interface EditorHandle {
setEditorValue: (content: string) => void; setEditorValue: (content: string) => void;
} }
export interface IMarking {
type: "heading";
level: number;
text: string;
sequence: number;
}
const DocumentEditor = ({ const DocumentEditor = ({
documentDetails, documentDetails,
onChange, onChange,

View File

@ -17,8 +17,8 @@ import {
HeadingThreeItem, HeadingThreeItem,
findTableAncestor, findTableAncestor,
EditorMenuItem, EditorMenuItem,
UploadImage,
} from "@plane/editor-core"; } from "@plane/editor-core";
import { UploadImage } from "@plane/editor-types";
export type BubbleMenuItem = EditorMenuItem; export type BubbleMenuItem = EditorMenuItem;

View File

@ -1,15 +1,15 @@
import { getEditorClassNames, useReadOnlyEditor } from "@plane/editor-core"; import { getEditorClassNames, useReadOnlyEditor } from "@plane/editor-core";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { useState, forwardRef, useEffect } from "react"; import { useState, forwardRef, useEffect } from "react";
import { EditorHeader } from "../components/editor-header"; import { EditorHeader } from "src/ui/components/editor-header";
import { PageRenderer } from "../components/page-renderer"; import { PageRenderer } from "src/ui/components/page-renderer";
import { SummarySideBar } from "../components/summary-side-bar"; import { SummarySideBar } from "src/ui/components/summary-side-bar";
import { IssueWidgetExtension } from "../extensions/widgets/IssueEmbedWidget"; import { IssueWidgetExtension } from "src/ui/extensions/widgets/issue-embed-widget";
import { IEmbedConfig } from "../extensions/widgets/IssueEmbedWidget/types"; import { IEmbedConfig } from "src/ui/extensions/widgets/issue-embed-widget/types";
import { useEditorMarkings } from "../hooks/use-editor-markings"; import { useEditorMarkings } from "src/hooks/use-editor-markings";
import { DocumentDetails } from "../types/editor-types"; import { DocumentDetails } from "src/types/editor-types";
import { IPageArchiveConfig, IPageLockConfig, IDuplicationConfig } from "../types/menu-actions"; import { IPageArchiveConfig, IPageLockConfig, IDuplicationConfig } from "src/types/menu-actions";
import { getMenuOptions } from "../utils/menu-options"; import { getMenuOptions } from "src/utils/menu-options";
interface IDocumentReadOnlyEditor { interface IDocumentReadOnlyEditor {
value: string; value: string;

View File

@ -1,5 +1,5 @@
import { Editor } from "@tiptap/react"; import { Editor } from "@tiptap/react";
import { IMarking } from ".."; import { IMarking } from "src/types/editor-types";
function findNthH1(editor: Editor, n: number, level: number): number { function findNthH1(editor: Editor, n: number, level: number): number {
let count = 0; let count = 0;

View File

@ -1,19 +1,9 @@
import { Editor } from "@tiptap/react"; import { Editor } from "@tiptap/react";
import { import { Archive, ArchiveRestoreIcon, ClipboardIcon, Copy, Link, Lock, Unlock } from "lucide-react";
Archive,
ArchiveIcon,
ArchiveRestoreIcon,
ClipboardIcon,
Copy,
Link,
Lock,
Unlock,
XCircle,
} from "lucide-react";
import { NextRouter } from "next/router"; import { NextRouter } from "next/router";
import { IVerticalDropdownItemProps } from "../components/vertical-dropdown-menu"; import { IVerticalDropdownItemProps } from "src/ui/components/vertical-dropdown-menu";
import { IDuplicationConfig, IPageArchiveConfig, IPageLockConfig } from "../types/menu-actions"; import { IDuplicationConfig, IPageArchiveConfig, IPageLockConfig } from "src/types/menu-actions";
import { copyMarkdownToClipboard, CopyPageLink } from "./menu-actions"; import { copyMarkdownToClipboard, CopyPageLink } from "src/utils/menu-actions";
export interface MenuOptionsProps { export interface MenuOptionsProps {
editor: Editor; editor: Editor;

View File

@ -1,5 +1,15 @@
{ {
"extends": "tsconfig/react-library.json", "extends": "tsconfig/react-library.json",
"include": ["src/**/*", "index.d.ts"], "include": [
"exclude": ["dist", "build", "node_modules"] "src/**/*",
"index.d.ts"
],
"exclude": [
"dist",
"build",
"node_modules"
],
"compilerOptions": {
"baseUrl": "."
}
} }

View File

@ -29,11 +29,10 @@
}, },
"dependencies": { "dependencies": {
"@plane/editor-core": "*", "@plane/editor-core": "*",
"@plane/editor-types": "*", "@tiptap/core": "^2.1.13",
"@tiptap/core": "^2.1.7", "@tiptap/pm": "^2.1.13",
"@tiptap/pm": "^2.1.7", "@tiptap/react": "^2.1.13",
"@tiptap/react": "^2.1.7", "@tiptap/suggestion": "^2.1.13",
"@tiptap/suggestion": "^2.0.4",
"eslint": "8.36.0", "eslint": "8.36.0",
"eslint-config-next": "13.2.4", "eslint-config-next": "13.2.4",
"lucide-react": "^0.294.0", "lucide-react": "^0.294.0",

View File

@ -1,9 +1,8 @@
import { useState, useEffect, useCallback, ReactNode, useRef, useLayoutEffect } from "react"; import { useState, useEffect, useCallback, ReactNode, useRef, useLayoutEffect } from "react";
import { Editor, Range, Extension } from "@tiptap/core"; import { Editor, Range, Extension } from "@tiptap/core";
import Suggestion from "@tiptap/suggestion"; import Suggestion, { SuggestionOptions } from "@tiptap/suggestion";
import { ReactRenderer } from "@tiptap/react"; import { ReactRenderer } from "@tiptap/react";
import tippy from "tippy.js"; import tippy from "tippy.js";
import type { UploadImage, ISlashCommandItem, CommandProps } from "@plane/editor-types";
import { import {
CaseSensitive, CaseSensitive,
Code2, Code2,
@ -19,6 +18,9 @@ import {
Table, Table,
} from "lucide-react"; } from "lucide-react";
import { import {
UploadImage,
ISlashCommandItem,
CommandProps,
cn, cn,
insertTableCommand, insertTableCommand,
toggleBlockquote, toggleBlockquote,
@ -38,7 +40,11 @@ interface CommandItemProps {
icon: ReactNode; icon: ReactNode;
} }
const Command = Extension.create({ export type SlashCommandOptions = {
suggestion: Omit<SuggestionOptions, "editor">;
};
const Command = Extension.create<SlashCommandOptions>({
name: "slash-command", name: "slash-command",
addOptions() { addOptions() {
return { return {
@ -47,6 +53,10 @@ const Command = Extension.create({
command: ({ editor, range, props }: { editor: Editor; range: Range; props: any }) => { command: ({ editor, range, props }: { editor: Editor; range: Range; props: any }) => {
props.command({ editor, range }); props.command({ editor, range });
}, },
allow({ editor }: { editor: Editor }) {
return !editor.isActive("table");
},
allowSpaces: true,
}, },
}; };
}, },
@ -54,9 +64,6 @@ const Command = Extension.create({
return [ return [
Suggestion({ Suggestion({
editor: this.editor, editor: this.editor,
allow({ editor }) {
return !editor.isActive("table");
},
...this.options.suggestion, ...this.options.suggestion,
}), }),
]; ];
@ -173,7 +180,7 @@ const getSuggestionItems =
key: "image", key: "image",
title: "Image", title: "Image",
description: "Upload an image from your computer.", description: "Upload an image from your computer.",
searchTerms: ["photo", "picture", "media"], searchTerms: ["img", "photo", "picture", "media"],
icon: <ImageIcon className="h-3.5 w-3.5" />, icon: <ImageIcon className="h-3.5 w-3.5" />,
command: ({ editor, range }: CommandProps) => { command: ({ editor, range }: CommandProps) => {
insertImageCommand(editor, uploadFile, setIsSubmitting, range); insertImageCommand(editor, uploadFile, setIsSubmitting, range);

View File

@ -1,2 +1,4 @@
export { SlashCommand } from "./extensions/slash-commands"; import "src/styles/drag-drop.css";
export { DragAndDrop } from "./extensions/drag-drop";
export { SlashCommand } from "src/extensions/slash-commands";
export { DragAndDrop } from "src/extensions/drag-drop";

View File

@ -0,0 +1,53 @@
.drag-handle {
position: fixed;
opacity: 1;
transition: opacity ease-in 0.2s;
height: 18px;
width: 15px;
display: grid;
place-items: center;
z-index: 10;
cursor: grab;
border-radius: 2px;
background-color: rgb(var(--color-background-90));
}
.drag-handle:hover {
background-color: rgb(var(--color-background-80));
transition: background-color 0.2s;
}
.drag-handle.hidden {
opacity: 0;
pointer-events: none;
}
@media screen and (max-width: 600px) {
.drag-handle {
display: none;
pointer-events: none;
}
}
.drag-handle-container {
height: 15px;
width: 15px;
cursor: grab;
display: grid;
place-items: center;
}
.drag-handle-dots {
height: 100%;
width: 12px;
display: grid;
grid-template-columns: repeat(2, 1fr);
place-items: center;
}
.drag-handle-dot {
height: 2.75px;
width: 3px;
background-color: rgba(var(--color-text-200));
border-radius: 50%;
}

View File

@ -1,5 +1,15 @@
{ {
"extends": "tsconfig/react-library.json", "extends": "tsconfig/react-library.json",
"include": ["src/**/*", "index.d.ts"], "include": [
"exclude": ["dist", "build", "node_modules"] "src/**/*",
"index.d.ts"
],
"exclude": [
"dist",
"build",
"node_modules"
],
"compilerOptions": {
"baseUrl": "."
}
} }

View File

@ -30,8 +30,7 @@
}, },
"dependencies": { "dependencies": {
"@plane/editor-core": "*", "@plane/editor-core": "*",
"@plane/ui": "*", "@plane/ui": "*"
"@plane/editor-types": "*"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "18.15.3", "@types/node": "18.15.3",

View File

@ -1,3 +1,3 @@
export { LiteTextEditor, LiteTextEditorWithRef } from "./ui"; export { LiteTextEditor, LiteTextEditorWithRef } from "src/ui";
export { LiteReadOnlyEditor, LiteReadOnlyEditorWithRef } from "./ui/read-only"; export { LiteReadOnlyEditor, LiteReadOnlyEditorWithRef } from "src/ui/read-only";
export type { IMentionSuggestion, IMentionHighlight } from "@plane/editor-types"; export type { IMentionSuggestion, IMentionHighlight } from "@plane/editor-core";

View File

@ -1,4 +1,4 @@
import { EnterKeyExtension } from "./enter-key-extension"; import { EnterKeyExtension } from "src/ui/extensions/enter-key-extension";
export const LiteTextEditorExtensions = (onEnterKeyPress?: () => void) => [ export const LiteTextEditorExtensions = (onEnterKeyPress?: () => void) => [
// EnterKeyExtension(onEnterKeyPress), // EnterKeyExtension(onEnterKeyPress),

View File

@ -1,8 +1,16 @@
import * as React from "react"; import * as React from "react";
import { EditorContainer, EditorContentWrapper, getEditorClassNames, useEditor } from "@plane/editor-core"; import {
import { FixedMenu } from "./menus/fixed-menu"; UploadImage,
import { LiteTextEditorExtensions } from "./extensions"; DeleteImage,
import { UploadImage, DeleteImage, IMentionSuggestion, RestoreImage } from "@plane/editor-types"; IMentionSuggestion,
RestoreImage,
EditorContainer,
EditorContentWrapper,
getEditorClassNames,
useEditor,
} from "@plane/editor-core";
import { FixedMenu } from "src/ui/menus/fixed-menu";
import { LiteTextEditorExtensions } from "src/ui/extensions";
interface ILiteTextEditor { interface ILiteTextEditor {
value: string; value: string;

View File

@ -9,27 +9,21 @@ import {
ImageItem, ImageItem,
isCellSelection, isCellSelection,
ItalicItem, ItalicItem,
LucideIconType,
NumberedListItem, NumberedListItem,
QuoteItem, QuoteItem,
StrikeThroughItem, StrikeThroughItem,
TableItem, TableItem,
UnderLineItem, UnderLineItem,
UploadImage,
} from "@plane/editor-core"; } from "@plane/editor-core";
import { Tooltip } from "@plane/ui"; import { Tooltip } from "@plane/ui";
import type { SVGProps } from "react";
import { UploadImage } from "@plane/editor-types";
interface LucideProps extends Partial<SVGProps<SVGSVGElement>> {
size?: string | number;
absoluteStrokeWidth?: boolean;
}
type LucideIcon = (props: LucideProps) => JSX.Element;
export interface BubbleMenuItem { export interface BubbleMenuItem {
name: string; name: string;
isActive: () => boolean; isActive: () => boolean;
command: () => void; command: () => void;
icon: LucideIcon; icon: LucideIconType;
} }
type EditorBubbleMenuProps = { type EditorBubbleMenuProps = {
@ -127,8 +121,8 @@ export const FixedMenu = (props: EditorBubbleMenuProps) => {
<div className="flex w-full items-stretch justify-between gap-2 rounded border-[0.5px] border-custom-border-200 bg-custom-background-90 p-1"> <div className="flex w-full items-stretch justify-between gap-2 rounded border-[0.5px] border-custom-border-200 bg-custom-background-90 p-1">
<div className="flex items-stretch"> <div className="flex items-stretch">
<div className="flex items-stretch gap-0.5 border-r border-custom-border-200 pr-2.5"> <div className="flex items-stretch gap-0.5 border-r border-custom-border-200 pr-2.5">
{basicTextFormattingItems.map((item, index) => ( {basicTextFormattingItems.map((item) => (
<Tooltip key={index} tooltipContent={<span className="capitalize">{item.name}</span>}> <Tooltip key={item.name} tooltipContent={<span className="capitalize">{item.name}</span>}>
<button <button
type="button" type="button"
onClick={item.command} onClick={item.command}
@ -150,8 +144,8 @@ export const FixedMenu = (props: EditorBubbleMenuProps) => {
))} ))}
</div> </div>
<div className="flex items-stretch gap-0.5 border-r border-custom-border-200 px-2.5"> <div className="flex items-stretch gap-0.5 border-r border-custom-border-200 px-2.5">
{listFormattingItems.map((item, index) => ( {listFormattingItems.map((item) => (
<Tooltip key={index} tooltipContent={<span className="capitalize">{item.name}</span>}> <Tooltip key={item.name} tooltipContent={<span className="capitalize">{item.name}</span>}>
<button <button
type="button" type="button"
onClick={item.command} onClick={item.command}
@ -173,8 +167,8 @@ export const FixedMenu = (props: EditorBubbleMenuProps) => {
))} ))}
</div> </div>
<div className="flex items-stretch gap-0.5 border-r border-custom-border-200 px-2.5"> <div className="flex items-stretch gap-0.5 border-r border-custom-border-200 px-2.5">
{userActionItems.map((item, index) => ( {userActionItems.map((item) => (
<Tooltip key={index} tooltipContent={<span className="capitalize">{item.name}</span>}> <Tooltip key={item.name} tooltipContent={<span className="capitalize">{item.name}</span>}>
<button <button
type="button" type="button"
onClick={item.command} onClick={item.command}
@ -196,8 +190,8 @@ export const FixedMenu = (props: EditorBubbleMenuProps) => {
))} ))}
</div> </div>
<div className="flex items-stretch gap-0.5 pl-2.5"> <div className="flex items-stretch gap-0.5 pl-2.5">
{complexItems.map((item, index) => ( {complexItems.map((item) => (
<Tooltip key={index} tooltipContent={<span className="capitalize">{item.name}</span>}> <Tooltip key={item.name} tooltipContent={<span className="capitalize">{item.name}</span>}>
<button <button
type="button" type="button"
onClick={item.command} onClick={item.command}

View File

@ -1,74 +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<Props> = ({
tooltipHeading,
tooltipContent,
position = "top",
children,
disabled = false,
className = "",
openDelay = 200,
closeDelay,
}) => {
const { theme } = useTheme();
return (
<Tooltip2
disabled={disabled}
hoverOpenDelay={openDelay}
hoverCloseDelay={closeDelay}
content={
<div
className={`relative z-50 max-w-xs gap-1 rounded-md p-2 text-xs shadow-md ${
theme === "custom" ? "bg-custom-background-100 text-custom-text-200" : "bg-black text-gray-400"
} overflow-hidden break-words ${className}`}
>
{tooltipHeading && (
<h5 className={`font-medium ${theme === "custom" ? "text-custom-text-100" : "text-white"}`}>
{tooltipHeading}
</h5>
)}
{tooltipContent}
</div>
}
position={position}
renderTarget={({ isOpen: isTooltipOpen, ref: eleReference, ...tooltipProps }) =>
React.cloneElement(children, {
ref: eleReference,
...tooltipProps,
...children.props,
})
}
/>
);
};

View File

@ -1,5 +1,15 @@
{ {
"extends": "tsconfig/react-library.json", "extends": "tsconfig/react-library.json",
"include": ["src/**/*", "index.d.ts"], "include": [
"exclude": ["dist", "build", "node_modules"] "src/**/*",
"index.d.ts"
],
"exclude": [
"dist",
"build",
"node_modules"
],
"compilerOptions": {
"baseUrl": "."
}
} }

View File

@ -31,9 +31,8 @@
"dependencies": { "dependencies": {
"@plane/editor-core": "*", "@plane/editor-core": "*",
"@plane/editor-extensions": "*", "@plane/editor-extensions": "*",
"@plane/editor-types": "*", "@tiptap/core": "^2.1.13",
"@tiptap/core": "^2.1.11", "@tiptap/extension-placeholder": "^2.1.13",
"@tiptap/extension-placeholder": "^2.1.11",
"lucide-react": "^0.294.0" "lucide-react": "^0.294.0"
}, },
"devDependencies": { "devDependencies": {

View File

@ -1,4 +1,4 @@
export { RichTextEditor, RichTextEditorWithRef } from "./ui"; export { RichTextEditor, RichTextEditorWithRef } from "src/ui";
export { RichReadOnlyEditor, RichReadOnlyEditorWithRef } from "./ui/read-only"; export { RichReadOnlyEditor, RichReadOnlyEditorWithRef } from "src/ui/read-only";
export type { RichTextEditorProps, IRichTextEditor } from "./ui"; export type { RichTextEditorProps, IRichTextEditor } from "src/ui";
export type { IMentionHighlight, IMentionSuggestion } from "@plane/editor-types"; export type { IMentionHighlight, IMentionSuggestion } from "@plane/editor-core";

View File

@ -1,7 +1,6 @@
import { SlashCommand } from "@plane/editor-extensions"; import { SlashCommand, DragAndDrop } from "@plane/editor-extensions";
import Placeholder from "@tiptap/extension-placeholder"; import Placeholder from "@tiptap/extension-placeholder";
import { DragAndDrop } from "@plane/editor-extensions"; import { UploadImage } from "@plane/editor-core";
import { UploadImage } from "@plane/editor-types";
export const RichTextEditorExtensions = ( export const RichTextEditorExtensions = (
uploadFile: UploadImage, uploadFile: UploadImage,

View File

@ -1,9 +1,17 @@
"use client"; "use client";
import * as React from "react"; import * as React from "react";
import { EditorContainer, EditorContentWrapper, getEditorClassNames, useEditor } from "@plane/editor-core"; import {
import { EditorBubbleMenu } from "./menus/bubble-menu"; DeleteImage,
import { RichTextEditorExtensions } from "./extensions"; EditorContainer,
import { DeleteImage, IMentionSuggestion, RestoreImage, UploadImage } from "@plane/editor-types"; EditorContentWrapper,
getEditorClassNames,
IMentionSuggestion,
RestoreImage,
UploadImage,
useEditor,
} from "@plane/editor-core";
import { EditorBubbleMenu } from "src/ui/menus/bubble-menu";
import { RichTextEditorExtensions } from "src/ui/extensions";
export type IRichTextEditor = { export type IRichTextEditor = {
value: string; value: string;

View File

@ -1,15 +1,15 @@
import { BubbleMenu, BubbleMenuProps, isNodeSelection } from "@tiptap/react"; import { BubbleMenu, BubbleMenuProps, isNodeSelection } from "@tiptap/react";
import { FC, useEffect, useState } from "react"; import { FC, useEffect, useState } from "react";
import { BoldIcon } from "lucide-react";
import { NodeSelector } from "./node-selector"; import { NodeSelector } from "src/ui/menus/bubble-menu/node-selector";
import { LinkSelector } from "./link-selector"; import { LinkSelector } from "src/ui/menus/bubble-menu/link-selector";
import { import {
BoldItem, BoldItem,
cn, cn,
CodeItem, CodeItem,
isCellSelection, isCellSelection,
ItalicItem, ItalicItem,
LucideIconType,
StrikeThroughItem, StrikeThroughItem,
UnderLineItem, UnderLineItem,
} from "@plane/editor-core"; } from "@plane/editor-core";
@ -18,7 +18,7 @@ export interface BubbleMenuItem {
name: string; name: string;
isActive: () => boolean; isActive: () => boolean;
command: () => void; command: () => void;
icon: typeof BoldIcon; icon: LucideIconType;
} }
type EditorBubbleMenuProps = Omit<BubbleMenuProps, "children">; type EditorBubbleMenuProps = Omit<BubbleMenuProps, "children">;
@ -117,9 +117,9 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props: any) => {
}} }}
/> />
<div className="flex"> <div className="flex">
{items.map((item, index) => ( {items.map((item) => (
<button <button
key={index} key={item.name}
type="button" type="button"
onClick={item.command} onClick={item.command}
className={cn( className={cn(

View File

@ -56,9 +56,9 @@ export const NodeSelector: FC<NodeSelectorProps> = ({ editor, isOpen, setIsOpen
{isOpen && ( {isOpen && (
<section className="fixed top-full z-[99999] mt-1 flex w-48 flex-col overflow-hidden rounded border border-custom-border-300 bg-custom-background-100 p-1 shadow-xl animate-in fade-in slide-in-from-top-1"> <section className="fixed top-full z-[99999] mt-1 flex w-48 flex-col overflow-hidden rounded border border-custom-border-300 bg-custom-background-100 p-1 shadow-xl animate-in fade-in slide-in-from-top-1">
{items.map((item, index) => ( {items.map((item) => (
<button <button
key={index} key={item.name}
type="button" type="button"
onClick={() => { onClick={() => {
item.command(); item.command();

View File

@ -1,5 +1,15 @@
{ {
"extends": "tsconfig/react-library.json", "extends": "tsconfig/react-library.json",
"include": ["src/**/*", "index.d.ts"], "include": [
"exclude": ["dist", "build", "node_modules"] "src/**/*",
"index.d.ts"
],
"exclude": [
"dist",
"build",
"node_modules"
],
"compilerOptions": {
"baseUrl": "."
}
} }

Some files were not shown because too many files have changed in this diff Show More