forked from github/plane
refactoring tiptap to core/lite/rich text editor
This commit is contained in:
parent
b5228bb0ef
commit
3d87a56e3b
@ -155,7 +155,7 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#tiptap-container {
|
#editor-container {
|
||||||
table {
|
table {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
table-layout: fixed;
|
table-layout: fixed;
|
||||||
|
@ -9,11 +9,11 @@ interface EditorContainerProps {
|
|||||||
|
|
||||||
export const EditorContainer = ({ editor, editorClassNames, children }: EditorContainerProps) => (
|
export const EditorContainer = ({ editor, editorClassNames, children }: EditorContainerProps) => (
|
||||||
<div
|
<div
|
||||||
id="tiptap-container"
|
id="editor-container"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
editor?.chain().focus().run();
|
editor?.chain().focus().run();
|
||||||
}}
|
}}
|
||||||
className={`tiptap-editor-container cursor-text ${editorClassNames}`}
|
className={`cursor-text ${editorClassNames}`}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
@ -19,7 +19,7 @@ import { DeleteImage } from "@/types/delete-image";
|
|||||||
|
|
||||||
import isValidHttpUrl from "@/ui/menus/bubble-menu/utils"
|
import isValidHttpUrl from "@/ui/menus/bubble-menu/utils"
|
||||||
|
|
||||||
export const TiptapExtensions = (
|
export const CoreEditorExtensions = (
|
||||||
deleteFile: DeleteImage,
|
deleteFile: DeleteImage,
|
||||||
) => [
|
) => [
|
||||||
StarterKit.configure({
|
StarterKit.configure({
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
import { useEditor as useCustomEditor, Editor, Extension, Node, Mark } from "@tiptap/react";
|
import { useEditor as useCustomEditor, Editor } from "@tiptap/react";
|
||||||
import { useImperativeHandle, useRef, MutableRefObject, forwardRef } from "react";
|
import { useImperativeHandle, useRef, MutableRefObject } from "react";
|
||||||
import { useDebouncedCallback } from "use-debounce";
|
import { useDebouncedCallback } from "use-debounce";
|
||||||
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 { TiptapEditorProps } from "../props";
|
import { CoreEditorProps } from "../props";
|
||||||
import { TiptapExtensions } from "../extensions";
|
import { CoreEditorExtensions } from "../extensions";
|
||||||
import { EditorProps } from '@tiptap/pm/view';
|
import { EditorProps } from '@tiptap/pm/view';
|
||||||
|
|
||||||
const DEBOUNCE_DELAY = 1500;
|
const DEBOUNCE_DELAY = 1500;
|
||||||
@ -27,10 +27,10 @@ export const useEditor = ({ uploadFile, editable, deleteFile, editorProps = {},
|
|||||||
const editor = useCustomEditor({
|
const editor = useCustomEditor({
|
||||||
editable: editable ?? true,
|
editable: editable ?? true,
|
||||||
editorProps: {
|
editorProps: {
|
||||||
...TiptapEditorProps(uploadFile, setIsSubmitting),
|
...CoreEditorProps(uploadFile, setIsSubmitting),
|
||||||
...editorProps,
|
...editorProps,
|
||||||
},
|
},
|
||||||
extensions: [...TiptapExtensions(deleteFile), ...extensions],
|
extensions: [...CoreEditorExtensions(deleteFile), ...extensions],
|
||||||
content: (typeof value === "string" && value.trim() !== "") ? value : "<p></p>",
|
content: (typeof value === "string" && value.trim() !== "") ? value : "<p></p>",
|
||||||
onUpdate: async ({ editor }) => {
|
onUpdate: async ({ editor }) => {
|
||||||
// for instant feedback loop
|
// for instant feedback loop
|
||||||
|
@ -9,7 +9,7 @@ import { useEditor } from './hooks/useEditor';
|
|||||||
import { EditorContainer } from '@/ui/editor-container';
|
import { EditorContainer } from '@/ui/editor-container';
|
||||||
import { EditorContentWrapper } from '@/ui/editor-content';
|
import { EditorContentWrapper } from '@/ui/editor-content';
|
||||||
|
|
||||||
interface ITiptapEditor {
|
interface ICoreEditor {
|
||||||
value: string;
|
value: string;
|
||||||
uploadFile: UploadImage;
|
uploadFile: UploadImage;
|
||||||
deleteFile: DeleteImage;
|
deleteFile: DeleteImage;
|
||||||
@ -34,7 +34,7 @@ interface ITiptapEditor {
|
|||||||
editorProps?: EditorProps;
|
editorProps?: EditorProps;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TiptapProps extends ITiptapEditor {
|
interface EditorCoreProps extends ICoreEditor {
|
||||||
forwardedRef?: React.Ref<EditorHandle>;
|
forwardedRef?: React.Ref<EditorHandle>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ interface EditorHandle {
|
|||||||
setEditorValue: (content: string) => void;
|
setEditorValue: (content: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const TiptapEditor = ({
|
const CoreEditor = ({
|
||||||
onChange,
|
onChange,
|
||||||
debouncedUpdatesEnabled,
|
debouncedUpdatesEnabled,
|
||||||
editable,
|
editable,
|
||||||
@ -57,7 +57,7 @@ const TiptapEditor = ({
|
|||||||
borderOnFocus,
|
borderOnFocus,
|
||||||
customClassName,
|
customClassName,
|
||||||
forwardedRef,
|
forwardedRef,
|
||||||
}: TiptapProps) => {
|
}: EditorCoreProps) => {
|
||||||
const editor = useEditor({
|
const editor = useEditor({
|
||||||
onChange,
|
onChange,
|
||||||
debouncedUpdatesEnabled,
|
debouncedUpdatesEnabled,
|
||||||
@ -83,10 +83,10 @@ const TiptapEditor = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const TiptapEditorWithRef = React.forwardRef<EditorHandle, ITiptapEditor>((props, ref) => (
|
const CoreEditorWithRef = React.forwardRef<EditorHandle, ICoreEditor>((props, ref) => (
|
||||||
<TiptapEditor {...props} forwardedRef={ref} />
|
<CoreEditor {...props} forwardedRef={ref} />
|
||||||
));
|
));
|
||||||
|
|
||||||
TiptapEditorWithRef.displayName = "TiptapEditorWithRef";
|
CoreEditorWithRef.displayName = "CoreEditorWithRef";
|
||||||
|
|
||||||
export { TiptapEditor, TiptapEditorWithRef };
|
export { CoreEditor, CoreEditorWithRef };
|
||||||
|
@ -3,7 +3,7 @@ import { findTableAncestor } from "@/lib/utils";
|
|||||||
import { startImageUpload } from "@/ui/plugins/upload-image";
|
import { startImageUpload } from "@/ui/plugins/upload-image";
|
||||||
import { UploadImage } from "@/types/upload-image";
|
import { UploadImage } from "@/types/upload-image";
|
||||||
|
|
||||||
export function TiptapEditorProps(
|
export function CoreEditorProps(
|
||||||
uploadFile: UploadImage,
|
uploadFile: UploadImage,
|
||||||
setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void
|
setIsSubmitting?: (isSubmitting: "submitting" | "submitted" | "saved") => void
|
||||||
): EditorProps {
|
): EditorProps {
|
||||||
|
@ -6,7 +6,7 @@ import { FixedMenu } from './menus/fixed-menu';
|
|||||||
export type UploadImage = (file: File) => Promise<string>;
|
export type UploadImage = (file: File) => Promise<string>;
|
||||||
export type DeleteImage = (assetUrlWithWorkspaceId: string) => Promise<any>;
|
export type DeleteImage = (assetUrlWithWorkspaceId: string) => Promise<any>;
|
||||||
|
|
||||||
interface ITiptapEditor {
|
interface ILiteTextEditor {
|
||||||
value: string;
|
value: string;
|
||||||
uploadFile: UploadImage;
|
uploadFile: UploadImage;
|
||||||
deleteFile: DeleteImage;
|
deleteFile: DeleteImage;
|
||||||
@ -32,7 +32,7 @@ interface ITiptapEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TiptapProps extends ITiptapEditor {
|
interface LiteTextEditorProps extends ILiteTextEditor {
|
||||||
forwardedRef?: React.Ref<EditorHandle>;
|
forwardedRef?: React.Ref<EditorHandle>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ const LiteTextEditor = ({
|
|||||||
customClassName,
|
customClassName,
|
||||||
forwardedRef,
|
forwardedRef,
|
||||||
commentAccessSpecifier,
|
commentAccessSpecifier,
|
||||||
}: TiptapProps) => {
|
}: LiteTextEditorProps) => {
|
||||||
const editor = useEditor({
|
const editor = useEditor({
|
||||||
onChange,
|
onChange,
|
||||||
debouncedUpdatesEnabled,
|
debouncedUpdatesEnabled,
|
||||||
@ -87,7 +87,7 @@ const LiteTextEditor = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const LiteTextEditorWithRef = React.forwardRef<EditorHandle, ITiptapEditor>((props, ref) => (
|
const LiteTextEditorWithRef = React.forwardRef<EditorHandle, ILiteTextEditor>((props, ref) => (
|
||||||
<LiteTextEditor {...props} forwardedRef={ref} />
|
<LiteTextEditor {...props} forwardedRef={ref} />
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
import "./styles/github-dark.css";
|
import "@/styles/github-dark.css";
|
||||||
|
|
||||||
export { RichTextEditor, RichTextEditorWithRef } from "@/ui";
|
export { RichTextEditor, RichTextEditorWithRef } from "@/ui";
|
||||||
|
@ -315,7 +315,7 @@ const renderItems = () => {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
popup = tippy("body", {
|
popup = tippy("body", {
|
||||||
getReferenceClientRect: props.clientRect,
|
getReferenceClientRect: props.clientRect,
|
||||||
appendTo: () => document.querySelector("#tiptap-container"),
|
appendTo: () => document.querySelector("#editor-container"),
|
||||||
content: component.element,
|
content: component.element,
|
||||||
showOnCreate: true,
|
showOnCreate: true,
|
||||||
interactive: true,
|
interactive: true,
|
||||||
|
@ -7,7 +7,7 @@ import { RichTextEditorExtensions } from './extensions';
|
|||||||
export type UploadImage = (file: File) => Promise<string>;
|
export type UploadImage = (file: File) => Promise<string>;
|
||||||
export type DeleteImage = (assetUrlWithWorkspaceId: string) => Promise<any>;
|
export type DeleteImage = (assetUrlWithWorkspaceId: string) => Promise<any>;
|
||||||
|
|
||||||
interface ITiptapEditor {
|
interface IRichTextEditor {
|
||||||
value: string;
|
value: string;
|
||||||
uploadFile: UploadImage;
|
uploadFile: UploadImage;
|
||||||
deleteFile: DeleteImage;
|
deleteFile: DeleteImage;
|
||||||
@ -23,7 +23,7 @@ interface ITiptapEditor {
|
|||||||
debouncedUpdatesEnabled?: boolean;
|
debouncedUpdatesEnabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TiptapProps extends ITiptapEditor {
|
interface RichTextEditorProps extends IRichTextEditor {
|
||||||
forwardedRef?: React.Ref<EditorHandle>;
|
forwardedRef?: React.Ref<EditorHandle>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ const RichTextEditor = ({
|
|||||||
borderOnFocus,
|
borderOnFocus,
|
||||||
customClassName,
|
customClassName,
|
||||||
forwardedRef,
|
forwardedRef,
|
||||||
}: TiptapProps) => {
|
}: RichTextEditorProps) => {
|
||||||
const editor = useEditor({
|
const editor = useEditor({
|
||||||
onChange,
|
onChange,
|
||||||
debouncedUpdatesEnabled,
|
debouncedUpdatesEnabled,
|
||||||
@ -74,7 +74,7 @@ const RichTextEditor = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const RichTextEditorWithRef = React.forwardRef<EditorHandle, ITiptapEditor>((props, ref) => (
|
const RichTextEditorWithRef = React.forwardRef<EditorHandle, IRichTextEditor>((props, ref) => (
|
||||||
<RichTextEditor {...props} forwardedRef={ref} />
|
<RichTextEditor {...props} forwardedRef={ref} />
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -155,7 +155,7 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#tiptap-container {
|
#editor-container {
|
||||||
table {
|
table {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
table-layout: fixed;
|
table-layout: fixed;
|
||||||
|
@ -25,7 +25,7 @@ import { CreateLabelModal } from "components/labels";
|
|||||||
// ui
|
// ui
|
||||||
import { CustomMenu, Input, PrimaryButton, SecondaryButton, ToggleSwitch } from "components/ui";
|
import { CustomMenu, Input, PrimaryButton, SecondaryButton, ToggleSwitch } from "components/ui";
|
||||||
// components
|
// components
|
||||||
import { TiptapEditorWithRef } from "@plane/rich-text-editor";
|
import { RichTextEditorWithRef } from "@plane/rich-text-editor";
|
||||||
// icons
|
// icons
|
||||||
import { SparklesIcon, XMarkIcon } from "@heroicons/react/24/outline";
|
import { SparklesIcon, XMarkIcon } from "@heroicons/react/24/outline";
|
||||||
// types
|
// types
|
||||||
@ -386,7 +386,7 @@ export const DraftIssueForm: FC<IssueFormProps> = (props) => {
|
|||||||
if (!value && !watch("description_html")) return <></>;
|
if (!value && !watch("description_html")) return <></>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TiptapEditorWithRef
|
<RichTextEditorWithRef
|
||||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||||
deleteFile={fileService.deleteImage}
|
deleteFile={fileService.deleteImage}
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
|
@ -25,7 +25,7 @@ import { CreateLabelModal } from "components/labels";
|
|||||||
// ui
|
// ui
|
||||||
import { CustomMenu, Input, PrimaryButton, SecondaryButton, ToggleSwitch } from "components/ui";
|
import { CustomMenu, Input, PrimaryButton, SecondaryButton, ToggleSwitch } from "components/ui";
|
||||||
// components
|
// components
|
||||||
import { TiptapEditorWithRef } from "@plane/rich-text-editor";
|
import { RichTextEditorWithRef } from "@plane/rich-text-editor";
|
||||||
|
|
||||||
// icons
|
// icons
|
||||||
import { SparklesIcon, XMarkIcon } from "@heroicons/react/24/outline";
|
import { SparklesIcon, XMarkIcon } from "@heroicons/react/24/outline";
|
||||||
@ -353,9 +353,8 @@ export const IssueForm: FC<IssueFormProps> = (props) => {
|
|||||||
{issueName && issueName !== "" && (
|
{issueName && issueName !== "" && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className={`flex items-center gap-1 rounded px-1.5 py-1 text-xs hover:bg-custom-background-90 ${
|
className={`flex items-center gap-1 rounded px-1.5 py-1 text-xs hover:bg-custom-background-90 ${iAmFeelingLucky ? "cursor-wait" : ""
|
||||||
iAmFeelingLucky ? "cursor-wait" : ""
|
}`}
|
||||||
}`}
|
|
||||||
onClick={handleAutoGenerateDescription}
|
onClick={handleAutoGenerateDescription}
|
||||||
disabled={iAmFeelingLucky}
|
disabled={iAmFeelingLucky}
|
||||||
>
|
>
|
||||||
@ -384,15 +383,15 @@ export const IssueForm: FC<IssueFormProps> = (props) => {
|
|||||||
if (!value && !watch("description_html")) return <></>;
|
if (!value && !watch("description_html")) return <></>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TiptapEditorWithRef
|
<RichTextEditorWithRef
|
||||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||||
deleteFile={fileService.deleteImage}
|
deleteFile={fileService.deleteImage}
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
debouncedUpdatesEnabled={false}
|
debouncedUpdatesEnabled={false}
|
||||||
value={
|
value={
|
||||||
!value ||
|
!value ||
|
||||||
value === "" ||
|
value === "" ||
|
||||||
(typeof value === "object" && Object.keys(value).length === 0)
|
(typeof value === "object" && Object.keys(value).length === 0)
|
||||||
? watch("description_html")
|
? watch("description_html")
|
||||||
: value
|
: value
|
||||||
}
|
}
|
||||||
@ -570,7 +569,7 @@ export const IssueForm: FC<IssueFormProps> = (props) => {
|
|||||||
onClick={() => setCreateMore((prevData) => !prevData)}
|
onClick={() => setCreateMore((prevData) => !prevData)}
|
||||||
>
|
>
|
||||||
<span className="text-xs">Create more</span>
|
<span className="text-xs">Create more</span>
|
||||||
<ToggleSwitch value={createMore} onChange={() => {}} size="md" />
|
<ToggleSwitch value={createMore} onChange={() => { }} size="md" />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<SecondaryButton
|
<SecondaryButton
|
||||||
@ -586,8 +585,8 @@ export const IssueForm: FC<IssueFormProps> = (props) => {
|
|||||||
? "Updating Issue..."
|
? "Updating Issue..."
|
||||||
: "Update Issue"
|
: "Update Issue"
|
||||||
: isSubmitting
|
: isSubmitting
|
||||||
? "Adding Issue..."
|
? "Adding Issue..."
|
||||||
: "Add Issue"}
|
: "Add Issue"}
|
||||||
</PrimaryButton>
|
</PrimaryButton>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -11,7 +11,7 @@ import aiService from "services/ai.service";
|
|||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
// components
|
// components
|
||||||
import { GptAssistantModal } from "components/core";
|
import { GptAssistantModal } from "components/core";
|
||||||
import { TiptapEditorWithRef } from "@plane/rich-text-editor";
|
import { RichTextEditorWithRef } from "@plane/rich-text-editor";
|
||||||
import { PrimaryButton, SecondaryButton, TextArea } from "components/ui";
|
import { PrimaryButton, SecondaryButton, TextArea } from "components/ui";
|
||||||
// types
|
// types
|
||||||
import { ICurrentUserResponse, IPageBlock } from "types";
|
import { ICurrentUserResponse, IPageBlock } from "types";
|
||||||
@ -281,7 +281,7 @@ export const CreateUpdateBlockInline: React.FC<Props> = ({
|
|||||||
render={({ field: { value, onChange } }) => {
|
render={({ field: { value, onChange } }) => {
|
||||||
if (!data)
|
if (!data)
|
||||||
return (
|
return (
|
||||||
<TiptapEditorWithRef
|
<RichTextEditorWithRef
|
||||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||||
deleteFile={fileService.deleteImage}
|
deleteFile={fileService.deleteImage}
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
@ -302,7 +302,7 @@ export const CreateUpdateBlockInline: React.FC<Props> = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<TiptapEditorWithRef
|
<RichTextEditorWithRef
|
||||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||||
deleteFile={fileService.deleteImage}
|
deleteFile={fileService.deleteImage}
|
||||||
ref={editorRef}
|
ref={editorRef}
|
||||||
|
@ -10,8 +10,7 @@ import { useForm, Controller } from "react-hook-form";
|
|||||||
import useProjectDetails from "hooks/use-project-details";
|
import useProjectDetails from "hooks/use-project-details";
|
||||||
|
|
||||||
// components
|
// components
|
||||||
import { TiptapEditorWithRef } from "@plane/rich-text-editor";
|
import { LiteTextEditorWithRef } from "@plane/lite-text-editor";
|
||||||
|
|
||||||
// icons
|
// icons
|
||||||
import { Send } from "lucide-react";
|
import { Send } from "lucide-react";
|
||||||
|
|
||||||
@ -32,7 +31,13 @@ type Props = {
|
|||||||
onSubmit: (data: IIssueComment) => Promise<void>;
|
onSubmit: (data: IIssueComment) => Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const commentAccess = [
|
type commentAccessType = {
|
||||||
|
icon: string;
|
||||||
|
key: string;
|
||||||
|
label: "Private" | "Public";
|
||||||
|
}
|
||||||
|
|
||||||
|
const commentAccess: commentAccessType[] = [
|
||||||
{
|
{
|
||||||
icon: "lock",
|
icon: "lock",
|
||||||
key: "INTERNAL",
|
key: "INTERNAL",
|
||||||
@ -53,7 +58,7 @@ export const AddComment: React.FC<Props> = ({ disabled = false, onSubmit }) => {
|
|||||||
|
|
||||||
const { projectDetails } = useProjectDetails();
|
const { projectDetails } = useProjectDetails();
|
||||||
|
|
||||||
const showAccessSpecifier = projectDetails?.is_deployed;
|
const showAccessSpecifier = projectDetails?.is_deployed || false;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
control,
|
control,
|
||||||
@ -73,51 +78,30 @@ export const AddComment: React.FC<Props> = ({ disabled = false, onSubmit }) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="w-full flex gap-x-2" onSubmit={handleSubmit(handleAddComment)}>
|
<form className="w-full flex gap-x-2" onSubmit={handleSubmit(handleAddComment)}>
|
||||||
<div className="relative flex-grow">
|
<div className="relative flex-grow">
|
||||||
<Controller
|
|
||||||
name="comment_html"
|
|
||||||
control={control}
|
|
||||||
render={({ field: { value, onChange } }) => (
|
|
||||||
<TiptapEditorWithRef
|
|
||||||
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
|
||||||
deleteFile={fileService.deleteImage}
|
|
||||||
ref={editorRef}
|
|
||||||
value={!value || value === "" ? "<p></p>" : value}
|
|
||||||
customClassName="p-3 min-h-[100px] shadow-sm"
|
|
||||||
debouncedUpdatesEnabled={false}
|
|
||||||
onChange={(comment_json: Object, comment_html: string) => onChange(comment_html)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
{showAccessSpecifier && (
|
|
||||||
<div className="relative bottom-2 left-3 z-[1]">
|
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
|
||||||
name="access"
|
name="access"
|
||||||
render={({ field: { onChange, value } }) => (
|
control={control}
|
||||||
<div className="flex border border-custom-border-300 divide-x divide-custom-border-300 rounded overflow-hidden">
|
render={({ field: { onChange: onAccessChange, value: accessValue } }) => (
|
||||||
{commentAccess.map((access) => (
|
<Controller
|
||||||
<Tooltip key={access.key} tooltipContent={access.label}>
|
name="comment_html"
|
||||||
<button
|
control={control}
|
||||||
type="button"
|
render={({ field: { onChange: onCommentChange, value: commentValue } }) => (
|
||||||
onClick={() => onChange(access.key)}
|
<LiteTextEditorWithRef
|
||||||
className={`grid place-items-center p-1 hover:bg-custom-background-80 ${value === access.key ? "bg-custom-background-80" : ""
|
uploadFile={fileService.getUploadFileFunction(workspaceSlug as string)}
|
||||||
}`}
|
deleteFile={fileService.deleteImage}
|
||||||
>
|
ref={editorRef}
|
||||||
<Icon
|
value={!commentValue || commentValue === "" ? "<p></p>" : commentValue}
|
||||||
iconName={access.icon}
|
customClassName="p-3 min-h-[100px] shadow-sm"
|
||||||
className={`w-4 h-4 -mt-1 ${value === access.key ? "!text-custom-text-100" : "!text-custom-text-400"
|
debouncedUpdatesEnabled={false}
|
||||||
}`}
|
onChange={(comment_json: Object, comment_html: string) => onCommentChange(comment_html)}
|
||||||
/>
|
commentAccessSpecifier={{ accessValue, onAccessChange, showAccessSpecifier, commentAccess }}
|
||||||
</button>
|
/>
|
||||||
</Tooltip>
|
)}
|
||||||
))}
|
/>
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="inline">
|
<div className="inline">
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
|
@ -155,7 +155,7 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#tiptap-container {
|
#editor-container {
|
||||||
table {
|
table {
|
||||||
border-collapse: collapse;
|
border-collapse: collapse;
|
||||||
table-layout: fixed;
|
table-layout: fixed;
|
||||||
|
48
yarn.lock
48
yarn.lock
@ -2355,6 +2355,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.1.10.tgz#6d8f3c777f1700dcc6c903b1185576754175e366"
|
resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.1.10.tgz#6d8f3c777f1700dcc6c903b1185576754175e366"
|
||||||
integrity sha512-yhUKsac6nlqbPQfwQnp+4Jb110EqmzocXKoZacLwzHpM7JVsr2+LXMDu9kahtrvHNJErJljhnQvDHRsrrYeJkQ==
|
integrity sha512-yhUKsac6nlqbPQfwQnp+4Jb110EqmzocXKoZacLwzHpM7JVsr2+LXMDu9kahtrvHNJErJljhnQvDHRsrrYeJkQ==
|
||||||
|
|
||||||
|
"@tiptap/core@^2.1.11":
|
||||||
|
version "2.1.11"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.1.11.tgz#06bbd189c6b2dffe58b1c80f848737d76fb012bd"
|
||||||
|
integrity sha512-1W2DdjpPwfphHgQ3Qm4s5wzCnEjiXm1TeZ+6/zBl89yKURXgv8Mw1JGdj/NcImQjtDcsNn97MscACK3GKbEJBA==
|
||||||
|
|
||||||
"@tiptap/extension-blockquote@^2.1.10":
|
"@tiptap/extension-blockquote@^2.1.10":
|
||||||
version "2.1.10"
|
version "2.1.10"
|
||||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.1.10.tgz#dc475bef70dd460fc730a14b3b4cc18f37cd1b2d"
|
resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.1.10.tgz#dc475bef70dd460fc730a14b3b4cc18f37cd1b2d"
|
||||||
@ -2382,6 +2387,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.1.10.tgz#22dabaa8c087bd03c160590f7b8bf9b1501752b5"
|
resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.1.10.tgz#22dabaa8c087bd03c160590f7b8bf9b1501752b5"
|
||||||
integrity sha512-HBrsgDX1sMx6FSoKxAhz2On8lwL8S1lqNryMQBTE63PemjOxcyxPNdGWZz+JfQmxyvymQoGhibaW5ImNAK84Zg==
|
integrity sha512-HBrsgDX1sMx6FSoKxAhz2On8lwL8S1lqNryMQBTE63PemjOxcyxPNdGWZz+JfQmxyvymQoGhibaW5ImNAK84Zg==
|
||||||
|
|
||||||
|
"@tiptap/extension-code-block-lowlight@^2.1.11":
|
||||||
|
version "2.1.11"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.1.11.tgz#6eec38c3b8662fae81ec2f117a2d18564f1fbb1a"
|
||||||
|
integrity sha512-k3olDvsRYO32JR9hyNa6VLqUdhwcpLwvR4Z6tJ66jHag5rsfP/7JZxJhrX9A1AF/jRCILdTiq9DTKybHieFjsw==
|
||||||
|
|
||||||
"@tiptap/extension-code-block@^2.1.10":
|
"@tiptap/extension-code-block@^2.1.10":
|
||||||
version "2.1.10"
|
version "2.1.10"
|
||||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.1.10.tgz#a125a12f716728b271a130178c6fc60237ed46f5"
|
resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.1.10.tgz#a125a12f716728b271a130178c6fc60237ed46f5"
|
||||||
@ -2444,6 +2454,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.1.10.tgz#cfdb67530be100054fc8511942d4ec3534acf828"
|
resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.1.10.tgz#cfdb67530be100054fc8511942d4ec3534acf828"
|
||||||
integrity sha512-91lGpK2d6WMPhrMDPBURS8z8pEg1CUBYy7GmBenKvvgh+JzVhG+U6MtykfWNfm2R4iRXOl1xLbyUOCiOSUXodQ==
|
integrity sha512-91lGpK2d6WMPhrMDPBURS8z8pEg1CUBYy7GmBenKvvgh+JzVhG+U6MtykfWNfm2R4iRXOl1xLbyUOCiOSUXodQ==
|
||||||
|
|
||||||
|
"@tiptap/extension-horizontal-rule@^2.1.11":
|
||||||
|
version "2.1.11"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.1.11.tgz#e423a2b41123ef7f8d778a1cd026e6606e7be28b"
|
||||||
|
integrity sha512-uvHPa2YCKnDhtSBSZB3lk5U4H3wRKP0DNvVx4Y2F7MdQianVzcyOd1pZYO9BQs+lUB1aZots6doE69Zqz3mU2Q==
|
||||||
|
|
||||||
"@tiptap/extension-image@^2.1.7":
|
"@tiptap/extension-image@^2.1.7":
|
||||||
version "2.1.10"
|
version "2.1.10"
|
||||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.1.10.tgz#6c597ad02285f1f3508fd4aa21e30213657cbd7c"
|
resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.1.10.tgz#6c597ad02285f1f3508fd4aa21e30213657cbd7c"
|
||||||
@ -2481,6 +2496,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.0.3.tgz#69575353f09fc7524c9cdbfbf16c04f73c29d154"
|
resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.0.3.tgz#69575353f09fc7524c9cdbfbf16c04f73c29d154"
|
||||||
integrity sha512-Z42jo0termRAf0S0L8oxrts94IWX5waU4isS2CUw8xCUigYyCFslkhQXkWATO1qRbjNFLKN2C9qvCgGf4UeBrw==
|
integrity sha512-Z42jo0termRAf0S0L8oxrts94IWX5waU4isS2CUw8xCUigYyCFslkhQXkWATO1qRbjNFLKN2C9qvCgGf4UeBrw==
|
||||||
|
|
||||||
|
"@tiptap/extension-placeholder@^2.1.11":
|
||||||
|
version "2.1.11"
|
||||||
|
resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.1.11.tgz#ba115f714dd48d5bbc65df277b74f357ff3b100e"
|
||||||
|
integrity sha512-laHYRFxJWj6m72Yf1v6Q5nF2nvwWpQlKUj6Yu/yluOOoVE92HpLqCAvA8RamqLtPiw5VxR3v3oCY0WNeQRvyIg==
|
||||||
|
|
||||||
"@tiptap/extension-strike@^2.1.10":
|
"@tiptap/extension-strike@^2.1.10":
|
||||||
version "2.1.10"
|
version "2.1.10"
|
||||||
resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.1.10.tgz#ec311395d16af15345b63d2dac2d459b9ad5fa9e"
|
resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.1.10.tgz#ec311395d16af15345b63d2dac2d459b9ad5fa9e"
|
||||||
@ -2630,6 +2650,13 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/unist" "^2"
|
"@types/unist" "^2"
|
||||||
|
|
||||||
|
"@types/hast@^3.0.0":
|
||||||
|
version "3.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/hast/-/hast-3.0.1.tgz#e1705ec9258ac4885659c2d50bac06b4fcd16466"
|
||||||
|
integrity sha512-hs/iBJx2aydugBQx5ETV3ZgeSS0oIreQrFJ4bjBl0XvM4wAmDjFEALY7p0rTSLt2eL+ibjRAAs9dTPiCLtmbqQ==
|
||||||
|
dependencies:
|
||||||
|
"@types/unist" "*"
|
||||||
|
|
||||||
"@types/hoist-non-react-statics@^3.3.0":
|
"@types/hoist-non-react-statics@^3.3.0":
|
||||||
version "3.3.2"
|
version "3.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#dc1e9ded53375d37603c479cc12c693b0878aa2a"
|
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#dc1e9ded53375d37603c479cc12c693b0878aa2a"
|
||||||
@ -2851,6 +2878,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.4.tgz#2b38784cd16957d3782e8e2b31c03bc1d13b4d65"
|
resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.4.tgz#2b38784cd16957d3782e8e2b31c03bc1d13b4d65"
|
||||||
integrity sha512-IDaobHimLQhjwsQ/NMwRVfa/yL7L/wriQPMhw1ZJall0KX6E1oxk29XMDeilW5qTIg5aoiqf5Udy8U/51aNoQQ==
|
integrity sha512-IDaobHimLQhjwsQ/NMwRVfa/yL7L/wriQPMhw1ZJall0KX6E1oxk29XMDeilW5qTIg5aoiqf5Udy8U/51aNoQQ==
|
||||||
|
|
||||||
|
"@types/unist@*":
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-3.0.0.tgz#988ae8af1e5239e89f9fbb1ade4c935f4eeedf9a"
|
||||||
|
integrity sha512-MFETx3tbTjE7Uk6vvnWINA/1iJ7LuMdO4fcq8UfF0pRbj01aGLduVvQcRyswuACJdpnHgg8E3rQLhaRdNEJS0w==
|
||||||
|
|
||||||
"@types/unist@^2", "@types/unist@^2.0.0":
|
"@types/unist@^2", "@types/unist@^2.0.0":
|
||||||
version "2.0.8"
|
version "2.0.8"
|
||||||
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.8.tgz#bb197b9639aa1a04cf464a617fe800cccd92ad5c"
|
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.8.tgz#bb197b9639aa1a04cf464a617fe800cccd92ad5c"
|
||||||
@ -3936,6 +3968,13 @@ detect-node-es@^1.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493"
|
resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493"
|
||||||
integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==
|
integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==
|
||||||
|
|
||||||
|
devlop@^1.0.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/devlop/-/devlop-1.1.0.tgz#4db7c2ca4dc6e0e834c30be70c94bbc976dc7018"
|
||||||
|
integrity sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==
|
||||||
|
dependencies:
|
||||||
|
dequal "^2.0.0"
|
||||||
|
|
||||||
didyoumean@^1.2.2:
|
didyoumean@^1.2.2:
|
||||||
version "1.2.2"
|
version "1.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
|
resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037"
|
||||||
@ -5904,6 +5943,15 @@ lowlight@^2.9.0:
|
|||||||
fault "^2.0.0"
|
fault "^2.0.0"
|
||||||
highlight.js "~11.8.0"
|
highlight.js "~11.8.0"
|
||||||
|
|
||||||
|
lowlight@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-3.0.0.tgz#8772e6514f1c14cd576b5a7a22668f5aa2ddd10b"
|
||||||
|
integrity sha512-kedX6yxvgak8P4LGh3vKRDQuMbVcnP+qRuDJlve2w+mNJAbEhEQPjYCp9QJnpVL5F2aAAVjeIzzrbQZUKHiDJw==
|
||||||
|
dependencies:
|
||||||
|
"@types/hast" "^3.0.0"
|
||||||
|
devlop "^1.0.0"
|
||||||
|
highlight.js "~11.8.0"
|
||||||
|
|
||||||
lru-cache@^5.1.1:
|
lru-cache@^5.1.1:
|
||||||
version "5.1.1"
|
version "5.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
|
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
|
||||||
|
Loading…
Reference in New Issue
Block a user