refactoring tiptap to core/lite/rich text editor

This commit is contained in:
Palanikannan1437 2023-10-02 14:52:16 +05:30
parent b5228bb0ef
commit 3d87a56e3b
17 changed files with 122 additions and 91 deletions

View File

@ -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;

View File

@ -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>

View File

@ -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({

View File

@ -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

View File

@ -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 };

View File

@ -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 {

View File

@ -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} />
)); ));

View File

@ -1,3 +1,3 @@
import "./styles/github-dark.css"; import "@/styles/github-dark.css";
export { RichTextEditor, RichTextEditorWithRef } from "@/ui"; export { RichTextEditor, RichTextEditorWithRef } from "@/ui";

View File

@ -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,

View File

@ -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} />
)); ));

View File

@ -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;

View File

@ -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}

View File

@ -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>

View File

@ -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}

View File

@ -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

View File

@ -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;

View File

@ -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"