mirror of
https://github.com/gosticks/plane.git
synced 2025-10-16 12:45:33 +00:00
[WIKI-345] chore: pass disabled and flagged extensions to block menu (#7152)
* chore: refactor editor * sync changes * feat: api service update * refactor : update sync * fix : package sync * fix: requested changes * fix : embedhandler type * fix : remove commands * refactor : space * refactor : rich lite editors * refactor : minor ce changes * chore : minor ui fix * package: tldjs * refactor : remove tldjs * refactor: flagged * refactor: flagged * chore : remove disbaled check in menu * refactor: fix space * refactor: NodeViewProps * refactor: type * refactor : update community types * refactor : remove external embed CE * remove : external embed config from ce * refactor : update disabled * chore: pass disabled * chore : update utils
This commit is contained in:
parent
8801ab0081
commit
0fe7da6265
@ -14,6 +14,7 @@ export abstract class APIService {
|
|||||||
this.axiosInstance = axios.create({
|
this.axiosInstance = axios.create({
|
||||||
baseURL,
|
baseURL,
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
|
timeout: 20000,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -71,7 +71,7 @@ export const isCommentEmpty = (comment: string | undefined): boolean => {
|
|||||||
return (
|
return (
|
||||||
comment?.trim() === "" ||
|
comment?.trim() === "" ||
|
||||||
comment === "<p></p>" ||
|
comment === "<p></p>" ||
|
||||||
isEmptyHtmlString(comment ?? "", ["img", "mention-component", "image-component"])
|
isEmptyHtmlString(comment ?? "", ["img", "mention-component", "image-component", "embed-component"])
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
// plane imports
|
// plane constants
|
||||||
import { EIssueCommentAccessSpecifier } from "@plane/constants";
|
import { EIssueCommentAccessSpecifier } from "@plane/constants";
|
||||||
|
// plane imports
|
||||||
import { type EditorRefApi, type ILiteTextEditorProps, LiteTextEditorWithRef, type TFileHandler } from "@plane/editor";
|
import { type EditorRefApi, type ILiteTextEditorProps, LiteTextEditorWithRef, type TFileHandler } from "@plane/editor";
|
||||||
import { useTranslation } from "@plane/i18n";
|
import { useTranslation } from "@plane/i18n";
|
||||||
import type { MakeOptional } from "@plane/types";
|
import type { MakeOptional } from "@plane/types";
|
||||||
@ -87,7 +88,6 @@ export const LiteTextEditor = React.forwardRef<EditorRefApi, LiteTextEditorWrapp
|
|||||||
// derived values
|
// derived values
|
||||||
const isEmpty = isCommentEmpty(props.initialValue);
|
const isEmpty = isCommentEmpty(props.initialValue);
|
||||||
const editorRef = isMutableRefObject<EditorRefApi>(ref) ? ref.current : null;
|
const editorRef = isMutableRefObject<EditorRefApi>(ref) ? ref.current : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
|
|||||||
@ -59,7 +59,6 @@ export const StickyEditor = React.forwardRef<EditorRefApi, StickyEditorWrapperPr
|
|||||||
}
|
}
|
||||||
// derived values
|
// derived values
|
||||||
const editorRef = isMutableRefObject<EditorRefApi>(ref) ? ref.current : null;
|
const editorRef = isMutableRefObject<EditorRefApi>(ref) ? ref.current : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn("relative border border-custom-border-200 rounded", parentClassName)}
|
className={cn("relative border border-custom-border-200 rounded", parentClassName)}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ const nextConfig = {
|
|||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
source: "/(.*)?",
|
source: "/(.*)?",
|
||||||
headers: [{ key: "X-Frame-Options", value: "SAMEORIGIN" }],
|
headers: [{ key: "X-Frame-Options", value: "DENY" }],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|||||||
@ -108,6 +108,8 @@ const CollaborativeDocumentEditor: React.FC<ICollaborativeDocumentEditorProps> =
|
|||||||
isTouchDevice={!!isTouchDevice}
|
isTouchDevice={!!isTouchDevice}
|
||||||
isLoading={!hasServerSynced && !hasServerConnectionFailed}
|
isLoading={!hasServerSynced && !hasServerConnectionFailed}
|
||||||
tabIndex={tabIndex}
|
tabIndex={tabIndex}
|
||||||
|
flaggedExtensions={flaggedExtensions}
|
||||||
|
disabledExtensions={disabledExtensions}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -82,6 +82,7 @@ const DocumentEditor = (props: IDocumentEditorProps) => {
|
|||||||
initialValue: value,
|
initialValue: value,
|
||||||
mentionHandler,
|
mentionHandler,
|
||||||
onChange,
|
onChange,
|
||||||
|
embedHandler,
|
||||||
});
|
});
|
||||||
|
|
||||||
const editorContainerClassName = getEditorClassNames({
|
const editorContainerClassName = getEditorClassNames({
|
||||||
@ -98,6 +99,8 @@ const DocumentEditor = (props: IDocumentEditorProps) => {
|
|||||||
editorContainerClassName={cn(editorContainerClassName, "document-editor")}
|
editorContainerClassName={cn(editorContainerClassName, "document-editor")}
|
||||||
id={id}
|
id={id}
|
||||||
isTouchDevice={!!isTouchDevice}
|
isTouchDevice={!!isTouchDevice}
|
||||||
|
flaggedExtensions={flaggedExtensions}
|
||||||
|
disabledExtensions={disabledExtensions}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { cn } from "@plane/utils";
|
|||||||
import { DocumentContentLoader, EditorContainer, EditorContentWrapper } from "@/components/editors";
|
import { DocumentContentLoader, EditorContainer, EditorContentWrapper } from "@/components/editors";
|
||||||
import { AIFeaturesMenu, BlockMenu, EditorBubbleMenu } from "@/components/menus";
|
import { AIFeaturesMenu, BlockMenu, EditorBubbleMenu } from "@/components/menus";
|
||||||
// types
|
// types
|
||||||
import { TAIHandler, TDisplayConfig } from "@/types";
|
import { IEditorProps, TAIHandler, TDisplayConfig } from "@/types";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
aiHandler?: TAIHandler;
|
aiHandler?: TAIHandler;
|
||||||
@ -18,6 +18,8 @@ type Props = {
|
|||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
isTouchDevice: boolean;
|
isTouchDevice: boolean;
|
||||||
tabIndex?: number;
|
tabIndex?: number;
|
||||||
|
flaggedExtensions?: IEditorProps["flaggedExtensions"];
|
||||||
|
disabledExtensions?: IEditorProps["disabledExtensions"];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const PageRenderer = (props: Props) => {
|
export const PageRenderer = (props: Props) => {
|
||||||
@ -32,6 +34,8 @@ export const PageRenderer = (props: Props) => {
|
|||||||
isLoading,
|
isLoading,
|
||||||
isTouchDevice,
|
isTouchDevice,
|
||||||
tabIndex,
|
tabIndex,
|
||||||
|
flaggedExtensions,
|
||||||
|
disabledExtensions,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -54,7 +58,11 @@ export const PageRenderer = (props: Props) => {
|
|||||||
{editor.isEditable && !isTouchDevice && (
|
{editor.isEditable && !isTouchDevice && (
|
||||||
<div>
|
<div>
|
||||||
{bubbleMenuEnabled && <EditorBubbleMenu editor={editor} />}
|
{bubbleMenuEnabled && <EditorBubbleMenu editor={editor} />}
|
||||||
<BlockMenu editor={editor} />
|
<BlockMenu
|
||||||
|
editor={editor}
|
||||||
|
flaggedExtensions={flaggedExtensions}
|
||||||
|
disabledExtensions={disabledExtensions}
|
||||||
|
/>
|
||||||
<AIFeaturesMenu menu={aiHandler?.menu} />
|
<AIFeaturesMenu menu={aiHandler?.menu} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -41,6 +41,7 @@ export const EditorWrapper: React.FC<Props> = (props) => {
|
|||||||
placeholder,
|
placeholder,
|
||||||
tabIndex,
|
tabIndex,
|
||||||
value,
|
value,
|
||||||
|
embedHandler,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const editor = useEditor({
|
const editor = useEditor({
|
||||||
@ -65,6 +66,7 @@ export const EditorWrapper: React.FC<Props> = (props) => {
|
|||||||
placeholder,
|
placeholder,
|
||||||
tabIndex,
|
tabIndex,
|
||||||
value,
|
value,
|
||||||
|
embedHandler,
|
||||||
});
|
});
|
||||||
|
|
||||||
const editorContainerClassName = getEditorClassNames({
|
const editorContainerClassName = getEditorClassNames({
|
||||||
|
|||||||
@ -1,8 +1,12 @@
|
|||||||
import { autoUpdate, flip, hide, shift, useDismiss, useFloating, useInteractions } from "@floating-ui/react";
|
import { autoUpdate, flip, hide, shift, useDismiss, useFloating, useInteractions } from "@floating-ui/react";
|
||||||
import { Editor, useEditorState } from "@tiptap/react";
|
import { Editor, useEditorState } from "@tiptap/react";
|
||||||
import { FC, useCallback, useEffect, useRef, useState } from "react";
|
import { FC, useCallback, useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
// components
|
// components
|
||||||
import { LinkView, LinkViewProps } from "@/components/links";
|
import { LinkView, LinkViewProps } from "@/components/links";
|
||||||
|
import { CORE_EXTENSIONS } from "@/constants/extension";
|
||||||
|
// components
|
||||||
|
import { getExtensionStorage } from "@/helpers/get-extension-storage";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
editor: Editor;
|
editor: Editor;
|
||||||
@ -18,7 +22,7 @@ export const LinkViewContainer: FC<Props> = ({ editor, containerRef }) => {
|
|||||||
const editorState = useEditorState({
|
const editorState = useEditorState({
|
||||||
editor,
|
editor,
|
||||||
selector: ({ editor }: { editor: Editor }) => ({
|
selector: ({ editor }: { editor: Editor }) => ({
|
||||||
linkExtensionStorage: editor.storage.link,
|
linkExtensionStorage: getExtensionStorage(editor, CORE_EXTENSIONS.CUSTOM_LINK),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -4,9 +4,12 @@ import { useCallback, useEffect, useRef } from "react";
|
|||||||
import tippy, { Instance } from "tippy.js";
|
import tippy, { Instance } from "tippy.js";
|
||||||
// constants
|
// constants
|
||||||
import { CORE_EXTENSIONS } from "@/constants/extension";
|
import { CORE_EXTENSIONS } from "@/constants/extension";
|
||||||
|
import { IEditorProps } from "@/types";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
editor: Editor;
|
editor: Editor;
|
||||||
|
flaggedExtensions?: IEditorProps["flaggedExtensions"];
|
||||||
|
disabledExtensions?: IEditorProps["disabledExtensions"];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const BlockMenu = (props: Props) => {
|
export const BlockMenu = (props: Props) => {
|
||||||
|
|||||||
@ -81,6 +81,7 @@ declare module "@tiptap/core" {
|
|||||||
export type CustomLinkStorage = {
|
export type CustomLinkStorage = {
|
||||||
isPreviewOpen: boolean;
|
isPreviewOpen: boolean;
|
||||||
posToInsert: { from: number; to: number };
|
posToInsert: { from: number; to: number };
|
||||||
|
isBubbleMenuOpen: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CustomLinkExtension = Mark.create<LinkOptions, CustomLinkStorage>({
|
export const CustomLinkExtension = Mark.create<LinkOptions, CustomLinkStorage>({
|
||||||
|
|||||||
@ -29,7 +29,7 @@ import {
|
|||||||
// plane editor extensions
|
// plane editor extensions
|
||||||
import { CoreEditorAdditionalExtensions } from "@/plane-editor/extensions";
|
import { CoreEditorAdditionalExtensions } from "@/plane-editor/extensions";
|
||||||
// types
|
// types
|
||||||
import type { IEditorProps } from "@/types";
|
import type { IEditorProps, TEmbedConfig } from "@/types";
|
||||||
// local imports
|
// local imports
|
||||||
import { CustomImageExtension } from "./custom-image/extension";
|
import { CustomImageExtension } from "./custom-image/extension";
|
||||||
import { EmojiExtension } from "./emoji/extension";
|
import { EmojiExtension } from "./emoji/extension";
|
||||||
@ -45,9 +45,11 @@ type TArguments = Pick<
|
|||||||
| "mentionHandler"
|
| "mentionHandler"
|
||||||
| "placeholder"
|
| "placeholder"
|
||||||
| "tabIndex"
|
| "tabIndex"
|
||||||
|
| "embedHandler"
|
||||||
> & {
|
> & {
|
||||||
enableHistory: boolean;
|
enableHistory: boolean;
|
||||||
editable: boolean;
|
editable: boolean;
|
||||||
|
embedHandler?: TEmbedConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const CoreEditorExtensions = (args: TArguments): Extensions => {
|
export const CoreEditorExtensions = (args: TArguments): Extensions => {
|
||||||
@ -60,6 +62,7 @@ export const CoreEditorExtensions = (args: TArguments): Extensions => {
|
|||||||
mentionHandler,
|
mentionHandler,
|
||||||
placeholder,
|
placeholder,
|
||||||
tabIndex,
|
tabIndex,
|
||||||
|
embedHandler,
|
||||||
editable,
|
editable,
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
@ -115,6 +118,7 @@ export const CoreEditorExtensions = (args: TArguments): Extensions => {
|
|||||||
disabledExtensions,
|
disabledExtensions,
|
||||||
flaggedExtensions,
|
flaggedExtensions,
|
||||||
fileHandler,
|
fileHandler,
|
||||||
|
embedHandler,
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@ -80,6 +80,7 @@ export const useCollaborativeEditor = (props: TCollaborativeEditorHookProps) =>
|
|||||||
);
|
);
|
||||||
|
|
||||||
const editor = useEditor({
|
const editor = useEditor({
|
||||||
|
embedHandler,
|
||||||
disabledExtensions,
|
disabledExtensions,
|
||||||
id,
|
id,
|
||||||
editable,
|
editable,
|
||||||
|
|||||||
@ -32,6 +32,7 @@ export const useEditor = (props: TEditorHookProps) => {
|
|||||||
onAssetChange,
|
onAssetChange,
|
||||||
onChange,
|
onChange,
|
||||||
onEditorFocus,
|
onEditorFocus,
|
||||||
|
embedHandler,
|
||||||
onTransaction,
|
onTransaction,
|
||||||
placeholder,
|
placeholder,
|
||||||
provider,
|
provider,
|
||||||
@ -63,6 +64,7 @@ export const useEditor = (props: TEditorHookProps) => {
|
|||||||
mentionHandler,
|
mentionHandler,
|
||||||
placeholder,
|
placeholder,
|
||||||
tabIndex,
|
tabIndex,
|
||||||
|
embedHandler,
|
||||||
}),
|
}),
|
||||||
...extensions,
|
...extensions,
|
||||||
],
|
],
|
||||||
|
|||||||
@ -21,6 +21,7 @@ const generalSelectors = [
|
|||||||
".image-component",
|
".image-component",
|
||||||
".image-upload-component",
|
".image-upload-component",
|
||||||
".editor-callout-component",
|
".editor-callout-component",
|
||||||
|
".editor-embed-component",
|
||||||
].join(", ");
|
].join(", ");
|
||||||
|
|
||||||
const maxScrollSpeed = 20;
|
const maxScrollSpeed = 20;
|
||||||
@ -103,6 +104,11 @@ export const nodeDOMAtCoords = (coords: { x: number; y: number }) => {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skip elements inside .editor-embed-component
|
||||||
|
if (elem.closest(".editor-embed-component") && !elem.matches(".editor-embed-component")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// apply general selector
|
// apply general selector
|
||||||
if (elem.matches(generalSelectors)) {
|
if (elem.matches(generalSelectors)) {
|
||||||
return elem;
|
return elem;
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import type { Content, Extensions, JSONContent, RawCommands } from "@tiptap/core
|
|||||||
import type { MarkType, NodeType } from "@tiptap/pm/model";
|
import type { MarkType, NodeType } from "@tiptap/pm/model";
|
||||||
import type { Selection } from "@tiptap/pm/state";
|
import type { Selection } from "@tiptap/pm/state";
|
||||||
import type { EditorProps, EditorView } from "@tiptap/pm/view";
|
import type { EditorProps, EditorView } from "@tiptap/pm/view";
|
||||||
|
import type { NodeViewProps as TNodeViewProps } from "@tiptap/react";
|
||||||
// extension types
|
// extension types
|
||||||
import type { TTextAlign } from "@/extensions";
|
import type { TTextAlign } from "@/extensions";
|
||||||
// types
|
// types
|
||||||
@ -48,7 +49,8 @@ export type TEditorCommands =
|
|||||||
| "text-align"
|
| "text-align"
|
||||||
| "callout"
|
| "callout"
|
||||||
| "attachment"
|
| "attachment"
|
||||||
| "emoji";
|
| "emoji"
|
||||||
|
| "external-embed";
|
||||||
|
|
||||||
export type TCommandExtraProps = {
|
export type TCommandExtraProps = {
|
||||||
image: {
|
image: {
|
||||||
@ -138,6 +140,7 @@ export type IEditorProps = {
|
|||||||
editorClassName?: string;
|
editorClassName?: string;
|
||||||
editorProps?: EditorProps;
|
editorProps?: EditorProps;
|
||||||
extensions?: Extensions;
|
extensions?: Extensions;
|
||||||
|
embedHandler?: TEmbedConfig;
|
||||||
flaggedExtensions: TExtensions[];
|
flaggedExtensions: TExtensions[];
|
||||||
fileHandler: TFileHandler;
|
fileHandler: TFileHandler;
|
||||||
forwardedRef?: React.MutableRefObject<EditorRefApi | null>;
|
forwardedRef?: React.MutableRefObject<EditorRefApi | null>;
|
||||||
@ -191,3 +194,5 @@ export type EditorEvents = {
|
|||||||
destroy: never;
|
destroy: never;
|
||||||
ready: { height: number };
|
ready: { height: number };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type NodeViewProps = TNodeViewProps;
|
||||||
|
|||||||
@ -13,6 +13,7 @@ type TCoreHookProps = Pick<
|
|||||||
| "handleEditorReady"
|
| "handleEditorReady"
|
||||||
| "isTouchDevice"
|
| "isTouchDevice"
|
||||||
| "onEditorFocus"
|
| "onEditorFocus"
|
||||||
|
| "embedHandler"
|
||||||
>;
|
>;
|
||||||
|
|
||||||
export type TEditorHookProps = TCoreHookProps &
|
export type TEditorHookProps = TCoreHookProps &
|
||||||
|
|||||||
@ -174,7 +174,7 @@ export const isCommentEmpty = (comment: string | undefined): boolean => {
|
|||||||
return (
|
return (
|
||||||
comment?.trim() === "" ||
|
comment?.trim() === "" ||
|
||||||
comment === "<p></p>" ||
|
comment === "<p></p>" ||
|
||||||
isEmptyHtmlString(comment ?? "", ["img", "mention-component", "image-component"])
|
isEmptyHtmlString(comment ?? "", ["img", "mention-component", "image-component", "embed-component"])
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user