mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
exported tiptap editor with and without ref
This commit is contained in:
parent
7ef1745e38
commit
3b9c29cfd4
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "@plane/editor",
|
"name": "plane-editor",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"description": "Rich Text Editor that powers Plane",
|
"description": "Rich Text Editor that powers Plane",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
@ -69,7 +69,7 @@
|
|||||||
"eslint": "^7.32.0",
|
"eslint": "^7.32.0",
|
||||||
"postcss": "^8.4.29",
|
"postcss": "^8.4.29",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"tailwind-config": "*",
|
"tailwind-config-custom": "*",
|
||||||
"tsconfig": "*",
|
"tsconfig": "*",
|
||||||
"tsup": "^7.2.0",
|
"tsup": "^7.2.0",
|
||||||
"typescript": "4.9.5"
|
"typescript": "4.9.5"
|
||||||
@ -80,5 +80,12 @@
|
|||||||
"markdown",
|
"markdown",
|
||||||
"nextjs",
|
"nextjs",
|
||||||
"react"
|
"react"
|
||||||
|
],
|
||||||
|
"typesVersions": {
|
||||||
|
"*": {
|
||||||
|
"*": [
|
||||||
|
"src/*"
|
||||||
]
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import "@/styles/tailwind.css";
|
import "@/styles/tailwind.css";
|
||||||
import "@/styles/editor.css";
|
import "@/styles/editor.css";
|
||||||
|
|
||||||
export { TipTapEditor } from "@/ui/editor";
|
export { TiptapEditor, TiptapEditorWithRef } from "@/ui/editor";
|
||||||
|
@ -10,8 +10,9 @@ import { ImageResizer } from '@/ui/editor/extensions/image/image-resize';
|
|||||||
import { TiptapEditorProps } from '@/ui/editor/props';
|
import { TiptapEditorProps } from '@/ui/editor/props';
|
||||||
import { UploadImage } from '@/types/upload-image';
|
import { UploadImage } from '@/types/upload-image';
|
||||||
import { DeleteImage } from '@/types/delete-image';
|
import { DeleteImage } from '@/types/delete-image';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
export interface ITipTapRichTextEditor {
|
interface ITiptapEditor {
|
||||||
value: string;
|
value: string;
|
||||||
uploadFile: UploadImage;
|
uploadFile: UploadImage;
|
||||||
deleteFile: DeleteImage;
|
deleteFile: DeleteImage;
|
||||||
@ -28,11 +29,20 @@ export interface ITipTapRichTextEditor {
|
|||||||
debouncedUpdatesEnabled?: boolean;
|
debouncedUpdatesEnabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Tiptap = (props: ITipTapRichTextEditor) => {
|
interface TiptapProps extends ITiptapEditor {
|
||||||
const {
|
forwardedRef?: React.Ref<EditorHandle>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EditorHandle {
|
||||||
|
clearEditor: () => void;
|
||||||
|
setEditorValue: (content: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEBOUNCE_DELAY = 1500;
|
||||||
|
|
||||||
|
const TiptapEditor = ({
|
||||||
onChange,
|
onChange,
|
||||||
debouncedUpdatesEnabled,
|
debouncedUpdatesEnabled,
|
||||||
forwardedRef,
|
|
||||||
editable,
|
editable,
|
||||||
setIsSubmitting,
|
setIsSubmitting,
|
||||||
setShouldShowAlert,
|
setShouldShowAlert,
|
||||||
@ -44,12 +54,12 @@ const Tiptap = (props: ITipTapRichTextEditor) => {
|
|||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
borderOnFocus,
|
borderOnFocus,
|
||||||
customClassName,
|
customClassName,
|
||||||
} = props;
|
forwardedRef,
|
||||||
|
}: TiptapProps) => {
|
||||||
const editor = useEditor({
|
const editor = useEditor({
|
||||||
editable: editable ?? true,
|
editable: editable ?? true,
|
||||||
editorProps: TiptapEditorProps(workspaceSlug, uploadFile, setIsSubmitting),
|
editorProps: TiptapEditorProps(workspaceSlug, uploadFile, setIsSubmitting),
|
||||||
// @ts-ignore
|
// @ts-expect-error
|
||||||
extensions: TiptapExtensions(workspaceSlug, uploadFile, deleteFile, setIsSubmitting),
|
extensions: TiptapExtensions(workspaceSlug, uploadFile, deleteFile, setIsSubmitting),
|
||||||
content: (typeof value === "string" && value.trim() !== "") ? value : "<p></p>",
|
content: (typeof value === "string" && value.trim() !== "") ? value : "<p></p>",
|
||||||
onUpdate: async ({ editor }) => {
|
onUpdate: async ({ editor }) => {
|
||||||
@ -65,6 +75,7 @@ const Tiptap = (props: ITipTapRichTextEditor) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const editorRef: React.MutableRefObject<Editor | null> = useRef(null);
|
const editorRef: React.MutableRefObject<Editor | null> = useRef(null);
|
||||||
|
editorRef.current = editor;
|
||||||
|
|
||||||
useImperativeHandle(forwardedRef, () => ({
|
useImperativeHandle(forwardedRef, () => ({
|
||||||
clearEditor: () => {
|
clearEditor: () => {
|
||||||
@ -76,19 +87,19 @@ const Tiptap = (props: ITipTapRichTextEditor) => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const debouncedUpdates = useDebouncedCallback(async ({ onChange, editor }) => {
|
const debouncedUpdates = useDebouncedCallback(async ({ onChange, editor }) => {
|
||||||
setTimeout(async () => {
|
|
||||||
if (onChange) {
|
if (onChange) {
|
||||||
onChange(editor.getJSON(), editor.getHTML());
|
onChange(editor.getJSON(), editor.getHTML());
|
||||||
}
|
}
|
||||||
}, 500);
|
}, DEBOUNCE_DELAY);
|
||||||
}, 1000);
|
|
||||||
|
|
||||||
const editorClassNames = `relative w-full max-w-full sm:rounded-lg mt-2 p-3 relative focus:outline-none rounded-md
|
const editorClassNames = cn(
|
||||||
${noBorder ? "" : "border border-custom-border-200"} ${borderOnFocus ? "focus:border border-custom-border-300" : "focus:border-0"
|
'relative w-full max-w-full sm:rounded-lg mt-2 p-3 relative focus:outline-none rounded-md',
|
||||||
} ${customClassName}`;
|
noBorder ? '' : 'border border-custom-border-200',
|
||||||
|
borderOnFocus ? 'focus:border border-custom-border-300' : 'focus:border-0',
|
||||||
|
customClassName
|
||||||
|
);
|
||||||
|
|
||||||
if (!editor) return null;
|
if (!editor) return null;
|
||||||
editorRef.current = editor;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@ -108,10 +119,10 @@ const Tiptap = (props: ITipTapRichTextEditor) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const TipTapEditor = forwardRef<ITipTapRichTextEditor, ITipTapRichTextEditor>((props, ref) => (
|
const TiptapEditorWithRef = forwardRef<EditorHandle, ITiptapEditor>((props, ref) => (
|
||||||
<Tiptap {...props} forwardedRef={ref} />
|
<TiptapEditor {...props} forwardedRef={ref} />
|
||||||
));
|
));
|
||||||
|
|
||||||
TipTapEditor.displayName = "TipTapEditor";
|
TiptapEditorWithRef.displayName = "TiptapEditorWithRef";
|
||||||
|
|
||||||
export { TipTapEditor };
|
export { TiptapEditor, TiptapEditorWithRef };
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const sharedConfig = require("tailwind-config/tailwind.config.js");
|
const sharedConfig = require("tailwind-config-custom/tailwind.config.js");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
// prefix ui lib classes to avoid conflicting with the app
|
// prefix ui lib classes to avoid conflicting with the app
|
||||||
|
@ -9,7 +9,7 @@ import { useDebouncedCallback } from "use-debounce";
|
|||||||
import { TextArea } from "components/ui";
|
import { TextArea } from "components/ui";
|
||||||
// types
|
// types
|
||||||
import { IIssue } from "types";
|
import { IIssue } from "types";
|
||||||
import { TipTapEditor } from "@plane/editor"
|
import { TiptapEditor } from "plane-editor"
|
||||||
import fileService from "services/file.service";
|
import fileService from "services/file.service";
|
||||||
|
|
||||||
export interface IssueDescriptionFormValues {
|
export interface IssueDescriptionFormValues {
|
||||||
@ -134,7 +134,7 @@ export const IssueDescriptionForm: FC<IssueDetailsProps> = ({
|
|||||||
if (!value) return <></>;
|
if (!value) return <></>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TipTapEditor
|
<TiptapEditor
|
||||||
uploadFile={fileService.uploadFile}
|
uploadFile={fileService.uploadFile}
|
||||||
deleteFile={fileService.deleteImage}
|
deleteFile={fileService.deleteImage}
|
||||||
value={
|
value={
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
"@nivo/pie": "0.80.0",
|
"@nivo/pie": "0.80.0",
|
||||||
"@nivo/scatterplot": "0.80.0",
|
"@nivo/scatterplot": "0.80.0",
|
||||||
"@sentry/nextjs": "^7.36.0",
|
"@sentry/nextjs": "^7.36.0",
|
||||||
|
"plane-editor": "*",
|
||||||
"@tiptap/extension-code-block-lowlight": "^2.0.4",
|
"@tiptap/extension-code-block-lowlight": "^2.0.4",
|
||||||
"@tiptap/extension-color": "^2.0.4",
|
"@tiptap/extension-color": "^2.0.4",
|
||||||
"@tiptap/extension-gapcursor": "^2.1.7",
|
"@tiptap/extension-gapcursor": "^2.1.7",
|
||||||
@ -79,8 +80,7 @@
|
|||||||
"tiptap-markdown": "^0.8.2",
|
"tiptap-markdown": "^0.8.2",
|
||||||
"tlds": "^1.238.0",
|
"tlds": "^1.238.0",
|
||||||
"use-debounce": "^9.0.4",
|
"use-debounce": "^9.0.4",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0"
|
||||||
"@plane/editor": "*"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/js-cookie": "^3.0.2",
|
"@types/js-cookie": "^3.0.2",
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
const sharedConfig = require("tailwind-config/tailwind.config.js");
|
const sharedConfig = require("tailwind-config-custom/tailwind.config.js");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
presets: [sharedConfig],
|
presets: [sharedConfig],
|
||||||
|
Loading…
Reference in New Issue
Block a user