From 6b1879cbb1d5129b8960a5dec9880f4951c0222e Mon Sep 17 00:00:00 2001 From: Meier Lukas Date: Sat, 13 Apr 2024 12:32:55 +0200 Subject: [PATCH] feat: add notebook widget (#294) * feat: add nestjs replacement, remove nestjs * feat: add notebook widget * fix: format issue * fix: add missing tiptap packages * refactor: improve structure of table options * fix: downgrade to tiptap 2.2.5 as not yet supported by mantine/tiptap * fix: format issue * fix: deepsource issues * fix: typecheck issues * refactor: move default notebook content to seperate file * fix: format issue --- apps/nextjs/package.json | 3 - .../app/[locale]/widgets/[kind]/_content.tsx | 2 + .../src/components/board/sections/content.tsx | 3 + packages/api/src/router/widgets/index.ts | 2 + packages/api/src/router/widgets/notebook.ts | 45 + packages/definitions/src/widget.ts | 1 + packages/translation/src/lang/en.ts | 63 ++ packages/widgets/package.json | 15 + packages/widgets/src/definition.ts | 2 + packages/widgets/src/index.tsx | 2 + packages/widgets/src/notebook/component.tsx | 18 + .../widgets/src/notebook/default-content.ts | 132 +++ packages/widgets/src/notebook/index.ts | 30 + packages/widgets/src/notebook/notebook.tsx | 989 ++++++++++++++++++ pnpm-lock.yaml | 428 +++++--- 15 files changed, 1587 insertions(+), 148 deletions(-) create mode 100644 packages/api/src/router/widgets/notebook.ts create mode 100644 packages/widgets/src/notebook/component.tsx create mode 100644 packages/widgets/src/notebook/default-content.ts create mode 100644 packages/widgets/src/notebook/index.ts create mode 100644 packages/widgets/src/notebook/notebook.tsx diff --git a/apps/nextjs/package.json b/apps/nextjs/package.json index 83bc199ee..c1fd0cabe 100644 --- a/apps/nextjs/package.json +++ b/apps/nextjs/package.json @@ -37,9 +37,6 @@ "@tanstack/react-query": "^5.29.0", "@tanstack/react-query-devtools": "^5.29.0", "@tanstack/react-query-next-experimental": "5.29.0", - "@tiptap/extension-link": "^2.2.5", - "@tiptap/react": "^2.2.5", - "@tiptap/starter-kit": "^2.2.5", "@trpc/client": "11.0.0-rc.332", "@trpc/next": "next", "@trpc/react-query": "next", diff --git a/apps/nextjs/src/app/[locale]/widgets/[kind]/_content.tsx b/apps/nextjs/src/app/[locale]/widgets/[kind]/_content.tsx index 34e700c04..bb86b44c9 100644 --- a/apps/nextjs/src/app/[locale]/widgets/[kind]/_content.tsx +++ b/apps/nextjs/src/app/[locale]/widgets/[kind]/_content.tsx @@ -112,6 +112,8 @@ export const WidgetPreviewPageContent = ({ width={dimensions.width} height={dimensions.height} isEditMode={editMode} + boardId={undefined} + itemId={undefined} /> diff --git a/apps/nextjs/src/components/board/sections/content.tsx b/apps/nextjs/src/components/board/sections/content.tsx index bb6b7174e..a11192bdc 100644 --- a/apps/nextjs/src/components/board/sections/content.tsx +++ b/apps/nextjs/src/components/board/sections/content.tsx @@ -88,6 +88,7 @@ interface ItemProps { } const BoardItem = ({ item, ...dimensions }: ItemProps) => { + const board = useRequiredBoard(); const editMode = useAtomValue(editModeAtom); const serverData = useServerDataFor(item.id); const Comp = loadWidgetDynamic(item.kind); @@ -104,6 +105,8 @@ const BoardItem = ({ item, ...dimensions }: ItemProps) => { integrations={item.integrations} serverData={serverData?.data as never} isEditMode={editMode} + boardId={board.id} + itemId={item.id} {...dimensions} /> diff --git a/packages/api/src/router/widgets/index.ts b/packages/api/src/router/widgets/index.ts index 7b8595fdb..ecd39a0a8 100644 --- a/packages/api/src/router/widgets/index.ts +++ b/packages/api/src/router/widgets/index.ts @@ -1,6 +1,8 @@ import { createTRPCRouter } from "../../trpc"; +import { notebookRouter } from "./notebook"; import { weatherRouter } from "./weather"; export const widgetRouter = createTRPCRouter({ + notebook: notebookRouter, weather: weatherRouter, }); diff --git a/packages/api/src/router/widgets/notebook.ts b/packages/api/src/router/widgets/notebook.ts new file mode 100644 index 000000000..8fd369630 --- /dev/null +++ b/packages/api/src/router/widgets/notebook.ts @@ -0,0 +1,45 @@ +import { TRPCError } from "@trpc/server"; +import SuperJSON from "superjson"; + +import { eq } from "@homarr/db"; +import { items } from "@homarr/db/schema/sqlite"; +import { z } from "@homarr/validation"; + +import { createTRPCRouter, publicProcedure } from "../../trpc"; + +export const notebookRouter = createTRPCRouter({ + updateContent: publicProcedure + .input( + z.object({ + itemId: z.string(), + content: z.string(), + boardId: z.string(), + }), + ) + .mutation(async ({ ctx, input }) => { + const item = await ctx.db.query.items.findFirst({ + where: eq(items.id, input.itemId), + with: { + section: { + columns: { + boardId: true, + }, + }, + }, + }); + + if (!item || item.section.boardId !== input.boardId) { + throw new TRPCError({ + code: "NOT_FOUND", + message: "Specified item was not found", + }); + } + + const options = SuperJSON.parse<{ content: string }>(item.options); + options.content = input.content; + await ctx.db + .update(items) + .set({ options: SuperJSON.stringify(options) }) + .where(eq(items.id, input.itemId)); + }), +}); diff --git a/packages/definitions/src/widget.ts b/packages/definitions/src/widget.ts index 66186acfc..7cd6ac962 100644 --- a/packages/definitions/src/widget.ts +++ b/packages/definitions/src/widget.ts @@ -4,5 +4,6 @@ export const widgetKinds = [ "app", "iframe", "video", + "notebook", ] as const; export type WidgetKind = (typeof widgetKinds)[number]; diff --git a/packages/translation/src/lang/en.ts b/packages/translation/src/lang/en.ts index bd6963876..fd1c2f1b3 100644 --- a/packages/translation/src/lang/en.ts +++ b/packages/translation/src/lang/en.ts @@ -192,9 +192,11 @@ export default { common: { action: { add: "Add", + apply: "Apply", backToOverview: "Back to overview", create: "Create", edit: "Edit", + insert: "Insert", remove: "Remove", save: "Save", saveChanges: "Save changes", @@ -372,6 +374,67 @@ export default { }, }, }, + notebook: { + name: "Notebook", + description: "A simple notebook widget that supports markdown", + option: { + showToolbar: { + label: "Show the toolbar to help you write markdown", + }, + allowReadOnlyCheck: { + label: "Allow check in read only mode", + }, + content: { + label: "The content of the notebook", + }, + }, + controls: { + bold: "Bold", + italic: "Italic", + strikethrough: "Strikethrough", + underline: "Underline", + colorText: "Color text", + colorHighlight: "Colored highlight text", + code: "Code", + clear: "Clear formatting", + heading: "Heading {level}", + align: "Align text: {position}", + blockquote: "Blockquote", + horizontalLine: "Horizontal line", + bulletList: "Bullet list", + orderedList: "Ordered list", + checkList: "Check list", + increaseIndent: "Increase Indent", + decreaseIndent: "Decrease Indent", + link: "Link", + unlink: "Remove link", + image: "Embed Image", + addTable: "Add table", + deleteTable: "Delete Table", + colorCell: "Color Cell", + mergeCell: "Toggle cell merging", + addColumnLeft: "Add column before", + addColumnRight: "Add column after", + deleteColumn: "Delete column", + addRowTop: "Add row before", + addRowBelow: "Add row after", + deleteRow: "Delete row", + }, + align: { + left: "Left", + center: "Center", + right: "Right", + }, + popover: { + clearColor: "Clear color", + source: "Source", + widthPlaceholder: "Value in % or pixels", + columns: "Columns", + rows: "Rows", + width: "Width", + height: "Height", + }, + }, iframe: { name: "iFrame", description: diff --git a/packages/widgets/package.json b/packages/widgets/package.json index 5ae8e29f3..d88aa9fc4 100644 --- a/packages/widgets/package.json +++ b/packages/widgets/package.json @@ -45,6 +45,21 @@ "@homarr/translation": "workspace:^0.1.0", "@homarr/ui": "workspace:^0.1.0", "@homarr/validation": "workspace:^0.1.0", + "@tiptap/extension-link": "^2.2.5", + "@tiptap/react": "^2.2.5", + "@tiptap/starter-kit": "^2.2.5", + "@tiptap/extension-color": "2.2.5", + "@tiptap/extension-highlight": "2.2.5", + "@tiptap/extension-image": "2.2.5", + "@tiptap/extension-table": "2.2.5", + "@tiptap/extension-table-cell": "2.2.5", + "@tiptap/extension-table-header": "2.2.5", + "@tiptap/extension-table-row": "2.2.5", + "@tiptap/extension-task-item": "2.2.5", + "@tiptap/extension-task-list": "2.2.5", + "@tiptap/extension-text-align": "2.2.5", + "@tiptap/extension-text-style": "2.2.5", + "@tiptap/extension-underline": "2.2.5", "video.js": "^8.10.0" } } diff --git a/packages/widgets/src/definition.ts b/packages/widgets/src/definition.ts index a8a42d698..88732a102 100644 --- a/packages/widgets/src/definition.ts +++ b/packages/widgets/src/definition.ts @@ -105,6 +105,8 @@ export type WidgetComponentProps = WidgetProps & { serverData?: inferServerDataForKind; } & { + itemId: string | undefined; // undefined when in preview mode + boardId: string | undefined; // undefined when in preview mode isEditMode: boolean; width: number; height: number; diff --git a/packages/widgets/src/index.tsx b/packages/widgets/src/index.tsx index 2ccde0c45..dfa38b1ba 100644 --- a/packages/widgets/src/index.tsx +++ b/packages/widgets/src/index.tsx @@ -10,6 +10,7 @@ import * as clock from "./clock"; import type { WidgetComponentProps } from "./definition"; import * as iframe from "./iframe"; import type { WidgetImportRecord } from "./import"; +import * as notebook from "./notebook"; import * as video from "./video"; import * as weather from "./weather"; @@ -23,6 +24,7 @@ export const widgetImports = { clock, weather, app, + notebook, iframe, video, } satisfies WidgetImportRecord; diff --git a/packages/widgets/src/notebook/component.tsx b/packages/widgets/src/notebook/component.tsx new file mode 100644 index 000000000..45c230a75 --- /dev/null +++ b/packages/widgets/src/notebook/component.tsx @@ -0,0 +1,18 @@ +import dynamic from "next/dynamic"; + +import "@mantine/tiptap/styles.css"; + +import type { WidgetComponentProps } from "../definition"; + +const Notebook = dynamic( + () => import("./notebook").then((module) => module.Notebook), + { + ssr: false, + }, +); + +export default function NotebookWidget( + props: WidgetComponentProps<"notebook">, +) { + return ; +} diff --git a/packages/widgets/src/notebook/default-content.ts b/packages/widgets/src/notebook/default-content.ts new file mode 100644 index 000000000..da525c48d --- /dev/null +++ b/packages/widgets/src/notebook/default-content.ts @@ -0,0 +1,132 @@ +export const defaultContent = ` +

+ +

+

Welcome to Homarr's notebook widget

+

+ The notebook widget focuses on usability and is designed to be as simple as possible to bring a + familiar editing experience to regular users, be it markdown or office type editors. + It is based on Tiptap.dev + and supports most of its features: +

+ + + + + + + + + + + + + + + + +
+

General text formatting

+
+

Bold

+
+

Italic

+
+

Underline

+
+

Strike-through

+
+

Text alignment

+
+

Headings

+
+ + + + + + + + + + + +
+

Lists

+
+
    +
  1. +

    Ordered

    +
  2. +
+
+
    +
  • +

    Bullet

    +
  • +
+
+
    +
  • + +

    Check

    +
  • +
+
+ + + + + + + + + + + +
+

Coloring

+
+

Text coloring

+
+

highlighting

+
+

Table cells

+
+ + + + + + + + + + + +
+

Inserts

+
+

Links

+
+

Images

+
+

Tables

+
+
+
+

Widget options

+
    +
  • +

    Show the toolbar to help you write markdown:

    +

    The toolbar at the top that helps with controls, some not available in markdown.

    +
  • +
  • +

    Allow check in read only mode:

    +

    Check boxes usable outside of editing, also allows anonymous checks.

    +
  • +
+
` + .split("\n") + .join("") + .replaceAll(" ", ""); diff --git a/packages/widgets/src/notebook/index.ts b/packages/widgets/src/notebook/index.ts new file mode 100644 index 000000000..81f6ff0f8 --- /dev/null +++ b/packages/widgets/src/notebook/index.ts @@ -0,0 +1,30 @@ +import { IconNotes } from "@homarr/ui"; + +import { createWidgetDefinition } from "../definition"; +import { optionsBuilder } from "../options"; +import { defaultContent } from "./default-content"; + +export const { definition, componentLoader } = createWidgetDefinition( + "notebook", + { + icon: IconNotes, + options: optionsBuilder.from( + (factory) => ({ + showToolbar: factory.switch({ + defaultValue: true, + }), + allowReadOnlyCheck: factory.switch({ + defaultValue: true, + }), + content: factory.text({ + defaultValue: defaultContent, + }), + }), + { + content: { + shouldHide: () => true, // Hide the content option as it can be modified in the editor + }, + }, + ), + }, +).withDynamicImport(() => import("./component")); diff --git a/packages/widgets/src/notebook/notebook.tsx b/packages/widgets/src/notebook/notebook.tsx new file mode 100644 index 000000000..7e056e4aa --- /dev/null +++ b/packages/widgets/src/notebook/notebook.tsx @@ -0,0 +1,989 @@ +"use client"; + +import { useCallback, useEffect, useState } from "react"; +import { + ActionIcon, + Button, + ColorPicker, + ColorSwatch, + Group, + NumberInput, + Popover, + ScrollArea, + Stack, + TextInput, + useMantineColorScheme, + useMantineTheme, +} from "@mantine/core"; +import { useDisclosure } from "@mantine/hooks"; +import { + Link, + RichTextEditor, + useRichTextEditorContext, +} from "@mantine/tiptap"; +import { + IconCheck, + IconCircleOff, + IconColumnInsertLeft, + IconColumnInsertRight, + IconColumnRemove, + IconDeviceFloppy, + IconEdit, + IconHighlight, + IconIndentDecrease, + IconIndentIncrease, + IconLayoutGrid, + IconLetterA, + IconListCheck, + IconPhoto, + IconRowInsertBottom, + IconRowInsertTop, + IconRowRemove, + IconTableOff, + IconTablePlus, + IconX, +} from "@tabler/icons-react"; +import { Color } from "@tiptap/extension-color"; +import Highlight from "@tiptap/extension-highlight"; +import Image from "@tiptap/extension-image"; +import Table from "@tiptap/extension-table"; +import TableCell from "@tiptap/extension-table-cell"; +import TableHeader from "@tiptap/extension-table-header"; +import TableRow from "@tiptap/extension-table-row"; +import TaskItem from "@tiptap/extension-task-item"; +import TaskList from "@tiptap/extension-task-list"; +import TextAlign from "@tiptap/extension-text-align"; +import TextStyle from "@tiptap/extension-text-style"; +import Underline from "@tiptap/extension-underline"; +import type { Editor } from "@tiptap/react"; +import { BubbleMenu, useEditor } from "@tiptap/react"; +import StarterKit from "@tiptap/starter-kit"; +import type { Node } from "prosemirror-model"; + +import { clientApi } from "@homarr/api/client"; +import { useForm } from "@homarr/form"; +import type { TranslationObject } from "@homarr/translation"; +import { useI18n, useScopedI18n } from "@homarr/translation/client"; +import type { TablerIcon } from "@homarr/ui"; + +import type { WidgetComponentProps } from "../definition"; + +const iconProps = { + size: "1.25rem", + stroke: 1.5, +}; + +const controlIconProps = { + size: "1rem", + stroke: 1.5, +}; + +export function Notebook({ + options, + isEditMode, + boardId, + itemId, +}: WidgetComponentProps<"notebook">) { + const [content, setContent] = useState(options.content); + const [toSaveContent, setToSaveContent] = useState(content); + + // TODO: Add check for user permissions + const enabled = !isEditMode; + const [isEditing, setIsEditing] = useState(false); + + const { primaryColor } = useMantineTheme(); + const { colorScheme } = useMantineColorScheme(); + + const { mutateAsync } = clientApi.widget.notebook.updateContent.useMutation(); + + const tControls = useScopedI18n("widget.notebook.controls"); + const t = useI18n(); + + const editor = useEditor( + { + extensions: [ + Color, + Highlight.configure({ multicolor: true }), + Image.extend({ + addAttributes() { + return { + ...this.parent?.(), + width: { default: null }, + }; + }, + }).configure({ inline: true }), + Link.configure({ + openOnClick: true, + validate(url) { + return /^https?:\/\//.test(url); + }, + }).extend({ + addAttributes() { + return { + ...this.parent?.(), + target: { default: null }, + }; + }, + }), + StarterKit, + Table.configure({ + resizable: true, + lastColumnResizable: false, + }), + TableCell.extend({ + addAttributes() { + return { + ...this.parent?.(), + backgroundColor: { + default: undefined, + renderHTML: (attributes) => ({ + style: attributes.backgroundColor + ? `background-color: ${attributes.backgroundColor}` + : undefined, + }), + parseHTML: (element) => + element.style.backgroundColor || undefined, + }, + }; + }, + }), + TableHeader, + TableRow, + TaskItem.configure({ + nested: true, + onReadOnlyChecked: (node, checked) => { + if (options.allowReadOnlyCheck && enabled) { + const event = new CustomEvent("onReadOnlyCheck", { + detail: { node, checked }, + }); + dispatchEvent(event); + return true; + } + return false; + }, + }), + TaskList.configure({ itemTypeName: "taskItem" }), + TextAlign.configure({ types: ["heading", "paragraph"] }), + TextStyle, + Underline, + ], + content, + onUpdate: ({ editor }) => { + setContent(editor.getHTML()); + }, + onCreate: ({ editor }) => { + editor.setEditable(false); + }, + }, + [toSaveContent], + ); + + const handleOnReadOnlyCheck = ( + event: CustomEventInit<{ node: Node; checked: boolean }>, + ) => { + if (!options.allowReadOnlyCheck) return; + if (!editor) return; + + editor.state.doc.descendants((subnode, pos) => { + if (!event.detail) return; + if (!subnode.eq(event.detail.node)) return; + + if (subnode.eq(event.detail.node)) { + const { tr } = editor.state; + tr.setNodeMarkup(pos, undefined, { + ...event.detail.node.attrs, + checked: event.detail.checked, + }); + editor.view.dispatch(tr); + setContent(editor.getHTML()); + handleContentUpdate(editor.getHTML()); + } + }); + }; + + addEventListener("onReadOnlyCheck", handleOnReadOnlyCheck); + + const handleEditToggleCallback = (previous: boolean) => { + const current = !previous; + if (!editor) return current; + editor.setEditable(current); + + handleContentUpdate(content); + + return current; + }; + + const handleEditCancelCallback = () => { + if (!editor) return false; + editor.setEditable(false); + + setContent(toSaveContent); + editor.commands.setContent(toSaveContent); + + return false; + }; + + const handleEditCancel = useCallback(() => { + setIsEditing(handleEditCancelCallback); + }, [setIsEditing, handleEditCancelCallback]); + + const handleContentUpdate = (contentUpdate: string) => { + setToSaveContent(contentUpdate); + // This is not available in preview mode + if (boardId && itemId) { + void mutateAsync({ boardId, itemId, content: contentUpdate }); + } + }; + + const handleEditToggle = useCallback(() => { + setIsEditing(handleEditToggleCallback); + }, [setIsEditing, handleEditToggleCallback]); + + return ( + <> + ({ + root: { + "& .ProseMirror": { + padding: "0 !important", + }, + backgroundColor: + colorScheme === "dark" ? theme.colors.dark[6] : "white", + border: "none", + borderRadius: "0.5rem", + display: "flex", + flexDirection: "column", + }, + toolbar: { + backgroundColor: "transparent", + padding: "0.5rem", + }, + content: { + backgroundColor: "transparent", + padding: "0.5rem", + }, + })} + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {(editor?.isActive("taskList") || + editor?.isActive("bulletList") || + editor?.isActive("orderedList")) && ( + <> + + + + )} + + + + + + + + + + + {editor?.isActive("table") && ( + <> + + + + + + + + + + )} + + + {editor && ( + + + + + + + + )} + + + + + + {enabled && ( + <> + + {isEditing ? ( + + ) : ( + + )} + + {isEditing && ( + + + + )} + + )} + + ); +} + +function TextHighlightControl() { + const tControls = useScopedI18n("widget.notebook.controls"); + const { editor } = useRichTextEditorContext(); + const defaultColor = "transparent"; + + const getCurrent = useCallback(() => { + return editor?.getAttributes("highlight").color as string | undefined; + }, [editor]); + + const update = useCallback( + (value: string) => { + if (value === defaultColor) { + editor?.chain().focus().unsetHighlight().run(); + return; + } + editor?.chain().focus().setHighlight({ color: value }).run(); + }, + [editor, defaultColor], + ); + + return ( + + ); +} + +function TextColorControl() { + const tControls = useScopedI18n("widget.notebook.controls"); + const { editor } = useRichTextEditorContext(); + const { black, colors } = useMantineTheme(); + const { colorScheme } = useMantineColorScheme(); + const defaultColor = colorScheme === "dark" ? colors.dark[0] : black; + + const getCurrent = useCallback(() => { + return editor?.getAttributes("textStyle").color as string | undefined; + }, [editor]); + + const update = useCallback( + (value: string) => { + if (value === defaultColor) { + editor?.chain().focus().unsetColor().run(); + return; + } + editor?.chain().focus().setColor(value).run(); + }, + [editor, defaultColor], + ); + + return ( + + ); +} + +function ColorCellControl() { + const tControls = useScopedI18n("widget.notebook.controls"); + const { editor } = useRichTextEditorContext(); + + const getCurrent = useCallback(() => { + return editor?.getAttributes("tableCell").backgroundColor as + | string + | undefined; + }, [editor]); + + const update = useCallback( + (value: string) => { + editor?.chain().focus().setCellAttribute("backgroundColor", value).run(); + }, + [editor], + ); + + return ( + + ); +} + +interface ColorControlProps { + defaultColor: string; + getCurrent: () => string | undefined; + update: (value: string) => void; + icon: TablerIcon; + ariaLabel: string; +} + +const ColorControl = ({ + defaultColor, + getCurrent, + update, + icon: Icon, + ariaLabel, +}: ColorControlProps) => { + const { editor } = useRichTextEditorContext(); + const [color, setColor] = useState(defaultColor); + const { colors, white } = useMantineTheme(); + const { colorScheme } = useMantineColorScheme(); + const [opened, { close, toggle }] = useDisclosure(false); + const t = useI18n(); + + const palette = [ + "#000000", + colors.dark[9], + colors.dark[6], + colors.dark[3], + colors.dark[0], + "#FFFFFF", + colors.red[9], + colors.pink[7], + colors.grape[8], + colors.violet[9], + colors.indigo[9], + colors.blue[5], + colors.green[6], + "#09D630", + colors.lime[5], + colors.yellow[5], + "#EB8415", + colors.orange[9], + ]; + + const onSelection = useCallback(() => { + setColor(getCurrent() ?? defaultColor); + }, [getCurrent, defaultColor, setColor]); + + useEffect(() => { + editor?.on("selectionUpdate", onSelection); + + return () => { + editor?.off("selectionUpdate", onSelection); + }; + }); + + const handleApplyColor = useCallback(() => { + update(color); + close(); + }, [color, update, close]); + + const handleClearColor = useCallback(() => { + update(defaultColor); + setColor(defaultColor); + close(); + }, [update, setColor, close, defaultColor]); + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +function EmbedImage() { + const tControls = useScopedI18n("widget.notebook.controls"); + const t = useI18n(); + const { editor } = useRichTextEditorContext(); + const { colors, white } = useMantineTheme(); + const { colorScheme } = useMantineColorScheme(); + const [opened, { open, close, toggle }] = useDisclosure(false); + const form = useForm({ + initialValues: { + src: (editor?.getAttributes("image").src as string | undefined) ?? "", + width: (editor?.getAttributes("image").width as string | undefined) ?? "", + }, + }); + + const handleOpen = useCallback(() => { + form.reset(); + open(); + }, [form, open]); + + const handleSubmit = useCallback( + (values: { src: string; width: string }) => { + editor?.commands.insertContent({ + type: "paragraph", + content: [ + { + type: "image", + attrs: values, + }, + ], + }); + close(); + }, + [editor, close], + ); + + return ( + + + + + + + +
+ + + + + +
+
+
+ ); +} + +function TaskListToggle() { + const { editor } = useRichTextEditorContext(); + const tControls = useScopedI18n("widget.notebook.controls"); + const handleToggleTaskList = useCallback(() => { + editor?.chain().focus().toggleTaskList().run(); + }, [editor]); + + return ( + + + + ); +} + +function ListIndentIncrease() { + const { editor } = useRichTextEditorContext(); + const [itemType, setItemType] = useState("listItem"); + const tControls = useScopedI18n("widget.notebook.controls"); + const handleIncreaseIndent = useCallback(() => { + editor?.chain().focus().sinkListItem(itemType).run(); + }, [editor, itemType]); + + editor?.on("selectionUpdate", ({ editor }) => { + setItemType(editor?.isActive("taskItem") ? "taskItem" : "listItem"); + }); + + return ( + + + + ); +} + +function ListIndentDecrease() { + const { editor } = useRichTextEditorContext(); + const [itemType, setItemType] = useState("listItem"); + const tControls = useScopedI18n("widget.notebook.controls"); + + const handleDecreaseIndent = useCallback(() => { + editor?.chain().focus().liftListItem(itemType).run(); + }, [editor, itemType]); + + editor?.on("selectionUpdate", ({ editor }) => { + setItemType(editor?.isActive("taskItem") ? "taskItem" : "listItem"); + }); + + return ( + + + + ); +} + +const handleAddColumnBefore = (editor: Editor) => { + editor.commands.addColumnBefore(); +}; + +const TableAddColumnBefore = () => ( + +); + +const handleAddColumnAfter = (editor: Editor) => { + editor.commands.addColumnAfter(); +}; + +const TableAddColumnAfter = () => ( + +); + +const handleRemoveColumn = (editor: Editor) => { + editor.commands.deleteColumn(); +}; + +const TableRemoveColumn = () => ( + +); + +const handleAddRowBefore = (editor: Editor) => { + editor.commands.addRowBefore(); +}; + +const TableAddRowBefore = () => ( + +); + +const handleAddRowAfter = (editor: Editor) => { + editor.commands.addRowAfter(); +}; + +const TableAddRowAfter = () => ( + +); + +const handleRemoveRow = (editor: Editor) => { + editor.commands.deleteRow(); +}; + +const TableRemoveRow = () => ( + +); + +interface TableControlProps { + title: Exclude< + keyof TranslationObject["widget"]["notebook"]["controls"], + "align" | "heading" + >; + onClick: (editor: Editor) => void; + icon: TablerIcon; +} + +const TableControl = ({ title, onClick, icon: Icon }: TableControlProps) => { + const { editor } = useRichTextEditorContext(); + const tControls = useScopedI18n("widget.notebook.controls"); + const handleControlClick = useCallback(() => { + if (!editor) return; + onClick(editor); + }, [editor, onClick]); + + return ( + + + + ); +}; + +function TableToggleMerge() { + const { editor } = useRichTextEditorContext(); + const tControls = useScopedI18n("widget.notebook.controls"); + const handleToggleMerge = useCallback(() => { + editor?.commands.mergeOrSplit(); + }, [editor]); + + return ( + 1} + > + + {/* No existing icon from tabler, taken from https://icon-sets.iconify.design/fluent/table-cells-merge-24-regular/ */} + + + + ); +} + +function TableToggle() { + const { editor } = useRichTextEditorContext(); + const isActive = editor?.isActive("table"); + + const { colors, white } = useMantineTheme(); + const { colorScheme } = useMantineColorScheme(); + + const [opened, { open, close, toggle }] = useDisclosure(false); + const t = useI18n(); + const tControls = useScopedI18n("widget.notebook.controls"); + const form = useForm({ + initialValues: { + cols: 3, + rows: 3, + }, + }); + + const handleOpen = useCallback(() => { + form.reset(); + open(); + }, [form, open]); + + const handleSubmit = useCallback( + (values: { rows: number; cols: number }) => { + editor?.commands.insertTable({ ...values, withHeaderRow: false }); + close(); + }, + [editor, close], + ); + + const handleControlClick = useCallback(() => { + if (isActive) { + editor?.commands.deleteTable(); + } else { + toggle(); + } + }, [isActive, editor, toggle]); + + return ( + + + + {isActive ? ( + + ) : ( + + )} + + + +
+ + + + + +
+
+
+ ); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 86d4b5467..f45a26e22 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -106,7 +106,7 @@ importers: version: 7.7.1(@mantine/core@7.7.1)(@mantine/hooks@7.7.1)(react-dom@18.2.0)(react@18.2.0) '@mantine/tiptap': specifier: ^7.7.1 - version: 7.7.1(@mantine/core@7.7.1)(@mantine/hooks@7.7.1)(@tiptap/extension-link@2.2.5)(@tiptap/react@2.2.5)(react-dom@18.2.0)(react@18.2.0) + version: 7.7.1(@mantine/core@7.7.1)(@mantine/hooks@7.7.1)(@tiptap/extension-link@2.2.6)(@tiptap/react@2.2.6)(react-dom@18.2.0)(react@18.2.0) '@t3-oss/env-nextjs': specifier: ^0.9.2 version: 0.9.2(typescript@5.4.5)(zod@3.22.4) @@ -119,15 +119,6 @@ importers: '@tanstack/react-query-next-experimental': specifier: 5.29.0 version: 5.29.0(@tanstack/react-query@5.29.0)(next@14.1.4)(react@18.2.0) - '@tiptap/extension-link': - specifier: ^2.2.5 - version: 2.2.5(@tiptap/core@2.2.5)(@tiptap/pm@2.2.4) - '@tiptap/react': - specifier: ^2.2.5 - version: 2.2.5(@tiptap/core@2.2.5)(@tiptap/pm@2.2.4)(react-dom@18.2.0)(react@18.2.0) - '@tiptap/starter-kit': - specifier: ^2.2.5 - version: 2.2.5(@tiptap/pm@2.2.4) '@trpc/client': specifier: 11.0.0-rc.332 version: 11.0.0-rc.332(@trpc/server@11.0.0-next-beta.289) @@ -160,7 +151,7 @@ importers: version: 16.4.5 jotai: specifier: ^2.8.0 - version: 2.8.0(@types/react@18.2.76)(react@18.2.0) + version: 2.8.0(@types/react@18.2.78)(react@18.2.0) next: specifier: ^14.1.4 version: 14.1.4(@babel/core@7.23.9)(react-dom@18.2.0)(react@18.2.0)(sass@1.74.1) @@ -200,7 +191,7 @@ importers: version: 20.12.7 '@types/react': specifier: ^18.2.76 - version: 18.2.76 + version: 18.2.78 '@types/react-dom': specifier: ^18.2.25 version: 18.2.25 @@ -723,7 +714,7 @@ importers: dependencies: '@mantine/core': specifier: ^7.7.1 - version: 7.7.1(@mantine/hooks@7.7.1)(@types/react@18.2.76)(react-dom@18.2.0)(react@18.2.0) + version: 7.7.1(@mantine/hooks@7.7.1)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) '@mantine/dates': specifier: ^7.7.1 version: 7.7.1(@mantine/core@7.7.1)(@mantine/hooks@7.7.1)(dayjs@1.11.10)(react-dom@18.2.0)(react@18.2.0) @@ -813,6 +804,51 @@ importers: '@homarr/validation': specifier: workspace:^0.1.0 version: link:../validation + '@tiptap/extension-color': + specifier: 2.2.5 + version: 2.2.5(@tiptap/core@2.2.6)(@tiptap/extension-text-style@2.2.5) + '@tiptap/extension-highlight': + specifier: 2.2.5 + version: 2.2.5(@tiptap/core@2.2.6) + '@tiptap/extension-image': + specifier: 2.2.5 + version: 2.2.5(@tiptap/core@2.2.6) + '@tiptap/extension-link': + specifier: ^2.2.5 + version: 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4) + '@tiptap/extension-table': + specifier: 2.2.5 + version: 2.2.5(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4) + '@tiptap/extension-table-cell': + specifier: 2.2.5 + version: 2.2.5(@tiptap/core@2.2.6) + '@tiptap/extension-table-header': + specifier: 2.2.5 + version: 2.2.5(@tiptap/core@2.2.6) + '@tiptap/extension-table-row': + specifier: 2.2.5 + version: 2.2.5(@tiptap/core@2.2.6) + '@tiptap/extension-task-item': + specifier: 2.2.5 + version: 2.2.5(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4) + '@tiptap/extension-task-list': + specifier: 2.2.5 + version: 2.2.5(@tiptap/core@2.2.6) + '@tiptap/extension-text-align': + specifier: 2.2.5 + version: 2.2.5(@tiptap/core@2.2.6) + '@tiptap/extension-text-style': + specifier: 2.2.5 + version: 2.2.5(@tiptap/core@2.2.6) + '@tiptap/extension-underline': + specifier: 2.2.5 + version: 2.2.5(@tiptap/core@2.2.6) + '@tiptap/react': + specifier: ^2.2.5 + version: 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4)(react-dom@18.2.0)(react@18.2.0) + '@tiptap/starter-kit': + specifier: ^2.2.5 + version: 2.2.6(@tiptap/pm@2.2.4) video.js: specifier: ^8.10.0 version: 8.10.0 @@ -1069,7 +1105,7 @@ packages: resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.23.9 /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.9): resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} @@ -1107,7 +1143,7 @@ packages: resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.24.0 + '@babel/types': 7.23.9 /@babel/helper-split-export-declaration@7.22.6: resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} @@ -2088,7 +2124,7 @@ packages: chroma-js: 2.4.2 dev: false - /@mantine/core@7.7.1(@mantine/hooks@7.7.1)(@types/react@18.2.76)(react-dom@18.2.0)(react@18.2.0): + /@mantine/core@7.7.1(@mantine/hooks@7.7.1)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-SdPzjvqvEK7uHFuVD3a8w3OZyQVoCwIXLSUfOtRNouDMQgsq6Ac7QjKXBBOk3wNweOWFVOU1vATLHobSmow0lQ==} peerDependencies: '@mantine/hooks': 7.7.1 @@ -2101,8 +2137,8 @@ packages: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) react-number-format: 5.3.1(react-dom@18.2.0)(react@18.2.0) - react-remove-scroll: 2.5.7(@types/react@18.2.76)(react@18.2.0) - react-textarea-autosize: 8.5.3(@types/react@18.2.76)(react@18.2.0) + react-remove-scroll: 2.5.7(@types/react@18.2.78)(react@18.2.0) + react-textarea-autosize: 8.5.3(@types/react@18.2.78)(react@18.2.0) type-fest: 4.12.0 transitivePeerDependencies: - '@types/react' @@ -2117,7 +2153,7 @@ packages: react: ^18.2.0 react-dom: ^18.2.0 dependencies: - '@mantine/core': 7.7.1(@mantine/hooks@7.7.1)(@types/react@18.2.76)(react-dom@18.2.0)(react@18.2.0) + '@mantine/core': 7.7.1(@mantine/hooks@7.7.1)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) '@mantine/hooks': 7.7.1(react@18.2.0) clsx: 2.1.0 dayjs: 1.11.10 @@ -2151,7 +2187,7 @@ packages: react: ^18.2.0 react-dom: ^18.2.0 dependencies: - '@mantine/core': 7.7.1(@mantine/hooks@7.7.1)(@types/react@18.2.76)(react-dom@18.2.0)(react@18.2.0) + '@mantine/core': 7.7.1(@mantine/hooks@7.7.1)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) '@mantine/hooks': 7.7.1(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) @@ -2165,7 +2201,7 @@ packages: react: ^18.2.0 react-dom: ^18.2.0 dependencies: - '@mantine/core': 7.7.1(@mantine/hooks@7.7.1)(@types/react@18.2.76)(react-dom@18.2.0)(react@18.2.0) + '@mantine/core': 7.7.1(@mantine/hooks@7.7.1)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) '@mantine/hooks': 7.7.1(react@18.2.0) '@mantine/store': 7.7.1(react@18.2.0) react: 18.2.0 @@ -2181,7 +2217,7 @@ packages: react: ^18.2.0 react-dom: ^18.2.0 dependencies: - '@mantine/core': 7.7.1(@mantine/hooks@7.7.1)(@types/react@18.2.76)(react-dom@18.2.0)(react@18.2.0) + '@mantine/core': 7.7.1(@mantine/hooks@7.7.1)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) '@mantine/hooks': 7.7.1(react@18.2.0) '@mantine/store': 7.7.1(react@18.2.0) react: 18.2.0 @@ -2196,7 +2232,7 @@ packages: react: 18.2.0 dev: false - /@mantine/tiptap@7.7.1(@mantine/core@7.7.1)(@mantine/hooks@7.7.1)(@tiptap/extension-link@2.2.5)(@tiptap/react@2.2.5)(react-dom@18.2.0)(react@18.2.0): + /@mantine/tiptap@7.7.1(@mantine/core@7.7.1)(@mantine/hooks@7.7.1)(@tiptap/extension-link@2.2.6)(@tiptap/react@2.2.6)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-MWX4+0UrP3tgyUeWVQdr0jH91j4VsviDPJF62QH1nxDSaObrcU7xkDU2mudPbSNeb07aKDG8ifIMBkcB/r6p9g==} peerDependencies: '@mantine/core': 7.7.1 @@ -2206,10 +2242,10 @@ packages: react: ^18.2.0 react-dom: ^18.2.0 dependencies: - '@mantine/core': 7.7.1(@mantine/hooks@7.7.1)(@types/react@18.2.76)(react-dom@18.2.0)(react@18.2.0) + '@mantine/core': 7.7.1(@mantine/hooks@7.7.1)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) '@mantine/hooks': 7.7.1(react@18.2.0) - '@tiptap/extension-link': 2.2.5(@tiptap/core@2.2.5)(@tiptap/pm@2.2.4) - '@tiptap/react': 2.2.5(@tiptap/core@2.2.5)(@tiptap/pm@2.2.4)(react-dom@18.2.0)(react@18.2.0) + '@tiptap/extension-link': 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4) + '@tiptap/react': 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4)(react-dom@18.2.0)(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false @@ -2653,199 +2689,301 @@ packages: react-error-boundary: 3.1.4(react@17.0.2) dev: true - /@tiptap/core@2.2.5(@tiptap/pm@2.2.4): - resolution: {integrity: sha512-BgF6tiXhwph0Ig16ZNppMmg30t22Z/yjZ+KnS8EALdJere3ACNw8THz9q/8iQqBWjjBOHUvhrQOgER4BJxfmGA==} + /@tiptap/core@2.2.6(@tiptap/pm@2.2.4): + resolution: {integrity: sha512-v7S7RhQhTXQo9KSk2jM/jJlTd3clU2FsJA3Omjz7GbgYtPSy67qSiaTbH/tWq12GzDHbKymx+oQnKmyx+yPucA==} peerDependencies: '@tiptap/pm': ^2.0.0 dependencies: '@tiptap/pm': 2.2.4 dev: false - /@tiptap/extension-blockquote@2.2.5(@tiptap/core@2.2.5): - resolution: {integrity: sha512-mlCNV+kAK5d2vjEmQQZ54br9Cn48VXz3ZwpQyeqZ9z6I4Rl2nqkeWgoIIX8FBT2/8ddcpHuSJnAkAHxuJ0PQrg==} + /@tiptap/extension-blockquote@2.2.6(@tiptap/core@2.2.6): + resolution: {integrity: sha512-Qoq4Tl4wyEGfuBrMFth5hWP1SroJtgDYPnyzAZeLiGzF3Yxtu7FFqjGtD1/Bos9ftnFVCAj+nIXnuKsM1YUaGg==} peerDependencies: '@tiptap/core': ^2.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) dev: false - /@tiptap/extension-bold@2.2.5(@tiptap/core@2.2.5): - resolution: {integrity: sha512-d33+v7430xpuV5B3qyTzDj8n43wc1lsqmCQKp8niW35N8JtEO+AjkZ+Pg9CZqYYE58CwSduCXm1vnCYIVezWag==} + /@tiptap/extension-bold@2.2.6(@tiptap/core@2.2.6): + resolution: {integrity: sha512-PI/jNH7rmi6hBvWy/z+3KUTYqeaDXBUjidM74gWP6OLV28HTJ5SkIPCriYe4u2j2Wc/nk3gPxs4/hPOAu/YiXA==} peerDependencies: '@tiptap/core': ^2.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) dev: false - /@tiptap/extension-bubble-menu@2.2.5(@tiptap/core@2.2.5)(@tiptap/pm@2.2.4): - resolution: {integrity: sha512-JFeFaUyin93SL/DZZqfoz/DWvMxtqcZLnPPd60hZBczxcLghRZCyDH5nqVHJybrkcs/xNNPennJ1Hqft+WEHbA==} + /@tiptap/extension-bubble-menu@2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4): + resolution: {integrity: sha512-nRWxbgkInhdGUL+e6iISgALcWh8A1PxeVB66w7yYZHS/WoZO0DXdXYT/BWb/XmEJ8r6B4c9SDZRklCiXT8dSXw==} peerDependencies: '@tiptap/core': ^2.0.0 '@tiptap/pm': ^2.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) '@tiptap/pm': 2.2.4 tippy.js: 6.3.7 dev: false - /@tiptap/extension-bullet-list@2.2.5(@tiptap/core@2.2.5): - resolution: {integrity: sha512-Jt4TGV66jqnWyF9egKuA596ehKbT1NN6Vnzle9Dn/hS20SyZxmPhCu13FE1MbajEDg8mn3rAYcWQ5A8+jrQr/Q==} + /@tiptap/extension-bullet-list@2.2.6(@tiptap/core@2.2.6): + resolution: {integrity: sha512-bSrmYlWfj/bXXoBMVB+gCTlsficVVzWi1jcAjAn+qNAENkhampmlFIUG4DiKGYtn18ZoTbyLgQGDMCO3SBdeDQ==} peerDependencies: '@tiptap/core': ^2.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) dev: false - /@tiptap/extension-code-block@2.2.5(@tiptap/core@2.2.5)(@tiptap/pm@2.2.4): - resolution: {integrity: sha512-EMOSdP+wqvXmrIO7wkzPCGy4jwgSPY42HR2xXg5jd0oqjYM4ZexWJ6cpdVwcUQ51Zjc8EDwJrmFAsbawnyk+fA==} + /@tiptap/extension-code-block@2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4): + resolution: {integrity: sha512-834gVybNyI4nY6NINqnOosFPa4WKylMQTraEY2KhUH2XU1mh0Ni7EgyK10dfZvOUj90OjaxZtXkyZrZ89RTxog==} peerDependencies: '@tiptap/core': ^2.0.0 '@tiptap/pm': ^2.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) '@tiptap/pm': 2.2.4 dev: false - /@tiptap/extension-code@2.2.5(@tiptap/core@2.2.5): - resolution: {integrity: sha512-BctyvPTzbY6FZLrBMVdauBgwoYDaUos1STGqHDV8v9nCDNypqw8OVVepF1SRhp2ggVM8cRxywsN0QC0AyDuO7Q==} + /@tiptap/extension-code@2.2.6(@tiptap/core@2.2.6): + resolution: {integrity: sha512-UGsSFvVWrWWWQFU4atk+b/qeewTLadOZG/BHZXQDloyP5eJ1SkgUVy9nv3y2cT8QWRbvF6sxkV+SdFoWnvaG3Q==} peerDependencies: '@tiptap/core': ^2.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) dev: false - /@tiptap/extension-document@2.2.5(@tiptap/core@2.2.5): - resolution: {integrity: sha512-05JLDpFUK0M9Oz6fxDv7tmZGRbQFldP8VDrHEh3uCLl8GUZSOplmwlnQ7HLgGo3iCFUX7o1O2OeEJRRQBCzqlA==} + /@tiptap/extension-color@2.2.5(@tiptap/core@2.2.6)(@tiptap/extension-text-style@2.2.5): + resolution: {integrity: sha512-lEqqnHMWDBbwwKcIKPS0QqmXyO+a1v2yAmzGhvyhQdMdcbcfXSslrrOAXJ5fGyU8Hl9TFtBd8Atet0YA/8PuHQ==} + peerDependencies: + '@tiptap/core': ^2.0.0 + '@tiptap/extension-text-style': ^2.0.0 + dependencies: + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) + '@tiptap/extension-text-style': 2.2.5(@tiptap/core@2.2.6) + dev: false + + /@tiptap/extension-document@2.2.6(@tiptap/core@2.2.6): + resolution: {integrity: sha512-yT9m5Oo9U/xAypcylaLiDE8qmVd3SCZSc8s5lqyC1OW+psb1oC0d14+TgKetO2s8K2wAbW2DxYG3yoxWffGYsQ==} peerDependencies: '@tiptap/core': ^2.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) dev: false - /@tiptap/extension-dropcursor@2.2.5(@tiptap/core@2.2.5)(@tiptap/pm@2.2.4): - resolution: {integrity: sha512-GRSYNtEKGekpr3kb/5ci2eR2hN1WqORMUqd8wxBBi5AF1cHyXLbvy08bYe2enu3M1+MA0sW5J7Jh5j7D0HY49w==} + /@tiptap/extension-dropcursor@2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4): + resolution: {integrity: sha512-mCeIbbfe4rl8CuxVQvT7iYSKGVX/ls1LOwALwlHJz5Uw5l3VknAJdjEmHt6hNFdHu162JivL02Il0QYQ8BZwvA==} peerDependencies: '@tiptap/core': ^2.0.0 '@tiptap/pm': ^2.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) '@tiptap/pm': 2.2.4 dev: false - /@tiptap/extension-floating-menu@2.2.5(@tiptap/core@2.2.5)(@tiptap/pm@2.2.4): - resolution: {integrity: sha512-/PfS9QHEHQsoV6ZqolJ6Rq6ZC6drD7IPJRgywuJi0zTTH0YCbLmJKrc3K2Qj69xbfwcANL8gBdsexv5zOjKAXA==} + /@tiptap/extension-floating-menu@2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4): + resolution: {integrity: sha512-6ONKC6Dx8zCc5YffXpnQ9FxGRoUp5Jm9mOO3losgiDFhdJqaO7SCk1ziOiD7enoWqIc2shZh8ADnqttCfnFVFQ==} peerDependencies: '@tiptap/core': ^2.0.0 '@tiptap/pm': ^2.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) '@tiptap/pm': 2.2.4 tippy.js: 6.3.7 dev: false - /@tiptap/extension-gapcursor@2.2.5(@tiptap/core@2.2.5)(@tiptap/pm@2.2.4): - resolution: {integrity: sha512-zKAg7KR1BWOSL8LopIb1jnw0PRapxLNJyC3OUSbl6snlxRy+ER5hbv8bHJDznDCC3PjcNemYRUewTTrggHucsA==} + /@tiptap/extension-gapcursor@2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4): + resolution: {integrity: sha512-HDYu+FmL9V+khsiT5904Dy2qG6KrAvnXEjZk1+vVul0TabnQvl2rqHjTxmev3P1rOYTgePmaWXazxAWFIvbMBQ==} peerDependencies: '@tiptap/core': ^2.0.0 '@tiptap/pm': ^2.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) '@tiptap/pm': 2.2.4 dev: false - /@tiptap/extension-hard-break@2.2.5(@tiptap/core@2.2.5): - resolution: {integrity: sha512-oySgYvu4RSrwc7/xPVxpqa4NLnVLUgaoOFE/wU0NWtgwh2wptZdanT2bacsBJTqIRMi6HCZbMzr88qbxk0cWgA==} + /@tiptap/extension-hard-break@2.2.6(@tiptap/core@2.2.6): + resolution: {integrity: sha512-gwavC76sn26XQLyDaDtf28KIcbhMYPP+C5pkbRvAhVSckQB3Ebz3GRttVbm/jp+Uifp3bmoQEzISGCONEdKQoQ==} peerDependencies: '@tiptap/core': ^2.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) dev: false - /@tiptap/extension-heading@2.2.5(@tiptap/core@2.2.5): - resolution: {integrity: sha512-gEihkfeAi5aOZ+WUd/ZLq6D6KopZr8e/EPWD/3eeeI/RyAGBwT2+ZnDTOZSL7/snbp4n/1TCFYhh9vjNSnCDkw==} + /@tiptap/extension-heading@2.2.6(@tiptap/core@2.2.6): + resolution: {integrity: sha512-XOmY+uezm42xSO1ero2bRBMdQxWytpxLJS+2shK0QogZ3sDplnfWfP5KV9Z2juXjTdPgPWG0ZaHzIIaLquEcfA==} peerDependencies: '@tiptap/core': ^2.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) dev: false - /@tiptap/extension-history@2.2.5(@tiptap/core@2.2.5)(@tiptap/pm@2.2.4): - resolution: {integrity: sha512-/KHFlQApljA2L/CX0qWhT+hPQeI2a8M4m5VynmTYVbQ4y/T2bVnys0k9zNuYwQxeqVSfeSqCZAIkMjen2fDzYQ==} + /@tiptap/extension-highlight@2.2.5(@tiptap/core@2.2.6): + resolution: {integrity: sha512-Ji8F9fkMGjL7723B4dymQKq+P5VBQ/PJMsTrHlbbIm3ZBWxRc43VHzT3bQJ4Qm66mO4YfpEC6eA5JDq44CrfWA==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) + dev: false + + /@tiptap/extension-history@2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4): + resolution: {integrity: sha512-c2Aeozc+pHcpqghLjXRX/tGU/C+Gp6hApUWPXdhZw5Y/ARj6ZRwx2/ym2K8MOrJ36/W7gc7Xyxd9ZbG7m7pcjA==} peerDependencies: '@tiptap/core': ^2.0.0 '@tiptap/pm': ^2.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) '@tiptap/pm': 2.2.4 dev: false - /@tiptap/extension-horizontal-rule@2.2.5(@tiptap/core@2.2.5)(@tiptap/pm@2.2.4): - resolution: {integrity: sha512-M0eGP5OsMj3JcfAL122XAmgMW5EYQBjKBNkkhihnSZb7r6/cQuqG4F89YZCOigiXVNW5r4KkYbL+ykSm/lFD9w==} + /@tiptap/extension-horizontal-rule@2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4): + resolution: {integrity: sha512-zyLU+Xlk8y3yBCblE8pFwqAP2Rju1csyAu45hi3NCJ6HDGQGdjy8oh+Xa8y2kTPxRNMZARxqB+vCiEoW3YZn2A==} peerDependencies: '@tiptap/core': ^2.0.0 '@tiptap/pm': ^2.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) '@tiptap/pm': 2.2.4 dev: false - /@tiptap/extension-italic@2.2.5(@tiptap/core@2.2.5): - resolution: {integrity: sha512-FEUaRkEQ1rY3nmOzHp2THHhTjE2Ltv5tXoABnannjpoLFe6AIdmYcsHOOI7pvdZQclejSQoFpuEDillvDHtUkg==} + /@tiptap/extension-image@2.2.5(@tiptap/core@2.2.6): + resolution: {integrity: sha512-sFBuNaTYnsprDV/GczBy8CCGd/9oPYLCRcCuTE+HaRnAh518jVL+n6X8XIOO5u+AEJT6frRGiM68wpyk1Tq31w==} peerDependencies: '@tiptap/core': ^2.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) dev: false - /@tiptap/extension-link@2.2.5(@tiptap/core@2.2.5)(@tiptap/pm@2.2.4): - resolution: {integrity: sha512-3UyEdD7eOzb31Ro9zh02EIvZhgSFKV+/rSKgAf4wU17QUFid0cYRqaXcVjG0UOSznHqccxGQKD7nNT0jxTg+cw==} + /@tiptap/extension-italic@2.2.6(@tiptap/core@2.2.6): + resolution: {integrity: sha512-wB+Y6p2gbc1f2hKYeGNXRQ7P2xi3+JzD3PjSyC9Ss/yyujZhxSOtxBF0nzFXdI+7nmN0Qm4inwPDU/DVrIPb+A==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) + dev: false + + /@tiptap/extension-link@2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4): + resolution: {integrity: sha512-Jj0oXSfQ8gZlzzwd669B8sEKBkoK8xV31Lu55tRv9PKHSU6p9CUqBuxY8qR+cquCtO28f3u0cdl5o4HzeIUL5A==} peerDependencies: '@tiptap/core': ^2.0.0 '@tiptap/pm': ^2.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) '@tiptap/pm': 2.2.4 linkifyjs: 4.1.3 dev: false - /@tiptap/extension-list-item@2.2.5(@tiptap/core@2.2.5): - resolution: {integrity: sha512-skmDdzvW0iwtwAkQOpDhAQy2eoWRFUWElu9uoqouC4uh+arbSpAEs1tXgBjb4wda0R2wvLUOLxFUdwwFZwgYhQ==} + /@tiptap/extension-list-item@2.2.6(@tiptap/core@2.2.6): + resolution: {integrity: sha512-3xig1q0jtOyV49TkAbvxBoOJdNypwq6vLYerfblhj6dK+hIIZUM33S+SmGl2+QaB25VwyeSHjiCvrJjB9PKWHQ==} peerDependencies: '@tiptap/core': ^2.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) dev: false - /@tiptap/extension-ordered-list@2.2.5(@tiptap/core@2.2.5): - resolution: {integrity: sha512-zVE21e8EWOQxstJEzpCSl0yI3MxjCciHpRBmnxEiuN7W3vDrjfphwrksZDwNHBDIZYQF7hEtTWgOgjnacxpmWQ==} + /@tiptap/extension-ordered-list@2.2.6(@tiptap/core@2.2.6): + resolution: {integrity: sha512-h4HOv+TAMnoueh3CzUY2/Pp2n8eCdEQtKSfiMtHSO3NTTSlst0XEvq+3Z4K81F+ni3baXc+JUALP5dRVpI4apQ==} peerDependencies: '@tiptap/core': ^2.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) dev: false - /@tiptap/extension-paragraph@2.2.5(@tiptap/core@2.2.5): - resolution: {integrity: sha512-FiyCkGfDPv1UQhVTX2uuEENAJ8G9GA6iDFD6HZH8/vOvkKgEI3B9/PUjOecR0rn+Ncta4f/dMRTyUlt6ezfwJg==} + /@tiptap/extension-paragraph@2.2.6(@tiptap/core@2.2.6): + resolution: {integrity: sha512-M2rM3pfzziUb7xS9x2dANCokO89okbqg5IqU4VPkZhk0Mfq9czyCatt58TYkAsE3ccsGhdTYtFBTDeKBtsHUqg==} peerDependencies: '@tiptap/core': ^2.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) dev: false - /@tiptap/extension-strike@2.2.5(@tiptap/core@2.2.5): - resolution: {integrity: sha512-Zx+6afbx3RbWzVXGSNHSAOVb2O8SDyZqsgEuIepbh5t2kFvZHCBMA7qLlco1zdIelPp+6pD2NoAvHkQnjjrDmw==} + /@tiptap/extension-strike@2.2.6(@tiptap/core@2.2.6): + resolution: {integrity: sha512-0fRh0SwPgqi+ZKD2NpRrmIAHdsgf27ddEUfvlIuFG5b9zqFa6pRZGpXW/6LyBwU0+0bkjW8/Wg3otyaRGjvZGw==} peerDependencies: '@tiptap/core': ^2.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) dev: false - /@tiptap/extension-text@2.2.5(@tiptap/core@2.2.5): - resolution: {integrity: sha512-Sn6Wqa52PVtJQW0W5zE8Tzf+61wH7s1kh0yN9Q05IeSoslK38R8mBdezp0bHnbqFrlqXDxtPrTRgipaWCSV6Lw==} + /@tiptap/extension-table-cell@2.2.5(@tiptap/core@2.2.6): + resolution: {integrity: sha512-vJl4rED9VUUKAA7sJejTzQshdIQ4TKWSiT20vS2hO332E8+fFLAByb0V/eBKC0mKIx2xFP+JbQPuMDPrXwaeKA==} peerDependencies: '@tiptap/core': ^2.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) + dev: false + + /@tiptap/extension-table-header@2.2.5(@tiptap/core@2.2.6): + resolution: {integrity: sha512-JicDIocBJr07dVcscjsPOEZyfq3ceBoYYvsW9hRq5xBS6OLJwNTNsJoKWKDXkQHG8q0K0v8L3Ce085NDxGTdCQ==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) + dev: false + + /@tiptap/extension-table-row@2.2.5(@tiptap/core@2.2.6): + resolution: {integrity: sha512-f/yff0eHr7hsNokXaipFece6bib8iLwI/rue2NKIMICzsBXpaWI9V5cwtDcddvWWjBz/ZdB7NVULtATtjUhpdg==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) + dev: false + + /@tiptap/extension-table@2.2.5(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4): + resolution: {integrity: sha512-+dAlJBtoyXkXH8sR5K872l0oI6sl4swVG/c00ve92h9ZWG3wuPyb74RKfglGK6zK4rxPkfwYnHc/xDMsyh+NgQ==} + peerDependencies: + '@tiptap/core': ^2.0.0 + '@tiptap/pm': ^2.0.0 + dependencies: + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) + '@tiptap/pm': 2.2.4 + dev: false + + /@tiptap/extension-task-item@2.2.5(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4): + resolution: {integrity: sha512-1lJ4d/7+Bk7N14NUNHmFUbfxgMnGVSxYiXki414UdKKfg5uS2nflwTEpE8nra6YyODotVmIpfluaIrHBGLG2/Q==} + peerDependencies: + '@tiptap/core': ^2.0.0 + '@tiptap/pm': ^2.0.0 + dependencies: + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) + '@tiptap/pm': 2.2.4 + dev: false + + /@tiptap/extension-task-list@2.2.5(@tiptap/core@2.2.6): + resolution: {integrity: sha512-Gq1/tZYs2axXFgdxCjkmNKXI505acZjp8qUjwt4yTzb9lORcl/62wweB5sryR1Zef7UuwMD7ew+8nimz3JVSjA==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) + dev: false + + /@tiptap/extension-text-align@2.2.5(@tiptap/core@2.2.6): + resolution: {integrity: sha512-rCnWjEc0hw52lgiEhs96lTn9s9R+sT0VWHP2RlGhIvC0gCCKqlpPbMdUPKc94SIoRurBIikHV4MWnWYoI0/trA==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) + dev: false + + /@tiptap/extension-text-style@2.2.5(@tiptap/core@2.2.6): + resolution: {integrity: sha512-Hlx9WTS5VXjD9CqPrHIqGjYm5vKFjkKPSOf9H2kxZ8vdVBKpAOzLsfryq4rOLdP1bpmcX3zeOe2DGByUapbs1g==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) + dev: false + + /@tiptap/extension-text@2.2.6(@tiptap/core@2.2.6): + resolution: {integrity: sha512-wVpo0I/2tJsBK/2yNZfRXOsThOfHCdTY+FDNO/USx9MCJaJ3LPs3H1AuGO549zNmZgkD+1MqcZqrYt9n4i03cw==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) + dev: false + + /@tiptap/extension-underline@2.2.5(@tiptap/core@2.2.6): + resolution: {integrity: sha512-qKes3UVhktaRLOUFv3tpl3MOY4g1rnY6mxuVRmFeicgEtG0IHv7ByrNwA775CdmKdsewz55P5JYrj1jUzbpBhQ==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) dev: false /@tiptap/pm@2.2.4: @@ -2871,44 +3009,44 @@ packages: prosemirror-view: 1.33.1 dev: false - /@tiptap/react@2.2.5(@tiptap/core@2.2.5)(@tiptap/pm@2.2.4)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-kpEnkvTXUnr6npLt1mQCBhdgle/ZkttGgKwtwSLdM74zPzPwj8XVeCp+3kyVBK4ME7DXWIo5dPbU0nUi/FyE+g==} + /@tiptap/react@2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-KZLsaia9FYrhjBJ+HP2L2HQLqspgC7JLT5wXcOpgdKwQ8wAMkD3b2a6bhAc9IKZSkbhcX2D+uafGPGn2M6j6Lw==} peerDependencies: '@tiptap/core': ^2.0.0 '@tiptap/pm': ^2.0.0 react: ^17.0.0 || ^18.0.0 react-dom: ^17.0.0 || ^18.0.0 dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) - '@tiptap/extension-bubble-menu': 2.2.5(@tiptap/core@2.2.5)(@tiptap/pm@2.2.4) - '@tiptap/extension-floating-menu': 2.2.5(@tiptap/core@2.2.5)(@tiptap/pm@2.2.4) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) + '@tiptap/extension-bubble-menu': 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4) + '@tiptap/extension-floating-menu': 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4) '@tiptap/pm': 2.2.4 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /@tiptap/starter-kit@2.2.5(@tiptap/pm@2.2.4): - resolution: {integrity: sha512-IcMwleJpIaPi2xvFDnxeg/TL2O9LYhgEOQZjTX96dOP2gG7logWYqIuPCfWzD46IKdjMvk4cqMB/SORd8zJAUQ==} + /@tiptap/starter-kit@2.2.6(@tiptap/pm@2.2.4): + resolution: {integrity: sha512-dWdLcx7g9DTYYzlnStft8vNLrnn+nUWj5Hx4i1dRRW31hBvIxnPwFYcEPKd+7xguozuUX5g+P4OYI6M3LOUxlA==} dependencies: - '@tiptap/core': 2.2.5(@tiptap/pm@2.2.4) - '@tiptap/extension-blockquote': 2.2.5(@tiptap/core@2.2.5) - '@tiptap/extension-bold': 2.2.5(@tiptap/core@2.2.5) - '@tiptap/extension-bullet-list': 2.2.5(@tiptap/core@2.2.5) - '@tiptap/extension-code': 2.2.5(@tiptap/core@2.2.5) - '@tiptap/extension-code-block': 2.2.5(@tiptap/core@2.2.5)(@tiptap/pm@2.2.4) - '@tiptap/extension-document': 2.2.5(@tiptap/core@2.2.5) - '@tiptap/extension-dropcursor': 2.2.5(@tiptap/core@2.2.5)(@tiptap/pm@2.2.4) - '@tiptap/extension-gapcursor': 2.2.5(@tiptap/core@2.2.5)(@tiptap/pm@2.2.4) - '@tiptap/extension-hard-break': 2.2.5(@tiptap/core@2.2.5) - '@tiptap/extension-heading': 2.2.5(@tiptap/core@2.2.5) - '@tiptap/extension-history': 2.2.5(@tiptap/core@2.2.5)(@tiptap/pm@2.2.4) - '@tiptap/extension-horizontal-rule': 2.2.5(@tiptap/core@2.2.5)(@tiptap/pm@2.2.4) - '@tiptap/extension-italic': 2.2.5(@tiptap/core@2.2.5) - '@tiptap/extension-list-item': 2.2.5(@tiptap/core@2.2.5) - '@tiptap/extension-ordered-list': 2.2.5(@tiptap/core@2.2.5) - '@tiptap/extension-paragraph': 2.2.5(@tiptap/core@2.2.5) - '@tiptap/extension-strike': 2.2.5(@tiptap/core@2.2.5) - '@tiptap/extension-text': 2.2.5(@tiptap/core@2.2.5) + '@tiptap/core': 2.2.6(@tiptap/pm@2.2.4) + '@tiptap/extension-blockquote': 2.2.6(@tiptap/core@2.2.6) + '@tiptap/extension-bold': 2.2.6(@tiptap/core@2.2.6) + '@tiptap/extension-bullet-list': 2.2.6(@tiptap/core@2.2.6) + '@tiptap/extension-code': 2.2.6(@tiptap/core@2.2.6) + '@tiptap/extension-code-block': 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4) + '@tiptap/extension-document': 2.2.6(@tiptap/core@2.2.6) + '@tiptap/extension-dropcursor': 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4) + '@tiptap/extension-gapcursor': 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4) + '@tiptap/extension-hard-break': 2.2.6(@tiptap/core@2.2.6) + '@tiptap/extension-heading': 2.2.6(@tiptap/core@2.2.6) + '@tiptap/extension-history': 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4) + '@tiptap/extension-horizontal-rule': 2.2.6(@tiptap/core@2.2.6)(@tiptap/pm@2.2.4) + '@tiptap/extension-italic': 2.2.6(@tiptap/core@2.2.6) + '@tiptap/extension-list-item': 2.2.6(@tiptap/core@2.2.6) + '@tiptap/extension-ordered-list': 2.2.6(@tiptap/core@2.2.6) + '@tiptap/extension-paragraph': 2.2.6(@tiptap/core@2.2.6) + '@tiptap/extension-strike': 2.2.6(@tiptap/core@2.2.6) + '@tiptap/extension-text': 2.2.6(@tiptap/core@2.2.6) transitivePeerDependencies: - '@tiptap/pm' dev: false @@ -3210,11 +3348,11 @@ packages: /@types/react-dom@18.2.25: resolution: {integrity: sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA==} dependencies: - '@types/react': 18.2.76 + '@types/react': 18.2.78 dev: true - /@types/react@18.2.76: - resolution: {integrity: sha512-T6z/v7YxpswDM61Vq5KoSPTJqCkroJfsDIsvXCr4+qOY6gik5Ju4w0jf67cpC5z7ydOnp/E0V0W08pDRy8u9Xw==} + /@types/react@18.2.78: + resolution: {integrity: sha512-qOwdPnnitQY4xKlKayt42q5W5UQrSHjgoXNVEtxeqdITJ99k4VXJOP3vt8Rkm9HmgJpH50UNU+rlqfkfWOqp0A==} dependencies: '@types/prop-types': 15.7.11 csstype: 3.1.3 @@ -6234,7 +6372,7 @@ packages: resolution: {integrity: sha512-/WByRr4jDcsKlvMd1dRJnPfS1GVO3WuKyaurJ/vvXcOaUQO8rnNObCQMlv/5uCceVQIq5Q4WLF44ohsdiTohdg==} dev: false - /jotai@2.8.0(@types/react@18.2.76)(react@18.2.0): + /jotai@2.8.0(@types/react@18.2.78)(react@18.2.0): resolution: {integrity: sha512-yZNMC36FdLOksOr8qga0yLf14miCJlEThlp5DeFJNnqzm2+ZG7wLcJzoOyij5K6U6Xlc5ljQqPDlJRgqW0Y18g==} engines: {node: '>=12.20.0'} peerDependencies: @@ -6246,7 +6384,7 @@ packages: react: optional: true dependencies: - '@types/react': 18.2.76 + '@types/react': 18.2.78 react: 18.2.0 dev: false @@ -6587,7 +6725,7 @@ packages: react: '>=18.0' react-dom: '>=18.0' dependencies: - '@mantine/core': 7.7.1(@mantine/hooks@7.7.1)(@types/react@18.2.76)(react-dom@18.2.0)(react@18.2.0) + '@mantine/core': 7.7.1(@mantine/hooks@7.7.1)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) '@mantine/dates': 7.7.1(@mantine/core@7.7.1)(@mantine/hooks@7.7.1)(dayjs@1.11.10)(react-dom@18.2.0)(react@18.2.0) '@mantine/hooks': 7.7.1(react@18.2.0) '@tabler/icons-react': 3.1.0(react@18.2.0) @@ -7700,7 +7838,7 @@ packages: engines: {node: '>=0.10.0'} dev: true - /react-remove-scroll-bar@2.3.4(@types/react@18.2.76)(react@18.2.0): + /react-remove-scroll-bar@2.3.4(@types/react@18.2.78)(react@18.2.0): resolution: {integrity: sha512-63C4YQBUt0m6ALadE9XV56hV8BgJWDmmTPY758iIJjfQKt2nYwoUrPk0LXRXcB/yIj82T1/Ixfdpdk68LwIB0A==} engines: {node: '>=10'} peerDependencies: @@ -7710,13 +7848,13 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.76 + '@types/react': 18.2.78 react: 18.2.0 - react-style-singleton: 2.2.1(@types/react@18.2.76)(react@18.2.0) + react-style-singleton: 2.2.1(@types/react@18.2.78)(react@18.2.0) tslib: 2.6.2 dev: false - /react-remove-scroll@2.5.7(@types/react@18.2.76)(react@18.2.0): + /react-remove-scroll@2.5.7(@types/react@18.2.78)(react@18.2.0): resolution: {integrity: sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==} engines: {node: '>=10'} peerDependencies: @@ -7726,16 +7864,16 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.76 + '@types/react': 18.2.78 react: 18.2.0 - react-remove-scroll-bar: 2.3.4(@types/react@18.2.76)(react@18.2.0) - react-style-singleton: 2.2.1(@types/react@18.2.76)(react@18.2.0) + react-remove-scroll-bar: 2.3.4(@types/react@18.2.78)(react@18.2.0) + react-style-singleton: 2.2.1(@types/react@18.2.78)(react@18.2.0) tslib: 2.6.2 - use-callback-ref: 1.3.1(@types/react@18.2.76)(react@18.2.0) - use-sidecar: 1.1.2(@types/react@18.2.76)(react@18.2.0) + use-callback-ref: 1.3.1(@types/react@18.2.78)(react@18.2.0) + use-sidecar: 1.1.2(@types/react@18.2.78)(react@18.2.0) dev: false - /react-style-singleton@2.2.1(@types/react@18.2.76)(react@18.2.0): + /react-style-singleton@2.2.1(@types/react@18.2.78)(react@18.2.0): resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} engines: {node: '>=10'} peerDependencies: @@ -7745,14 +7883,14 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.76 + '@types/react': 18.2.78 get-nonce: 1.0.1 invariant: 2.2.4 react: 18.2.0 tslib: 2.6.2 dev: false - /react-textarea-autosize@8.5.3(@types/react@18.2.76)(react@18.2.0): + /react-textarea-autosize@8.5.3(@types/react@18.2.78)(react@18.2.0): resolution: {integrity: sha512-XT1024o2pqCuZSuBt9FwHlaDeNtVrtCXu0Rnz88t1jUGheCLa3PhjE1GH8Ctm2axEtvdCl5SUHYschyQ0L5QHQ==} engines: {node: '>=10'} peerDependencies: @@ -7761,7 +7899,7 @@ packages: '@babel/runtime': 7.23.9 react: 18.2.0 use-composed-ref: 1.3.0(react@18.2.0) - use-latest: 1.2.1(@types/react@18.2.76)(react@18.2.0) + use-latest: 1.2.1(@types/react@18.2.78)(react@18.2.0) transitivePeerDependencies: - '@types/react' dev: false @@ -8879,7 +9017,7 @@ packages: resolution: {integrity: sha512-mtN6xk+Nac+oyJ/PrI7tzfmomRVNFIWKUbG8jdYFt52hxbiReFAXIjYskvu64/dvuW71IcB7lV8l0HvZMac6Jg==} dev: false - /use-callback-ref@1.3.1(@types/react@18.2.76)(react@18.2.0): + /use-callback-ref@1.3.1(@types/react@18.2.78)(react@18.2.0): resolution: {integrity: sha512-Lg4Vx1XZQauB42Hw3kK7JM6yjVjgFmFC5/Ab797s79aARomD2nEErc4mCgM8EZrARLmmbWpi5DGCadmK50DcAQ==} engines: {node: '>=10'} peerDependencies: @@ -8889,7 +9027,7 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.76 + '@types/react': 18.2.78 react: 18.2.0 tslib: 2.6.2 dev: false @@ -8913,7 +9051,7 @@ packages: react: 18.2.0 dev: false - /use-isomorphic-layout-effect@1.1.2(@types/react@18.2.76)(react@18.2.0): + /use-isomorphic-layout-effect@1.1.2(@types/react@18.2.78)(react@18.2.0): resolution: {integrity: sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==} peerDependencies: '@types/react': '*' @@ -8922,11 +9060,11 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.76 + '@types/react': 18.2.78 react: 18.2.0 dev: false - /use-latest@1.2.1(@types/react@18.2.76)(react@18.2.0): + /use-latest@1.2.1(@types/react@18.2.78)(react@18.2.0): resolution: {integrity: sha512-xA+AVm/Wlg3e2P/JiItTziwS7FK92LWrDB0p+hgXloIMuVCeJJ8v6f0eeHyPZaJrM+usM1FkFfbNCrJGs8A/zw==} peerDependencies: '@types/react': '*' @@ -8935,12 +9073,12 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.76 + '@types/react': 18.2.78 react: 18.2.0 - use-isomorphic-layout-effect: 1.1.2(@types/react@18.2.76)(react@18.2.0) + use-isomorphic-layout-effect: 1.1.2(@types/react@18.2.78)(react@18.2.0) dev: false - /use-sidecar@1.1.2(@types/react@18.2.76)(react@18.2.0): + /use-sidecar@1.1.2(@types/react@18.2.78)(react@18.2.0): resolution: {integrity: sha512-epTbsLuzZ7lPClpz2TyryBfztm7m+28DlEv2ZCQ3MDr5ssiwyOwGH/e5F9CkfWjJ1t4clvI58yF822/GUkjjhw==} engines: {node: '>=10'} peerDependencies: @@ -8950,7 +9088,7 @@ packages: '@types/react': optional: true dependencies: - '@types/react': 18.2.76 + '@types/react': 18.2.78 detect-node-es: 1.1.0 react: 18.2.0 tslib: 2.6.2