diff --git a/.changeset/strong-suits-wonder.md b/.changeset/strong-suits-wonder.md new file mode 100644 index 0000000000..6f4ee3533c --- /dev/null +++ b/.changeset/strong-suits-wonder.md @@ -0,0 +1,8 @@ +--- +"uploadthing": minor +"@uploadthing/react": minor +--- + +feat: add `generateReactHelpers.getRouteConfig`, `isValidFileSize` and `isValidFileType` helpers + +💡 See https://github.com/pingdotgg/uploadthing/blob/main/examples/with-novel/uploadthing/novel-plugin.ts#L50-L61 for a live example utilizing these helpers. \ No newline at end of file diff --git a/docs/src/pages/api/uploadthing.ts b/docs/src/pages/api/uploadthing.ts new file mode 100644 index 0000000000..850c58564c --- /dev/null +++ b/docs/src/pages/api/uploadthing.ts @@ -0,0 +1,16 @@ +import { createRouteHandler, createUploadthing } from "uploadthing/next-legacy"; + +const f = createUploadthing(); +const router = { + mockRoute: f(["image"]) + .middleware(() => { + throw new Error("This is just a mock route, you cant use it"); + return {}; + }) + .onUploadComplete(() => {}), +}; + +export default createRouteHandler({ + router, + config: { uploadthingSecret: "sk_foo" }, +}); diff --git a/docs/src/pages/theming.mdx b/docs/src/pages/theming.mdx index ea24dd578c..5a7545db8d 100644 --- a/docs/src/pages/theming.mdx +++ b/docs/src/pages/theming.mdx @@ -242,6 +242,7 @@ component match your design in the exact way you want. ``` Upload stuff; @@ -710,6 +724,7 @@ type UploadDropzoneProps = { ``` Upload stuff; diff --git a/examples/minimal-appdir/src/app/page.tsx b/examples/minimal-appdir/src/app/page.tsx index 68a4c4086c..bf64b7a1cd 100644 --- a/examples/minimal-appdir/src/app/page.tsx +++ b/examples/minimal-appdir/src/app/page.tsx @@ -30,7 +30,7 @@ export default function Home() { onUploadBegin={() => { console.log("upload begin"); }} - config={{ appendOnPaste: true }} + config={{ appendOnPaste: true, mode: "manual" }} /> + + + +This is a stripped down version of the Novel Web app. See the original full +source code at: https://github.com/steven-tey/novel/tree/main/apps/web + +For the UploadThing specific code in this example, see +[uploadthing/novel-plugin.ts](./uploadthing/novel-plugin.ts). + +## QuickStart + +1. Grab an API key from the UploadThing dashboard: + https://uploadthing.com/dashboard +2. `cp .env.example .env` and paste in your API key in the newly created `.env` + file +3. `pnpm i && pnpm dev` +4. Use the editor and upload files! + +## Further reference + +Check out the docs at: + +- https://docs.uploadthing.com/getting-started/appdir +- https://novel.sh/docs diff --git a/examples/with-novel/app/_styles/CalSans-SemiBold.otf b/examples/with-novel/app/_styles/CalSans-SemiBold.otf new file mode 100644 index 0000000000..7ad1591f12 Binary files /dev/null and b/examples/with-novel/app/_styles/CalSans-SemiBold.otf differ diff --git a/examples/with-novel/app/_styles/fonts.ts b/examples/with-novel/app/_styles/fonts.ts new file mode 100644 index 0000000000..db9e8362e9 --- /dev/null +++ b/examples/with-novel/app/_styles/fonts.ts @@ -0,0 +1,47 @@ +import { Crimson_Text, Inconsolata, Inter } from "next/font/google"; +import localFont from "next/font/local"; + +export const cal = localFont({ + src: "./CalSans-SemiBold.otf", + variable: "--font-title", +}); + +export const crimsonBold = Crimson_Text({ + weight: "700", + variable: "--font-title", + subsets: ["latin"], +}); + +export const inter = Inter({ + variable: "--font-default", + subsets: ["latin"], +}); + +export const inconsolataBold = Inconsolata({ + weight: "700", + variable: "--font-title", + subsets: ["latin"], +}); + +export const crimson = Crimson_Text({ + weight: "400", + variable: "--font-default", + subsets: ["latin"], +}); + +export const inconsolata = Inconsolata({ + variable: "--font-default", + subsets: ["latin"], +}); + +export const titleFontMapper = { + Default: cal.variable, + Serif: crimsonBold.variable, + Mono: inconsolataBold.variable, +}; + +export const defaultFontMapper = { + Default: inter.variable, + Serif: crimson.variable, + Mono: inconsolata.variable, +}; diff --git a/examples/with-novel/app/_styles/globals.css b/examples/with-novel/app/_styles/globals.css new file mode 100644 index 0000000000..f744c33cef --- /dev/null +++ b/examples/with-novel/app/_styles/globals.css @@ -0,0 +1,96 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + + --card: 0 0% 100%; + --card-foreground: 222.2 84% 4.9%; + + --popover: 0 0% 100%; + --popover-foreground: 222.2 84% 4.9%; + + --primary: 222.2 47.4% 11.2%; + --primary-foreground: 210 40% 98%; + + --secondary: 210 40% 96.1%; + --secondary-foreground: 222.2 47.4% 11.2%; + + --muted: 210 40% 96.1%; + --muted-foreground: 215.4 16.3% 46.9%; + + --accent: 210 40% 96.1%; + --accent-foreground: 222.2 47.4% 11.2%; + + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 40% 98%; + + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + --ring: 222.2 84% 4.9%; + + --radius: 0.5rem; + + --novel-highlight-default: #ffffff; + --novel-highlight-purple: #f6f3f8; + --novel-highlight-red: #fdebeb; + --novel-highlight-yellow: #fbf4a2; + --novel-highlight-blue: #c1ecf9; + --novel-highlight-green: #acf79f; + --novel-highlight-orange: #faebdd; + --novel-highlight-pink: #faf1f5; + --novel-highlight-gray: #f1f1ef; + } + + .dark { + --background: 222.2 84% 4.9%; + --foreground: 210 40% 98%; + + --card: 222.2 84% 4.9%; + --card-foreground: 210 40% 98%; + + --popover: 222.2 84% 4.9%; + --popover-foreground: 210 40% 98%; + + --primary: 210 40% 98%; + --primary-foreground: 222.2 47.4% 11.2%; + + --secondary: 217.2 32.6% 17.5%; + --secondary-foreground: 210 40% 98%; + + --muted: 217.2 32.6% 17.5%; + --muted-foreground: 215 20.2% 65.1%; + + --accent: 217.2 32.6% 17.5%; + --accent-foreground: 210 40% 98%; + + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 210 40% 98%; + + --border: 217.2 32.6% 17.5%; + --input: 217.2 32.6% 17.5%; + --ring: 212.7 26.8% 83.9%; + + --novel-highlight-default: #000000; + --novel-highlight-purple: #3f2c4b; + --novel-highlight-red: #5c1a1a; + --novel-highlight-yellow: #5c4b1a; + --novel-highlight-blue: #1a3d5c; + --novel-highlight-green: #1a5c20; + --novel-highlight-orange: #5c3a1a; + --novel-highlight-pink: #5c1a3a; + --novel-highlight-gray: #3a3a3a; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/examples/with-novel/app/_styles/prosemirror.css b/examples/with-novel/app/_styles/prosemirror.css new file mode 100644 index 0000000000..57ba4c8123 --- /dev/null +++ b/examples/with-novel/app/_styles/prosemirror.css @@ -0,0 +1,170 @@ +.ProseMirror { + @apply p-12 px-8 sm:px-12; +} + +.ProseMirror .is-editor-empty:first-child::before { + content: attr(data-placeholder); + float: left; + color: hsl(var(--muted-foreground)); + pointer-events: none; + height: 0; +} +.ProseMirror .is-empty::before { + content: attr(data-placeholder); + float: left; + color: hsl(var(--muted-foreground)); + pointer-events: none; + height: 0; +} + +/* Custom image styles */ + +.ProseMirror img { + transition: filter 0.1s ease-in-out; + + &:hover { + cursor: pointer; + filter: brightness(90%); + } + + &.ProseMirror-selectednode { + outline: 3px solid #5abbf7; + filter: brightness(90%); + } +} + +.img-placeholder { + position: relative; + + &:before { + content: ""; + box-sizing: border-box; + position: absolute; + top: 50%; + left: 50%; + width: 36px; + height: 36px; + border-radius: 50%; + border: 3px solid var(--novel-stone-200); + border-top-color: var(--novel-stone-800); + animation: spinning 0.6s linear infinite; + } +} + +@keyframes spinning { + to { + transform: rotate(360deg); + } +} + +/* Custom TODO list checkboxes – shoutout to this awesome tutorial: https://moderncss.dev/pure-css-custom-checkbox-style/ */ + +ul[data-type="taskList"] li > label { + margin-right: 0.2rem; + user-select: none; +} + +@media screen and (max-width: 768px) { + ul[data-type="taskList"] li > label { + margin-right: 0.5rem; + } +} + +ul[data-type="taskList"] li > label input[type="checkbox"] { + -webkit-appearance: none; + appearance: none; + background-color: hsl(var(--background)); + margin: 0; + cursor: pointer; + width: 1.2em; + height: 1.2em; + position: relative; + top: 5px; + border: 2px solid hsl(var(--border)); + margin-right: 0.3rem; + display: grid; + place-content: center; + + &:hover { + background-color: hsl(var(--accent)); + } + + &:active { + background-color: hsl(var(--accent)); + } + + &::before { + content: ""; + width: 0.65em; + height: 0.65em; + transform: scale(0); + transition: 120ms transform ease-in-out; + box-shadow: inset 1em 1em; + transform-origin: center; + clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%); + } + + &:checked::before { + transform: scale(1); + } +} + +ul[data-type="taskList"] li[data-checked="true"] > div > p { + color: var(--muted-foreground); + text-decoration: line-through; + text-decoration-thickness: 2px; +} + +/* Overwrite tippy-box original max-width */ + +.tippy-box { + max-width: 400px !important; +} + +.ProseMirror:not(.dragging) .ProseMirror-selectednode { + outline: none !important; + background-color: var(--novel-highlight-blue); + transition: background-color 0.2s; + box-shadow: none; +} + +.drag-handle { + position: fixed; + opacity: 1; + transition: opacity ease-in 0.2s; + border-radius: 0.25rem; + + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' style='fill: rgba(0, 0, 0, 0.5)'%3E%3Cpath d='M3,2 C2.44771525,2 2,1.55228475 2,1 C2,0.44771525 2.44771525,0 3,0 C3.55228475,0 4,0.44771525 4,1 C4,1.55228475 3.55228475,2 3,2 Z M3,6 C2.44771525,6 2,5.55228475 2,5 C2,4.44771525 2.44771525,4 3,4 C3.55228475,4 4,4.44771525 4,5 C4,5.55228475 3.55228475,6 3,6 Z M3,10 C2.44771525,10 2,9.55228475 2,9 C2,8.44771525 2.44771525,8 3,8 C3.55228475,8 4,8.44771525 4,9 C4,9.55228475 3.55228475,10 3,10 Z M7,2 C6.44771525,2 6,1.55228475 6,1 C6,0.44771525 6.44771525,0 7,0 C7.55228475,0 8,0.44771525 8,1 C8,1.55228475 7.55228475,2 7,2 Z M7,6 C6.44771525,6 6,5.55228475 6,5 C6,4.44771525 6.44771525,4 7,4 C7.55228475,4 8,4.44771525 8,5 C8,5.55228475 7.55228475,6 7,6 Z M7,10 C6.44771525,10 6,9.55228475 6,9 C6,8.44771525 6.44771525,8 7,8 C7.55228475,8 8,8.44771525 8,9 C8,9.55228475 7.55228475,10 7,10 Z'%3E%3C/path%3E%3C/svg%3E"); + background-size: calc(0.5em + 0.375rem) calc(0.5em + 0.375rem); + background-repeat: no-repeat; + background-position: center; + width: 1.2rem; + height: 1.5rem; + z-index: 50; + cursor: grab; + + &:hover { + background-color: var(--novel-stone-100); + transition: background-color 0.2s; + } + + &:active { + background-color: var(--novel-stone-200); + transition: background-color 0.2s; + cursor: grabbing; + } + + &.hide { + opacity: 0; + pointer-events: none; + } + + @media screen and (max-width: 600px) { + display: none; + pointer-events: none; + } +} + +.dark .drag-handle { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10' style='fill: rgba(255, 255, 255, 0.5)'%3E%3Cpath d='M3,2 C2.44771525,2 2,1.55228475 2,1 C2,0.44771525 2.44771525,0 3,0 C3.55228475,0 4,0.44771525 4,1 C4,1.55228475 3.55228475,2 3,2 Z M3,6 C2.44771525,6 2,5.55228475 2,5 C2,4.44771525 2.44771525,4 3,4 C3.55228475,4 4,4.44771525 4,5 C4,5.55228475 3.55228475,6 3,6 Z M3,10 C2.44771525,10 2,9.55228475 2,9 C2,8.44771525 2.44771525,8 3,8 C3.55228475,8 4,8.44771525 4,9 C4,9.55228475 3.55228475,10 3,10 Z M7,2 C6.44771525,2 6,1.55228475 6,1 C6,0.44771525 6.44771525,0 7,0 C7.55228475,0 8,0.44771525 8,1 C8,1.55228475 7.55228475,2 7,2 Z M7,6 C6.44771525,6 6,5.55228475 6,5 C6,4.44771525 6.44771525,4 7,4 C7.55228475,4 8,4.44771525 8,5 C8,5.55228475 7.55228475,6 7,6 Z M7,10 C6.44771525,10 6,9.55228475 6,9 C6,8.44771525 6.44771525,8 7,8 C7.55228475,8 8,8.44771525 8,9 C8,9.55228475 7.55228475,10 7,10 Z'%3E%3C/path%3E%3C/svg%3E"); +} diff --git a/examples/with-novel/app/api/uploadthing/route.ts b/examples/with-novel/app/api/uploadthing/route.ts new file mode 100644 index 0000000000..8b54d8b722 --- /dev/null +++ b/examples/with-novel/app/api/uploadthing/route.ts @@ -0,0 +1,12 @@ +import { uploadRouter } from "@/uploadthing/server"; + +import { createRouteHandler } from "uploadthing/next"; + +export const runtime = "edge"; + +export const { GET, POST } = createRouteHandler({ + router: uploadRouter, + config: { + logLevel: "debug", + }, +}); diff --git a/examples/with-novel/app/layout.tsx b/examples/with-novel/app/layout.tsx new file mode 100644 index 0000000000..64c8f36576 --- /dev/null +++ b/examples/with-novel/app/layout.tsx @@ -0,0 +1,47 @@ +import "./_styles/globals.css"; +import "./_styles/prosemirror.css"; + +import type { ReactNode } from "react"; +import type { Metadata, Viewport } from "next"; +import { uploadRouter } from "@/uploadthing/server"; + +import { NextSSRPlugin } from "@uploadthing/react/next-ssr-plugin"; +import { extractRouterConfig } from "uploadthing/server"; + +import Providers from "./providers"; + +const title = + "Novel - Notion-style WYSIWYG editor with AI-powered autocompletions"; +const description = + "Novel is a Notion-style WYSIWYG editor with AI-powered autocompletions. Built with Tiptap, OpenAI, and Vercel AI SDK."; + +export const metadata: Metadata = { + title, + description, + openGraph: { + title, + description, + }, + twitter: { + title, + description, + card: "summary_large_image", + creator: "@steventey", + }, + metadataBase: new URL("https://novel.sh"), +}; + +export const viewport: Viewport = { + themeColor: "#ffffff", +}; + +export default function RootLayout({ children }: { children: ReactNode }) { + return ( + + + + {children} + + + ); +} diff --git a/examples/with-novel/app/menu.tsx b/examples/with-novel/app/menu.tsx new file mode 100644 index 0000000000..f6e3ee12dd --- /dev/null +++ b/examples/with-novel/app/menu.tsx @@ -0,0 +1,57 @@ +"use client"; + +import { Button } from "@/ui/button"; +import { Popover, PopoverContent, PopoverTrigger } from "@/ui/popover"; +import { Check, Menu as MenuIcon, Monitor, Moon, SunDim } from "lucide-react"; +import { useTheme } from "next-themes"; + +const appearances = [ + { + theme: "System", + icon: , + }, + { + theme: "Light", + icon: , + }, + { + theme: "Dark", + icon: , + }, +]; +export function Menu() { + const { theme: currentTheme, setTheme } = useTheme(); + + return ( + + + + + +

+ Appearance +

+ {appearances.map(({ theme, icon }) => ( + + ))} +
+
+ ); +} diff --git a/examples/with-novel/app/page.tsx b/examples/with-novel/app/page.tsx new file mode 100644 index 0000000000..6300b48d8e --- /dev/null +++ b/examples/with-novel/app/page.tsx @@ -0,0 +1,37 @@ +import { Menu } from "@/app/menu"; +import { AdvancedEditor } from "@/editor"; +import { buttonVariants } from "@/ui/button"; +import { Github } from "lucide-react"; +import { twMerge } from "tailwind-merge"; + +export default function Page() { + return ( + + ); +} diff --git a/examples/with-novel/app/providers.tsx b/examples/with-novel/app/providers.tsx new file mode 100644 index 0000000000..55ddb5e77c --- /dev/null +++ b/examples/with-novel/app/providers.tsx @@ -0,0 +1,26 @@ +"use client"; + +import { type ReactNode } from "react"; +import { ThemeProvider, useTheme } from "next-themes"; +import { Toaster } from "sonner"; + +const ToasterProvider = () => { + const { theme } = useTheme() as { + theme: "light" | "dark" | "system"; + }; + return ; +}; + +export default function Providers({ children }: { children: ReactNode }) { + return ( + + + {children} + + ); +} diff --git a/examples/with-novel/editor/extensions.ts b/examples/with-novel/editor/extensions.ts new file mode 100644 index 0000000000..1b25b235ae --- /dev/null +++ b/examples/with-novel/editor/extensions.ts @@ -0,0 +1,115 @@ +import { cx } from "class-variance-authority"; +import { + HorizontalRule, + Placeholder, + StarterKit, + TaskItem, + TaskList, + TiptapImage, + TiptapLink, + UpdatedImage, +} from "novel/extensions"; +import { UploadImagesPlugin } from "novel/plugins"; + +//TODO I am using cx here to get tailwind autocomplete working, idk if someone else can write a regex to just capture the class key in objects +//You can overwrite the placeholder with your own configuration +const placeholder = Placeholder; +const tiptapLink = TiptapLink.configure({ + HTMLAttributes: { + class: cx( + "text-muted-foreground underline underline-offset-[3px] hover:text-primary transition-colors cursor-pointer", + ), + }, +}); + +const tiptapImage = TiptapImage.extend({ + addProseMirrorPlugins() { + return [ + UploadImagesPlugin({ + imageClass: cx("opacity-40 rounded-lg border border-stone-200"), + }), + ]; + }, +}).configure({ + allowBase64: true, + HTMLAttributes: { + class: cx("rounded-lg border border-muted"), + }, +}); + +const updatedImage = UpdatedImage.configure({ + HTMLAttributes: { + class: cx("rounded-lg border border-muted"), + }, +}); + +const taskList = TaskList.configure({ + HTMLAttributes: { + class: cx("not-prose pl-2 "), + }, +}); +const taskItem = TaskItem.configure({ + HTMLAttributes: { + class: cx("flex gap-2 items-start my-4"), + }, + nested: true, +}); + +const horizontalRule = HorizontalRule.configure({ + HTMLAttributes: { + class: cx("mt-4 mb-6 border-t border-muted-foreground"), + }, +}); + +const starterKit = StarterKit.configure({ + bulletList: { + HTMLAttributes: { + class: cx("list-disc list-outside leading-3 -mt-2"), + }, + }, + orderedList: { + HTMLAttributes: { + class: cx("list-decimal list-outside leading-3 -mt-2"), + }, + }, + listItem: { + HTMLAttributes: { + class: cx("leading-normal -mb-2"), + }, + }, + blockquote: { + HTMLAttributes: { + class: cx("border-l-4 border-primary"), + }, + }, + codeBlock: { + HTMLAttributes: { + class: cx( + "rounded-md bg-muted text-muted-foreground border p-5 font-mono font-medium", + ), + }, + }, + code: { + HTMLAttributes: { + class: cx("rounded-md bg-muted px-1.5 py-1 font-mono font-medium"), + spellcheck: "false", + }, + }, + horizontalRule: false, + dropcursor: { + color: "#DBEAFE", + width: 4, + }, + gapcursor: false, +}); + +export const defaultExtensions = [ + starterKit, + placeholder, + tiptapLink, + tiptapImage, + updatedImage, + taskList, + taskItem, + horizontalRule, +]; diff --git a/examples/with-novel/editor/index.tsx b/examples/with-novel/editor/index.tsx new file mode 100644 index 0000000000..a184ffbb8b --- /dev/null +++ b/examples/with-novel/editor/index.tsx @@ -0,0 +1,210 @@ +"use client"; + +import React, { useEffect, useState } from "react"; +import { uploadFn } from "@/uploadthing/novel-plugin"; +import { + EditorCommand, + EditorCommandEmpty, + EditorCommandItem, + EditorCommandList, + EditorContent, + EditorInstance, + EditorRoot, + type JSONContent, +} from "novel"; +import { handleCommandNavigation, ImageResizer } from "novel/extensions"; +import { handleImageDrop, handleImagePaste } from "novel/plugins"; +import { useDebouncedCallback } from "use-debounce"; + +import { defaultExtensions } from "./extensions"; +import { slashCommand, suggestionItems } from "./slash-command"; + +const extensions = [...defaultExtensions, slashCommand]; + +export const AdvancedEditor = () => { + const [initialContent, setInitialContent] = useState( + null, + ); + const [saveStatus, setSaveStatus] = useState("Saved"); + + const debouncedUpdates = useDebouncedCallback( + async (editor: EditorInstance) => { + const json = editor.getJSON(); + + window.localStorage.setItem("novel-content", JSON.stringify(json)); + setSaveStatus("Saved"); + }, + 500, + ); + + useEffect(() => { + const content = window.localStorage.getItem("novel-content"); + if (content) setInitialContent(JSON.parse(content)); + else setInitialContent(defaultEditorContent); + }, []); + + if (!initialContent) return null; + + return ( +
+
+ {saveStatus} +
+ + handleCommandNavigation(event), + }, + handlePaste: (view, event) => + handleImagePaste(view, event, uploadFn), + handleDrop: (view, event, _slice, moved) => + handleImageDrop(view, event, moved, uploadFn), + attributes: { + class: `prose prose-lg dark:prose-invert prose-headings:font-title font-default focus:outline-none max-w-full`, + }, + }} + onUpdate={({ editor }) => { + debouncedUpdates(editor); + setSaveStatus("Unsaved"); + }} + slotAfter={} + > + + + No results + + + {suggestionItems.map((item) => ( + item.command?.(val)} + className={`hover:bg-accent aria-selected:bg-accent flex w-full items-center space-x-2 rounded-md px-2 py-1 text-left text-sm `} + key={item.title} + > +
+ {item.icon} +
+
+

{item.title}

+

+ {item.description} +

+
+
+ ))} +
+
+
+
+
+ ); +}; + +const defaultEditorContent = { + type: "doc", + content: [ + { + type: "heading", + attrs: { level: 2 }, + content: [{ type: "text", text: "Novel x UploadThing" }], + }, + { + type: "paragraph", + content: [ + { + type: "text", + text: "This is a stripped down example based on ", + }, + { + type: "text", + marks: [ + { + type: "link", + attrs: { + href: "https://github.com/steven-tey/novel/apps/web", + target: "_blank", + }, + }, + ], + text: "the official Novel web app", + }, + { + type: "text", + text: " showing how to integrate it with UploadThing.", + }, + ], + }, + { + type: "heading", + attrs: { level: 3 }, + content: [{ type: "text", text: "Installation" }], + }, + { + type: "codeBlock", + attrs: { language: null }, + content: [ + { type: "text", text: "npm i novel uploadthing @uploadthing/react" }, + ], + }, + { + type: "heading", + attrs: { level: 3 }, + content: [{ type: "text", text: "Try uploading something by" }], + }, + { + type: "taskList", + content: [ + { + type: "taskItem", + attrs: { checked: false }, + content: [ + { + type: "paragraph", + content: [{ type: "text", text: "Copy-Pasting an image" }], + }, + ], + }, + { + type: "taskItem", + attrs: { checked: false }, + content: [ + { + type: "paragraph", + content: [{ type: "text", text: "Drag and drop an image" }], + }, + ], + }, + { + type: "taskItem", + attrs: { checked: false }, + content: [ + { + type: "paragraph", + content: [ + { + type: "text", + text: "Using the Image command from the slash menu", + }, + ], + }, + ], + }, + ], + }, + { + type: "image", + attrs: { + src: "https://docs.uploadthing.com/og.jpg", + alt: "banner.png", + title: "banner.png", + width: null, + height: null, + }, + }, + { type: "horizontalRule" }, + ], +}; diff --git a/examples/with-novel/editor/node-selector.tsx b/examples/with-novel/editor/node-selector.tsx new file mode 100644 index 0000000000..92f6009aa7 --- /dev/null +++ b/examples/with-novel/editor/node-selector.tsx @@ -0,0 +1,141 @@ +import { Button } from "@/ui/button"; +import { PopoverContent, PopoverTrigger } from "@/ui/popover"; +import { Popover } from "@radix-ui/react-popover"; +import { + Check, + CheckSquare, + ChevronDown, + Code, + Heading1, + Heading2, + Heading3, + ListOrdered, + TextIcon, + TextQuote, + type LucideIcon, +} from "lucide-react"; +import { EditorBubbleItem, useEditor } from "novel"; + +type NovelEditor = NonNullable["editor"]>; + +export type SelectorItem = { + name: string; + icon: LucideIcon; + command: (editor: NovelEditor) => void; + isActive: (editor: NovelEditor) => boolean; +}; + +const items: SelectorItem[] = [ + { + name: "Text", + icon: TextIcon, + command: (editor) => editor.chain().focus().clearNodes().run(), + // I feel like there has to be a more efficient way to do this – feel free to PR if you know how! + isActive: (editor) => + editor.isActive("paragraph") && + !editor.isActive("bulletList") && + !editor.isActive("orderedList"), + }, + { + name: "Heading 1", + icon: Heading1, + command: (editor) => + editor.chain().focus().clearNodes().toggleHeading({ level: 1 }).run(), + isActive: (editor) => editor.isActive("heading", { level: 1 }), + }, + { + name: "Heading 2", + icon: Heading2, + command: (editor) => + editor.chain().focus().clearNodes().toggleHeading({ level: 2 }).run(), + isActive: (editor) => editor.isActive("heading", { level: 2 }), + }, + { + name: "Heading 3", + icon: Heading3, + command: (editor) => + editor.chain().focus().clearNodes().toggleHeading({ level: 3 }).run(), + isActive: (editor) => editor.isActive("heading", { level: 3 }), + }, + { + name: "To-do List", + icon: CheckSquare, + command: (editor) => + editor.chain().focus().clearNodes().toggleTaskList().run(), + isActive: (editor) => editor.isActive("taskItem"), + }, + { + name: "Bullet List", + icon: ListOrdered, + command: (editor) => + editor.chain().focus().clearNodes().toggleBulletList().run(), + isActive: (editor) => editor.isActive("bulletList"), + }, + { + name: "Numbered List", + icon: ListOrdered, + command: (editor) => + editor.chain().focus().clearNodes().toggleOrderedList().run(), + isActive: (editor) => editor.isActive("orderedList"), + }, + { + name: "Quote", + icon: TextQuote, + command: (editor) => + editor.chain().focus().clearNodes().toggleBlockquote().run(), + isActive: (editor) => editor.isActive("blockquote"), + }, + { + name: "Code", + icon: Code, + command: (editor) => + editor.chain().focus().clearNodes().toggleCodeBlock().run(), + isActive: (editor) => editor.isActive("codeBlock"), + }, +]; +interface NodeSelectorProps { + open: boolean; + onOpenChange: (open: boolean) => void; +} + +export const NodeSelector = ({ open, onOpenChange }: NodeSelectorProps) => { + const { editor } = useEditor(); + if (!editor) return null; + const activeItem = items.filter((item) => item.isActive(editor)).pop() ?? { + name: "Multiple", + }; + + return ( + + + + + + {items.map((item, index) => ( + { + item.command(editor); + onOpenChange(false); + }} + className="hover:bg-accent flex cursor-pointer items-center justify-between rounded-sm px-2 py-1 text-sm" + > +
+
+ +
+ {item.name} +
+ {activeItem.name === item.name && } +
+ ))} +
+
+ ); +}; diff --git a/examples/with-novel/editor/slash-command.tsx b/examples/with-novel/editor/slash-command.tsx new file mode 100644 index 0000000000..1be463de30 --- /dev/null +++ b/examples/with-novel/editor/slash-command.tsx @@ -0,0 +1,160 @@ +import { uploadFn } from "@/uploadthing/novel-plugin"; +import { + CheckSquare, + Code, + Heading1, + Heading2, + Heading3, + ImageIcon, + List, + ListOrdered, + MessageSquarePlus, + Text, + TextQuote, +} from "lucide-react"; +import { Command, createSuggestionItems, renderItems } from "novel/extensions"; + +export const suggestionItems = createSuggestionItems([ + { + title: "Send Feedback", + description: "Let us know how we can improve.", + icon: , + command: ({ editor, range }) => { + editor.chain().focus().deleteRange(range).run(); + window.open("/feedback", "_blank"); + }, + }, + { + title: "Text", + description: "Just start typing with plain text.", + searchTerms: ["p", "paragraph"], + icon: , + command: ({ editor, range }) => { + editor + .chain() + .focus() + .deleteRange(range) + .toggleNode("paragraph", "paragraph") + .run(); + }, + }, + { + title: "To-do List", + description: "Track tasks with a to-do list.", + searchTerms: ["todo", "task", "list", "check", "checkbox"], + icon: , + command: ({ editor, range }) => { + editor.chain().focus().deleteRange(range).toggleTaskList().run(); + }, + }, + { + title: "Heading 1", + description: "Big section heading.", + searchTerms: ["title", "big", "large"], + icon: , + command: ({ editor, range }) => { + editor + .chain() + .focus() + .deleteRange(range) + .setNode("heading", { level: 1 }) + .run(); + }, + }, + { + title: "Heading 2", + description: "Medium section heading.", + searchTerms: ["subtitle", "medium"], + icon: , + command: ({ editor, range }) => { + editor + .chain() + .focus() + .deleteRange(range) + .setNode("heading", { level: 2 }) + .run(); + }, + }, + { + title: "Heading 3", + description: "Small section heading.", + searchTerms: ["subtitle", "small"], + icon: , + command: ({ editor, range }) => { + editor + .chain() + .focus() + .deleteRange(range) + .setNode("heading", { level: 3 }) + .run(); + }, + }, + { + title: "Bullet List", + description: "Create a simple bullet list.", + searchTerms: ["unordered", "point"], + icon: , + command: ({ editor, range }) => { + editor.chain().focus().deleteRange(range).toggleBulletList().run(); + }, + }, + { + title: "Numbered List", + description: "Create a list with numbering.", + searchTerms: ["ordered"], + icon: , + command: ({ editor, range }) => { + editor.chain().focus().deleteRange(range).toggleOrderedList().run(); + }, + }, + { + title: "Quote", + description: "Capture a quote.", + searchTerms: ["blockquote"], + icon: , + command: ({ editor, range }) => + editor + .chain() + .focus() + .deleteRange(range) + .toggleNode("paragraph", "paragraph") + .toggleBlockquote() + .run(), + }, + { + title: "Code", + description: "Capture a code snippet.", + searchTerms: ["codeblock"], + icon: , + command: ({ editor, range }) => + editor.chain().focus().deleteRange(range).toggleCodeBlock().run(), + }, + { + title: "Image", + description: "Upload an image from your computer.", + searchTerms: ["photo", "picture", "media"], + icon: , + command: ({ editor, range }) => { + editor.chain().focus().deleteRange(range).run(); + // upload image + const input = document.createElement("input"); + input.type = "file"; + input.accept = "image/*"; + input.onchange = async () => { + if (input.files?.length) { + const file = input.files[0]; + const pos = editor.view.state.selection.from; + uploadFn(file!, editor.view, pos); + } + }; + input.click(); + }, + }, +]); + +export const slashCommand = Command.configure({ + suggestion: { + items: () => suggestionItems, + render: renderItems, + }, +}); diff --git a/examples/with-novel/editor/text-buttons.tsx b/examples/with-novel/editor/text-buttons.tsx new file mode 100644 index 0000000000..baf1223af9 --- /dev/null +++ b/examples/with-novel/editor/text-buttons.tsx @@ -0,0 +1,70 @@ +import { Button } from "@/ui/button"; +import { + BoldIcon, + CodeIcon, + ItalicIcon, + StrikethroughIcon, + UnderlineIcon, +} from "lucide-react"; +import { EditorBubbleItem, useEditor } from "novel"; +import { twMerge } from "tailwind-merge"; + +import type { SelectorItem } from "./node-selector"; + +export const TextButtons = () => { + const { editor } = useEditor(); + if (!editor) return null; + const items: SelectorItem[] = [ + { + name: "bold", + isActive: (editor) => editor.isActive("bold"), + command: (editor) => editor.chain().focus().toggleBold().run(), + icon: BoldIcon, + }, + { + name: "italic", + isActive: (editor) => editor.isActive("italic"), + command: (editor) => editor.chain().focus().toggleItalic().run(), + icon: ItalicIcon, + }, + { + name: "underline", + isActive: (editor) => editor.isActive("underline"), + command: (editor) => editor.chain().focus().toggleUnderline().run(), + icon: UnderlineIcon, + }, + { + name: "strike", + isActive: (editor) => editor.isActive("strike"), + command: (editor) => editor.chain().focus().toggleStrike().run(), + icon: StrikethroughIcon, + }, + { + name: "code", + isActive: (editor) => editor.isActive("code"), + command: (editor) => editor.chain().focus().toggleCode().run(), + icon: CodeIcon, + }, + ]; + return ( +
+ {items.map((item, index) => ( + { + item.command(editor); + }} + > + + + ))} +
+ ); +}; diff --git a/examples/with-novel/next-env.d.ts b/examples/with-novel/next-env.d.ts new file mode 100644 index 0000000000..4f11a03dc6 --- /dev/null +++ b/examples/with-novel/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/examples/with-novel/next.config.js b/examples/with-novel/next.config.js new file mode 100644 index 0000000000..c4a407b7ce --- /dev/null +++ b/examples/with-novel/next.config.js @@ -0,0 +1,2 @@ +/** @type {import('next').NextConfig} */ +export default {}; diff --git a/examples/with-novel/package.json b/examples/with-novel/package.json new file mode 100644 index 0000000000..dbe54b2a1f --- /dev/null +++ b/examples/with-novel/package.json @@ -0,0 +1,38 @@ +{ + "name": "with-novel", + "type": "module", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@radix-ui/react-dialog": "^1.0.5", + "@radix-ui/react-popover": "^1.0.6", + "@radix-ui/react-slot": "^1.0.2", + "@tailwindcss/typography": "^0.5.10", + "@uploadthing/react": "^6.5.3", + "class-variance-authority": "^0.7.0", + "cmdk": "^0.2.1", + "lucide-react": "^0.368.0", + "next": "14.2.1", + "next-themes": "^0.3.0", + "novel": "^0.3.1", + "react": "18.2.0", + "react-dom": "18.2.0", + "sonner": "^1.4.41", + "tailwind-merge": "^2.2.1", + "uploadthing": "6.10.3", + "use-debounce": "^9.0.3" + }, + "devDependencies": { + "@types/node": "^20.11.21", + "@types/react": "18.2.78", + "@types/react-dom": "18.2.25", + "tailwindcss": "^3.4.1", + "tailwindcss-animate": "^1.0.7", + "typescript": "^5.4.5" + } +} diff --git a/examples/with-novel/postcss.config.cjs b/examples/with-novel/postcss.config.cjs new file mode 100644 index 0000000000..ee5f90b309 --- /dev/null +++ b/examples/with-novel/postcss.config.cjs @@ -0,0 +1,5 @@ +module.exports = { + plugins: { + tailwindcss: {}, + }, +}; diff --git a/examples/with-novel/tailwind.config.ts b/examples/with-novel/tailwind.config.ts new file mode 100644 index 0000000000..c309c004b7 --- /dev/null +++ b/examples/with-novel/tailwind.config.ts @@ -0,0 +1,79 @@ +import typography from "@tailwindcss/typography"; +import type { Config } from "tailwindcss"; +import animate from "tailwindcss-animate"; + +export default { + darkMode: ["class"], + content: [ + "./app/**/*.{ts,tsx}", + "./editor/**/*.{ts,tsx}", + "./ui/**/*.{ts,tsx}", + ], + prefix: "", + theme: { + container: { + center: true, + padding: "2rem", + screens: { + "2xl": "1400px", + }, + }, + extend: { + colors: { + border: "hsl(var(--border))", + input: "hsl(var(--input))", + ring: "hsl(var(--ring))", + background: "hsl(var(--background))", + foreground: "hsl(var(--foreground))", + primary: { + DEFAULT: "hsl(var(--primary))", + foreground: "hsl(var(--primary-foreground))", + }, + secondary: { + DEFAULT: "hsl(var(--secondary))", + foreground: "hsl(var(--secondary-foreground))", + }, + destructive: { + DEFAULT: "hsl(var(--destructive))", + foreground: "hsl(var(--destructive-foreground))", + }, + muted: { + DEFAULT: "hsl(var(--muted))", + foreground: "hsl(var(--muted-foreground))", + }, + accent: { + DEFAULT: "hsl(var(--accent))", + foreground: "hsl(var(--accent-foreground))", + }, + popover: { + DEFAULT: "hsl(var(--popover))", + foreground: "hsl(var(--popover-foreground))", + }, + card: { + DEFAULT: "hsl(var(--card))", + foreground: "hsl(var(--card-foreground))", + }, + }, + borderRadius: { + lg: "var(--radius)", + md: "calc(var(--radius) - 2px)", + sm: "calc(var(--radius) - 4px)", + }, + keyframes: { + "accordion-down": { + from: { height: "0" }, + to: { height: "var(--radix-accordion-content-height)" }, + }, + "accordion-up": { + from: { height: "var(--radix-accordion-content-height)" }, + to: { height: "0" }, + }, + }, + animation: { + "accordion-down": "accordion-down 0.2s ease-out", + "accordion-up": "accordion-up 0.2s ease-out", + }, + }, + }, + plugins: [animate, typography], +} satisfies Config; diff --git a/examples/with-novel/tsconfig.json b/examples/with-novel/tsconfig.json new file mode 100644 index 0000000000..cd9852d0ad --- /dev/null +++ b/examples/with-novel/tsconfig.json @@ -0,0 +1,36 @@ +{ + "compilerOptions": { + /* Base Options: */ + "skipLibCheck": true, + "target": "es2022", + "allowJs": true, + "moduleDetection": "force", + "isolatedModules": true, + + /* Strictness */ + "strict": true, + "noUncheckedIndexedAccess": true, + "checkJs": true, + + /* Bundled projects */ + "lib": ["dom", "dom.iterable", "ES2022"], + "noEmit": true, + "module": "Preserve", + "jsx": "preserve", + "plugins": [{ "name": "next" }], + "incremental": true, + + /* Path Aliases */ + "paths": { + "@/*": ["./*"] + } + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + "*.js", + ".next/types/**/*.ts" + ], + "exclude": ["node_modules"] +} diff --git a/examples/with-novel/ui/button.tsx b/examples/with-novel/ui/button.tsx new file mode 100644 index 0000000000..55bec375ed --- /dev/null +++ b/examples/with-novel/ui/button.tsx @@ -0,0 +1,55 @@ +import * as React from "react"; +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; +import { twMerge } from "tailwind-merge"; + +const buttonVariants = cva( + "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground hover:bg-destructive/90", + outline: + "border border-input bg-background hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-10 px-4 py-2", + sm: "h-9 rounded-md px-3", + lg: "h-11 rounded-md px-8", + icon: "h-10 w-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + }, +); + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean; +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button"; + return ( + + ); + }, +); +Button.displayName = "Button"; + +export { Button, buttonVariants }; diff --git a/examples/with-novel/ui/command.tsx b/examples/with-novel/ui/command.tsx new file mode 100644 index 0000000000..d25bfcae0d --- /dev/null +++ b/examples/with-novel/ui/command.tsx @@ -0,0 +1,185 @@ +"use client"; + +import * as React from "react"; +import { Dialog, DialogContent } from "@/ui/dialog"; +import { type DialogProps } from "@radix-ui/react-dialog"; +import { Command as CommandPrimitive } from "cmdk"; +import { twMerge } from "tailwind-merge"; + +const Magic = ({ className }: { className: string }) => ( + + + + + +); + +const Command = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +Command.displayName = CommandPrimitive.displayName; + +interface CommandDialogProps extends DialogProps {} + +const CommandDialog = ({ children, ...props }: CommandDialogProps) => { + return ( + + + + {children} + + + + ); +}; + +const CommandInput = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( +
+ + +
+)); + +CommandInput.displayName = CommandPrimitive.Input.displayName; + +const CommandList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); + +CommandList.displayName = CommandPrimitive.List.displayName; + +const CommandEmpty = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>((props, ref) => ( + +)); + +CommandEmpty.displayName = CommandPrimitive.Empty.displayName; + +const CommandGroup = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); + +CommandGroup.displayName = CommandPrimitive.Group.displayName; + +const CommandSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +CommandSeparator.displayName = CommandPrimitive.Separator.displayName; + +const CommandItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); + +CommandItem.displayName = CommandPrimitive.Item.displayName; + +const CommandShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ); +}; +CommandShortcut.displayName = "CommandShortcut"; + +export { + Command, + CommandDialog, + CommandInput, + CommandList, + CommandEmpty, + CommandGroup, + CommandItem, + CommandShortcut, + CommandSeparator, +}; diff --git a/examples/with-novel/ui/dialog.tsx b/examples/with-novel/ui/dialog.tsx new file mode 100644 index 0000000000..5e52628d86 --- /dev/null +++ b/examples/with-novel/ui/dialog.tsx @@ -0,0 +1,121 @@ +"use client"; + +import * as React from "react"; +import * as DialogPrimitive from "@radix-ui/react-dialog"; +import { X } from "lucide-react"; +import { twMerge } from "tailwind-merge"; + +const Dialog = DialogPrimitive.Root; + +const DialogTrigger = DialogPrimitive.Trigger; + +const DialogPortal = DialogPrimitive.Portal; + +const DialogClose = DialogPrimitive.Close; + +const DialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)); +DialogContent.displayName = DialogPrimitive.Content.displayName; + +const DialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +DialogHeader.displayName = "DialogHeader"; + +const DialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +DialogFooter.displayName = "DialogFooter"; + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogTitle.displayName = DialogPrimitive.Title.displayName; + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogDescription.displayName = DialogPrimitive.Description.displayName; + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogClose, + DialogTrigger, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +}; diff --git a/examples/with-novel/ui/popover.tsx b/examples/with-novel/ui/popover.tsx new file mode 100644 index 0000000000..a38d9036d4 --- /dev/null +++ b/examples/with-novel/ui/popover.tsx @@ -0,0 +1,30 @@ +"use client"; + +import * as React from "react"; +import * as PopoverPrimitive from "@radix-ui/react-popover"; +import { twMerge } from "tailwind-merge"; + +const Popover = PopoverPrimitive.Root; + +const PopoverTrigger = PopoverPrimitive.Trigger; + +const PopoverContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( + + + +)); +PopoverContent.displayName = PopoverPrimitive.Content.displayName; + +export { Popover, PopoverTrigger, PopoverContent }; diff --git a/examples/with-novel/uploadthing/client.ts b/examples/with-novel/uploadthing/client.ts new file mode 100644 index 0000000000..2a8e4243f2 --- /dev/null +++ b/examples/with-novel/uploadthing/client.ts @@ -0,0 +1,6 @@ +import { generateReactHelpers } from "@uploadthing/react"; + +import type { UploadRouter } from "./server"; + +export const { uploadFiles, getRouteConfig } = + generateReactHelpers(); diff --git a/examples/with-novel/uploadthing/novel-plugin.ts b/examples/with-novel/uploadthing/novel-plugin.ts new file mode 100644 index 0000000000..3175fb5193 --- /dev/null +++ b/examples/with-novel/uploadthing/novel-plugin.ts @@ -0,0 +1,62 @@ +import { createImageUpload } from "novel/plugins"; +import { toast } from "sonner"; + +import { isValidFileSize, isValidFileType } from "uploadthing/client"; + +import { getRouteConfig, uploadFiles } from "./client"; + +const preloadImage = (url: string, tries = 0, maxTries = 10) => + new Promise((resolve, reject) => { + const image = new Image(); + image.src = url; + image.onload = () => resolve(url); + image.onerror = (e) => { + if (tries < maxTries) { + preloadImage(url, ++tries).then(resolve); + } else { + toast.error( + "Image was uploaded, but failed to preload. Please refresh your browser, and try again.", + ); + reject(e); + } + }; + }); + +export const uploadFn = createImageUpload({ + onUpload: (file) => { + /** + * Upload the file to the server and preload the image in the browser + */ + const uploadPromise = uploadFiles("imageUploader", { + files: [file], + skipPolling: true, + }); + + return new Promise((resolve) => { + toast.promise( + uploadPromise.then(async (res) => { + const [uploadedFileData] = res; + const imageUrl = await preloadImage(uploadedFileData!.url); + resolve(imageUrl); + }), + { + loading: "Uploading image...", + success: "Image uploaded successfully.", + error: (e) => e.message, + }, + ); + }); + }, + validateFn: (file) => { + const config = getRouteConfig("imageUploader"); + if (!isValidFileType(file, config)) { + toast.error("File type not supported."); + return false; + } + if (!isValidFileSize(file, config)) { + toast.error("File size too big."); + return false; + } + return true; + }, +}); diff --git a/examples/with-novel/uploadthing/server.ts b/examples/with-novel/uploadthing/server.ts new file mode 100644 index 0000000000..5151253a22 --- /dev/null +++ b/examples/with-novel/uploadthing/server.ts @@ -0,0 +1,26 @@ +import { createUploadthing, FileRouter } from "uploadthing/next"; + +const f = createUploadthing({ + /** + * Log out more information about the error, but don't return it to the client + * @see https://docs.uploadthing.com/errors#error-formatting + */ + errorFormatter: (err) => { + console.log("Error uploading file", err.message); + console.log(" - Above error caused by:", err.cause); + + return { message: err.message }; + }, +}); + +export const uploadRouter = { + imageUploader: f({ image: { maxFileSize: "1MB", maxFileCount: 4 } }) + .middleware(() => { + return {}; + }) + .onUploadComplete(({ file }) => { + console.log("upload completed", file); + }), +} satisfies FileRouter; + +export type UploadRouter = typeof uploadRouter; diff --git a/packages/react/src/components/button.tsx b/packages/react/src/components/button.tsx index 151875beb5..6bb2227934 100644 --- a/packages/react/src/components/button.tsx +++ b/packages/react/src/components/button.tsx @@ -1,6 +1,6 @@ "use client"; -import { useEffect, useRef, useState } from "react"; +import { useMemo, useRef, useState } from "react"; import { twMerge } from "tailwind-merge"; import { @@ -22,6 +22,7 @@ import type { FileRouter } from "uploadthing/types"; import type { UploadthingComponentProps } from "../types"; import { INTERNAL_uploadthingHookGen } from "../useUploadThing"; +import { usePaste } from "../utils/usePaste"; import { progressWidths, Spinner } from "./shared"; type ButtonStyleFieldCallbackArgs = { @@ -64,9 +65,17 @@ export type UploadButtonProps< content?: ButtonContent; }; +/** These are some internal stuff we use to test the component and for forcing a state in docs */ +type UploadThingInternalProps = { + __internal_state?: "readying" | "ready" | "uploading"; + __internal_upload_progress?: number; + __internal_button_disabled?: boolean; +}; + /** + * @remarks It is not recommended using this directly as it requires manually binding generics. Instead, use `createUploadButton`. * @example - * + * * endpoint="someEndpoint" * onUploadComplete={(res) => console.log(res)} * onUploadError={(err) => console.log(err)} @@ -87,17 +96,8 @@ export function UploadButton< TRouter, TEndpoint, TSkipPolling - > & { - // props not exposed on public type - // Allow to set internal state for testing - __internal_state?: "readying" | "ready" | "uploading"; - // Allow to set upload progress for testing - __internal_upload_progress?: number; - // Allow to set ready explicitly and independently of internal state - __internal_ready?: boolean; - // Allow to disable the button - __internal_button_disabled?: boolean; - }; + > & + UploadThingInternalProps; const { mode = "auto", appendOnPaste = false } = $props.config ?? {}; @@ -107,16 +107,12 @@ export function UploadButton< const fileInputRef = useRef(null); const labelRef = useRef(null); - const [uploadProgressState, setUploadProgress] = useState( + const [uploadProgress, setUploadProgress] = useState( $props.__internal_upload_progress ?? 0, ); const [files, setFiles] = useState([]); - const [isManualTriggerDisplayed, setIsManualTriggerDisplayed] = - useState(false); - const uploadProgress = - $props.__internal_upload_progress ?? uploadProgressState; - const { startUpload, isUploading, permittedFileInfo } = useUploadThing( + const { startUpload, isUploading, routeConfig } = useUploadThing( $props.endpoint, { headers: $props.headers, @@ -125,7 +121,6 @@ export function UploadButton< if (fileInputRef.current) { fileInputRef.current.value = ""; } - setIsManualTriggerDisplayed(false); setFiles([]); $props.onClientUploadComplete?.(res); setUploadProgress(0); @@ -140,95 +135,96 @@ export function UploadButton< }, ); - const { fileTypes, multiple } = generatePermittedFileTypes( - permittedFileInfo?.config, - ); + const { fileTypes, multiple } = generatePermittedFileTypes(routeConfig); - const ready = - $props.__internal_ready ?? - ($props.__internal_state === "ready" || fileTypes.length > 0); + const fileRouteInput = "input" in $props ? $props.input : undefined; + const inputProps = useMemo( + () => ({ + type: "file", + ref: fileInputRef, + multiple, + accept: generateMimeTypes(fileTypes).join(", "), + onChange: (e: React.ChangeEvent) => { + if (!e.target.files) return; + const selectedFiles = Array.from(e.target.files); - useEffect(() => { - const handlePaste = (event: ClipboardEvent) => { - if (!appendOnPaste) return; - if (document.activeElement !== labelRef.current) return; + if (mode === "manual") { + setFiles(selectedFiles); + return; + } - const pastedFiles = getFilesFromClipboardEvent(event); - if (!pastedFiles) return; + void startUpload(selectedFiles, fileRouteInput); + }, + disabled: fileTypes.length === 0, + tabIndex: fileTypes.length === 0 ? -1 : 0, + }), + [fileRouteInput, fileTypes, mode, multiple, startUpload], + ); - setFiles((prev) => [...prev, ...pastedFiles]); + if ($props.__internal_button_disabled) inputProps.disabled = true; - if (mode === "auto") { - const input = "input" in $props ? $props.input : undefined; - void startUpload(files, input); - } - }; - - window.addEventListener("paste", handlePaste); - return () => { - window.removeEventListener("paste", handlePaste); - }; - }, [startUpload, appendOnPaste, $props, files, mode, fileTypes]); - - const getUploadButtonText = (fileTypes: string[]) => { - if (isManualTriggerDisplayed) - return `Upload ${files.length} file${files.length === 1 ? "" : "s"}`; - if (fileTypes.length === 0) return "Loading..."; - return `Choose File${multiple ? `(s)` : ``}`; - }; + const state = (() => { + if ($props.__internal_state) return $props.__internal_state; + if (inputProps.disabled) return "readying"; + if (!inputProps.disabled && !isUploading) return "ready"; + return "uploading"; + })(); - const getUploadButtonContents = (fileTypes: string[]) => { - if (state !== "uploading") { - return getUploadButtonText(fileTypes); - } - if (uploadProgress === 100) { - return ; - } - return {uploadProgress}%; - }; + usePaste((event) => { + if (!appendOnPaste) return; + if (document.activeElement !== fileInputRef.current) return; - const getInputProps = () => ({ - type: "file", - ref: fileInputRef, - multiple, - accept: generateMimeTypes(fileTypes).join(", "), - onChange: (e: React.ChangeEvent) => { - if (!e.target.files) return; - const selectedFiles = Array.from(e.target.files); - - if (mode === "manual") { - setFiles(selectedFiles); - setIsManualTriggerDisplayed(true); - return; - } + const pastedFiles = getFilesFromClipboardEvent(event); + if (!pastedFiles) return; + + let filesToUpload = pastedFiles; + setFiles((prev) => { + filesToUpload = [...prev, ...pastedFiles]; + return filesToUpload; + }); + if (mode === "auto") { const input = "input" in $props ? $props.input : undefined; - void startUpload(selectedFiles, input); - }, - disabled: $props.__internal_button_disabled ?? !ready, - ...(!($props.__internal_button_disabled ?? !ready) ? { tabIndex: 0 } : {}), + void startUpload(files, input); + } }); const styleFieldArg = { - ready: ready, - isUploading: $props.__internal_state === "uploading" || isUploading, + ready: state !== "readying", + isUploading: state === "uploading", uploadProgress, fileTypes, } as ButtonStyleFieldCallbackArgs; - const state = (() => { - if ($props.__internal_state) return $props.__internal_state; - if (!ready) return "readying"; - if (ready && !isUploading) return "ready"; + const renderButton = () => { + const customContent = contentFieldToContent( + $props.content?.button, + styleFieldArg, + ); + if (customContent) return customContent; - return "uploading"; - })(); + if (state === "readying") { + return "Loading..."; + } + + if (state !== "uploading") { + if (mode === "manual" && files.length > 0) { + return `Upload ${files.length} file${files.length === 1 ? "" : "s"}`; + } + return `Choose File${inputProps.multiple ? `(s)` : ``}`; + } + + if (uploadProgress === 100) { + return ; + } + + return {uploadProgress}%; + }; const renderClearButton = () => (
); @@ -289,7 +285,7 @@ export function UploadButton< data-ut-element="button" ref={labelRef} onClick={(e) => { - if (isManualTriggerDisplayed) { + if (mode === "manual" && files.length > 0) { e.preventDefault(); e.stopPropagation(); const input = "input" in $props ? $props.input : undefined; @@ -297,9 +293,8 @@ export function UploadButton< } }} > - - {contentFieldToContent($props.content?.button, styleFieldArg) ?? - getUploadButtonContents(fileTypes)} + + {renderButton()} {mode === "manual" && files.length > 0 ? renderClearButton() diff --git a/packages/react/src/useUploadThing.ts b/packages/react/src/useUploadThing.ts index a8c667e46c..0e3a755d2e 100644 --- a/packages/react/src/useUploadThing.ts +++ b/packages/react/src/useUploadThing.ts @@ -1,6 +1,9 @@ import { useRef, useState } from "react"; -import type { EndpointMetadata } from "@uploadthing/shared"; +import type { + EndpointMetadata, + ExpandedRouteConfig, +} from "@uploadthing/shared"; import { INTERNAL_DO_NOT_USE__fatalClientError, resolveMaybeUrlArg, @@ -26,13 +29,16 @@ declare const globalThis: { __UPLOADTHING?: EndpointMetadata; }; -const useEndpointMetadata = (url: URL, endpoint: string) => { +const useRouteConfig = ( + url: URL, + endpoint: string, +): ExpandedRouteConfig | undefined => { const maybeServerData = globalThis.__UPLOADTHING; const { data } = useFetch( // Don't fetch if we already have the data maybeServerData ? undefined : url.href, ); - return (maybeServerData ?? data)?.find((x) => x.slug === endpoint); + return (maybeServerData ?? data)?.find((x) => x.slug === endpoint)?.config; }; export const INTERNAL_uploadthingHookGen = < @@ -66,11 +72,6 @@ export const INTERNAL_uploadthingHookGen = < const uploadProgress = useRef(0); const fileProgress = useRef>(new Map()); - const permittedFileInfo = useEndpointMetadata( - initOpts.url, - endpoint as string, - ); - type InferredInput = inferEndpointInput; type FuncInput = undefined extends InferredInput ? [files: File[], input?: undefined] @@ -131,10 +132,19 @@ export const INTERNAL_uploadthingHookGen = < } }); + const routeConfig = useRouteConfig(initOpts.url, endpoint as string); + return { startUpload, isUploading, - permittedFileInfo, + routeConfig, + + /** + * @deprecated Use `routeConfig` instead + */ + permittedFileInfo: routeConfig + ? { slug: endpoint, config: routeConfig } + : undefined, } as const; }; @@ -146,11 +156,28 @@ export const generateReactHelpers = ( ) => { const url = resolveMaybeUrlArg(initOpts?.url); + const getRouteConfig = (endpoint: keyof TRouter) => { + const maybeServerData = globalThis.__UPLOADTHING; + const config = maybeServerData?.find((x) => x.slug === endpoint)?.config; + if (!config) { + throw new Error( + `No config found for endpoint "${endpoint.toString()}". Please make sure to use the NextSSRPlugin in your Next.js app.`, + ); + } + return config; + }; + return { useUploadThing: INTERNAL_uploadthingHookGen({ url }), uploadFiles: genUploader({ url, package: "@uploadthing/react", }), + + /** + * Get the config for a given endpoint outside of React context. + * @remarks Can only be used if the NextSSRPlugin is used in the app. + */ + getRouteConfig, } as const; }; diff --git a/packages/react/src/utils/usePaste.ts b/packages/react/src/utils/usePaste.ts new file mode 100644 index 0000000000..5d728fe0c7 --- /dev/null +++ b/packages/react/src/utils/usePaste.ts @@ -0,0 +1,15 @@ +import { useEffect } from "react"; + +import { useEvent } from "./useEvent"; + +type PasteCallback = (event: ClipboardEvent) => void; +export const usePaste = (callback: PasteCallback) => { + const stableCallback = useEvent(callback); + + useEffect(() => { + window.addEventListener("paste", stableCallback); + return () => { + window.removeEventListener("paste", stableCallback); + }; + }, [stableCallback]); +}; diff --git a/packages/uploadthing/src/client.ts b/packages/uploadthing/src/client.ts index b816d79e4e..4777a340b3 100644 --- a/packages/uploadthing/src/client.ts +++ b/packages/uploadthing/src/client.ts @@ -6,13 +6,20 @@ import { unsafeCoerce } from "effect/Function"; import * as Option from "effect/Option"; import * as Runtime from "effect/Runtime"; -import type { FetchError, InvalidJsonError } from "@uploadthing/shared"; +import type { + ExpandedRouteConfig, + FetchError, + InvalidJsonError, +} from "@uploadthing/shared"; import { exponentialBackoff, FetchContext, fetchEff, + fileSizeToBytes, getErrorTypeFromStatusCode, + getTypeFromFileName, isObject, + objectKeys, parseResponseJson, resolveMaybeUrlArg, RetryError, @@ -37,6 +44,8 @@ import type { UploadFilesOptions, } from "./types"; +export const version = pkgJson.version; + export { /** @public */ generateClientDropzoneAccept, @@ -46,7 +55,36 @@ export { generatePermittedFileTypes, } from "@uploadthing/shared"; -export const version = pkgJson.version; +/** + * Validate that a file is of a valid type given a route config + * @public + */ +export const isValidFileType = ( + file: File, + routeConfig: ExpandedRouteConfig, +): boolean => + Effect.runSync( + getTypeFromFileName(file.name, objectKeys(routeConfig)).pipe( + Effect.flatMap((type) => Effect.succeed(file.type.includes(type))), + Effect.catchAll(() => Effect.succeed(false)), + ), + ); + +/** + * Validate that a file is of a valid size given a route config + * @public + */ +export const isValidFileSize = ( + file: File, + routeConfig: ExpandedRouteConfig, +): boolean => + Effect.runSync( + getTypeFromFileName(file.name, objectKeys(routeConfig)).pipe( + Effect.flatMap((type) => fileSizeToBytes(routeConfig[type]!.maxFileSize)), + Effect.flatMap((maxFileSize) => Effect.succeed(file.size <= maxFileSize)), + Effect.catchAll(() => Effect.succeed(false)), + ), + ); const uploadFilesInternal = < TRouter extends FileRouter, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e64f0c48c7..39c6c8b580 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -680,6 +680,79 @@ importers: specifier: ^5.4.5 version: 5.4.5 + examples/with-novel: + dependencies: + '@radix-ui/react-dialog': + specifier: ^1.0.5 + version: 1.0.5(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-popover': + specifier: ^1.0.6 + version: 1.0.7(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': + specifier: ^1.0.2 + version: 1.0.2(@types/react@18.2.78)(react@18.2.0) + '@tailwindcss/typography': + specifier: ^0.5.10 + version: 0.5.13(tailwindcss@3.4.3) + '@uploadthing/react': + specifier: ^6.5.3 + version: link:../../packages/react + class-variance-authority: + specifier: ^0.7.0 + version: 0.7.0 + cmdk: + specifier: ^0.2.1 + version: 0.2.1(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + lucide-react: + specifier: ^0.368.0 + version: 0.368.0(react@18.2.0) + next: + specifier: 14.2.1 + version: 14.2.1(@babel/core@7.24.4)(react-dom@18.2.0)(react@18.2.0) + next-themes: + specifier: ^0.3.0 + version: 0.3.0(react-dom@18.2.0)(react@18.2.0) + novel: + specifier: ^0.3.1 + version: 0.3.1(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + react: + specifier: 18.2.0 + version: 18.2.0 + react-dom: + specifier: 18.2.0 + version: 18.2.0(react@18.2.0) + sonner: + specifier: ^1.4.41 + version: 1.4.41(react-dom@18.2.0)(react@18.2.0) + tailwind-merge: + specifier: ^2.2.1 + version: 2.3.0 + uploadthing: + specifier: 6.10.3 + version: link:../../packages/uploadthing + use-debounce: + specifier: ^9.0.3 + version: 9.0.4(react@18.2.0) + devDependencies: + '@types/node': + specifier: ^20.11.21 + version: 20.12.7 + '@types/react': + specifier: 18.2.78 + version: 18.2.78 + '@types/react-dom': + specifier: 18.2.25 + version: 18.2.25 + tailwindcss: + specifier: ^3.4.1 + version: 3.4.3 + tailwindcss-animate: + specifier: ^1.0.7 + version: 1.0.7(tailwindcss@3.4.3) + typescript: + specifier: ^5.4.5 + version: 5.4.5 + examples/with-react-image-crop: dependencies: '@uploadthing/react': @@ -1267,7 +1340,7 @@ importers: version: link:../tsconfig tsup: specifier: 8.0.2 - version: 8.0.2(postcss@8.4.38)(typescript@5.4.5) + version: 8.0.2(typescript@5.4.5) typescript: specifier: ^5.4.5 version: 5.4.5 @@ -1283,7 +1356,6 @@ packages: /@alloc/quick-lru@5.2.0: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} - dev: true /@ampproject/remapping@2.2.1: resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} @@ -2005,6 +2077,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.14.0 + dev: false /@babel/runtime@7.24.4: resolution: {integrity: sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==} @@ -2107,10 +2180,16 @@ packages: statuses: 2.0.1 dev: false + /@cfcs/core@0.0.6: + resolution: {integrity: sha512-FxfJMwoLB8MEMConeXUCqtMGqxdtePQxRBOiGip9ULcYYam3WfCgoY6xdnMaSkYvRvmosp5iuG+TiPofm65+Pw==} + dependencies: + '@egjs/component': 3.0.5 + dev: false + /@changesets/apply-release-plan@7.0.0: resolution: {integrity: sha512-vfi69JR416qC9hWmFGSxj7N6wA5J222XNBmezSVATPWDVPIF7gkd4d8CpbEbXmRWbVrkoli3oerGS6dcL/BGsQ==} dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.24.4 '@changesets/config': 3.0.0 '@changesets/get-version-range-type': 0.4.0 '@changesets/git': 3.0.0 @@ -2128,7 +2207,7 @@ packages: /@changesets/assemble-release-plan@6.0.0: resolution: {integrity: sha512-4QG7NuisAjisbW4hkLCmGW2lRYdPrKzro+fCtZaILX+3zdUELSvYjpL4GTv0E4aM9Mef3PuIQp89VmHJ4y2bfw==} dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.24.4 '@changesets/errors': 0.2.0 '@changesets/get-dependents-graph': 2.0.0 '@changesets/types': 6.0.0 @@ -2230,7 +2309,7 @@ packages: /@changesets/get-release-plan@4.0.0: resolution: {integrity: sha512-9L9xCUeD/Tb6L/oKmpm8nyzsOzhdNBBbt/ZNcjynbHC07WW4E1eX8NMGC5g5SbM5z/V+MOrYsJ4lRW41GCbg3w==} dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.24.4 '@changesets/assemble-release-plan': 6.0.0 '@changesets/config': 3.0.0 '@changesets/pre': 2.0.0 @@ -2246,7 +2325,7 @@ packages: /@changesets/git@3.0.0: resolution: {integrity: sha512-vvhnZDHe2eiBNRFHEgMiGd2CT+164dfYyrJDhwwxTVD/OW0FUD6G7+4DIx1dNwkwjHyzisxGAU96q0sVNBns0w==} dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.24.4 '@changesets/errors': 0.2.0 '@changesets/types': 6.0.0 '@manypkg/get-packages': 1.1.3 @@ -2271,7 +2350,7 @@ packages: /@changesets/pre@2.0.0: resolution: {integrity: sha512-HLTNYX/A4jZxc+Sq8D1AMBsv+1qD6rmmJtjsCJa/9MSRybdxh0mjbTvE6JYZQ/ZiQ0mMlDOlGPXTm9KLTU3jyw==} dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.24.4 '@changesets/errors': 0.2.0 '@changesets/types': 6.0.0 '@manypkg/get-packages': 1.1.3 @@ -2281,7 +2360,7 @@ packages: /@changesets/read@0.6.0: resolution: {integrity: sha512-ZypqX8+/im1Fm98K4YcZtmLKgjs1kDQ5zHpc2U1qdtNBmZZfo/IBiG162RoP0CUF05tvp2y4IspH11PLnPxuuw==} dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.24.4 '@changesets/git': 3.0.0 '@changesets/logger': 0.1.0 '@changesets/parse': 0.4.0 @@ -2302,7 +2381,7 @@ packages: /@changesets/write@0.3.0: resolution: {integrity: sha512-slGLb21fxZVUYbyea+94uFiD6ntQW0M2hIKNznFizDhZPDgn2c/fv1UzzlW43RVzh1BEDuIqW6hzlJ1OflNmcw==} dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.24.4 '@changesets/types': 6.0.0 fs-extra: 7.0.1 human-id: 1.0.2 @@ -2577,6 +2656,10 @@ packages: '@jridgewell/trace-mapping': 0.3.9 dev: true + /@daybrush/utils@1.13.0: + resolution: {integrity: sha512-ALK12C6SQNNHw1enXK+UO8bdyQ+jaWNQ1Af7Z3FNxeAwjYhQT7do+TRE4RASAJ3ObaS2+TJ7TXR3oz2Gzbw0PQ==} + dev: false + /@deno/shim-deno-test@0.5.0: resolution: {integrity: sha512-4nMhecpGlPi0cSzT67L+Tm+GOJqvuk8gqHBziqcUQOarnuIax1z96/gJHCSIz2Z0zhxE6Rzwb3IZXPtFh51j+w==} dev: false @@ -2603,6 +2686,24 @@ packages: fast-check: 3.18.0 dev: false + /@egjs/agent@2.4.3: + resolution: {integrity: sha512-XvksSENe8wPeFlEVouvrOhKdx8HMniJ3by7sro2uPF3M6QqWwjzVcmvwoPtdjiX8O1lfRoLhQMp1a7NGlVTdIA==} + dev: false + + /@egjs/children-differ@1.0.1: + resolution: {integrity: sha512-DRvyqMf+CPCOzAopQKHtW+X8iN6Hy6SFol+/7zCUiE5y4P/OB8JP8FtU4NxtZwtafvSL4faD5KoQYPj3JHzPFQ==} + dependencies: + '@egjs/list-differ': 1.0.1 + dev: false + + /@egjs/component@3.0.5: + resolution: {integrity: sha512-cLcGizTrrUNA2EYE3MBmEDt2tQv1joVP1Q3oDisZ5nw0MZDx2kcgEXM+/kZpfa/PAkFvYVhRUZwytIQWoN3V/w==} + dev: false + + /@egjs/list-differ@1.0.1: + resolution: {integrity: sha512-OTFTDQcWS+1ZREOdCWuk5hCBgYO4OsD30lXcOCyVOAjXMhgL5rBRDnt/otb6Nz8CzU0L/igdcaQBDLWc4t9gvg==} + dev: false + /@elysiajs/cors@0.8.0(elysia@0.8.17): resolution: {integrity: sha512-NADcOsokALRv4nljA5DYJPJdIJ7iwq+ouV5lH5W+hLgZRMYsfbKShg82QSmxd7BJQFuGSv2dIIF2dfG9ieUyng==} peerDependencies: @@ -3700,6 +3801,17 @@ packages: '@floating-ui/utils': 0.2.1 dev: false + /@floating-ui/react-dom@2.0.9(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-q0umO0+LQK4+p6aGyvzASqKbKOJcAHJ7ycE9CuUvfx3s9zTHWmGJTPOIlM/hmSBfUfg/XfY5YhLBLR/LHwShQQ==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + dependencies: + '@floating-ui/dom': 1.6.3 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@floating-ui/utils@0.2.1: resolution: {integrity: sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==} dev: false @@ -4133,7 +4245,7 @@ packages: /@manypkg/find-root@1.1.0: resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.24.4 '@types/node': 12.20.55 find-up: 4.1.0 fs-extra: 8.1.0 @@ -4151,7 +4263,7 @@ packages: /@manypkg/get-packages@1.1.3: resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.24.4 '@changesets/types': 4.1.0 '@manypkg/find-root': 1.1.0 fs-extra: 8.1.0 @@ -5652,6 +5764,12 @@ packages: prettier: 3.2.5 dev: false + /@radix-ui/primitive@1.0.0: + resolution: {integrity: sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA==} + dependencies: + '@babel/runtime': 7.24.4 + dev: false + /@radix-ui/primitive@1.0.1: resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==} dependencies: @@ -5687,6 +5805,27 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-arrow@1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-wSP+pHsB/jQRaL6voubsQ/ZlrGBHHrOjmBnr19hxYgtS0WvAFwZhK2WP/YY5yF9uKECCEEDGxuLxq1NBK51wFA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.78 + '@types/react-dom': 18.2.25 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /@radix-ui/react-collapsible@1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-UBmVDkmR6IvDsloHVN+3rtx4Mi5TFvylYXpluuv0f37dtaz3H99bp8No0LGXRigVpl3UAT4l9j6bIchh42S/Gg==} peerDependencies: @@ -5739,6 +5878,15 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /@radix-ui/react-compose-refs@1.0.0(react@18.2.0): + resolution: {integrity: sha512-0KaSv6sx787/hK3eF53iOkiSLwAGlFMx5lotrqD2pTjB18KbybKoEIgkNZTKC60YECDQTKGTRcDBILwZVqVKvA==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.4 + react: 18.2.0 + dev: false + /@radix-ui/react-compose-refs@1.0.1(@types/react@18.2.78)(react@18.2.0): resolution: {integrity: sha512-fDSBgd44FKHa1FRMU59qBMPFcl2PZE+2nmqunj+BWFyYYjnhIDWL2ItDs3rrbJDQOtzt5nIebLCQc4QRfz6LJw==} peerDependencies: @@ -5753,6 +5901,15 @@ packages: react: 18.2.0 dev: false + /@radix-ui/react-context@1.0.0(react@18.2.0): + resolution: {integrity: sha512-1pVM9RfOQ+n/N5PJK33kRSKsr1glNxomxONs5c49MliinBY6Yw2Q995qfBUUo0/Mbg05B/sGA0gkgPI7kmSHBg==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.4 + react: 18.2.0 + dev: false + /@radix-ui/react-context@1.0.1(@types/react@18.2.78)(react@18.2.0): resolution: {integrity: sha512-ebbrdFoYTcuZ0v4wG5tedGnp9tzcV8awzsxYph7gXUyvnNLuTIcCk1q17JEbnVhXAKG9oX3KtchwiMIAYp9NLg==} peerDependencies: @@ -5767,22 +5924,69 @@ packages: react: 18.2.0 dev: false - /@radix-ui/react-direction@1.0.1(@types/react@18.2.78)(react@18.2.0): - resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==} + /@radix-ui/react-dialog@1.0.0(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Yn9YU+QlHYLWwV1XfKiqnGVpWYWk6MeBVM6x/bcoyPvxgjQGoeT35482viLPctTMWoMw0PoHgqfSox7Ig+957Q==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/primitive': 1.0.0 + '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) + '@radix-ui/react-context': 1.0.0(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.0(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-guards': 1.0.0(react@18.2.0) + '@radix-ui/react-focus-scope': 1.0.0(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.0.0(react@18.2.0) + '@radix-ui/react-portal': 1.0.0(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.0.0(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.0.0(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.0(react@18.2.0) + aria-hidden: 1.2.4 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-remove-scroll: 2.5.4(@types/react@18.2.78)(react@18.2.0) + transitivePeerDependencies: + - '@types/react' + dev: false + + /@radix-ui/react-dialog@1.0.5(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-GjWJX/AUpB703eEBanuBnIWdIXg6NvJFCXcNlSZk4xdszCdhrJgBoUd1cGk67vFO+WdA2pfI/plOpqz/5GUP6Q==} peerDependencies: '@types/react': '*' + '@types/react-dom': '*' react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: '@types/react': optional: true + '@types/react-dom': + optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.24.4 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.78)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.78)(react@18.2.0) '@types/react': 18.2.78 + '@types/react-dom': 18.2.25 + aria-hidden: 1.2.4 react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-remove-scroll: 2.5.5(@types/react@18.2.78)(react@18.2.0) dev: false - /@radix-ui/react-id@1.0.1(@types/react@18.2.78)(react@18.2.0): - resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==} + /@radix-ui/react-direction@1.0.1(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-RXcvnXgyvYvBEOhCBuddKecVkoMiI10Jcm5cTI7abJRAHYfFxeu+FBQs/DvdxSYucxR5mna0dNsL6QFlds5TMA==} peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 @@ -5791,13 +5995,28 @@ packages: optional: true dependencies: '@babel/runtime': 7.22.10 - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.78)(react@18.2.0) '@types/react': 18.2.78 react: 18.2.0 dev: false - /@radix-ui/react-presence@1.0.1(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==} + /@radix-ui/react-dismissable-layer@1.0.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-n7kDRfx+LB1zLueRDvZ1Pd0bxdJWDUZNQ/GWoxDn2prnuJKRdxsjulejX/ePkOsLi2tTm6P24mDqlMSgQpsT6g==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/primitive': 1.0.0 + '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) + '@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.0(react@18.2.0) + '@radix-ui/react-use-escape-keydown': 1.0.0(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-dismissable-layer@1.0.5(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-aJeDjQhywg9LBu2t/At58hCvr7pEm0o2Ke1x33B+MhjNmmZ17sy4KImo0KPLgsnc/zN7GPdce8Cnn0SWvwZO7g==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -5809,53 +6028,90 @@ packages: '@types/react-dom': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.24.4 + '@radix-ui/primitive': 1.0.1 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.78)(react@18.2.0) - '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@radix-ui/react-use-escape-keydown': 1.0.3(@types/react@18.2.78)(react@18.2.0) '@types/react': 18.2.78 '@types/react-dom': 18.2.25 react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} + /@radix-ui/react-focus-guards@1.0.0(react@18.2.0): + resolution: {integrity: sha512-UagjDk4ijOAnGu4WMUPj9ahi7/zJJqNZ9ZAiGPp7waUWJO0O1aWXi/udPphI0IUjvrhBsZJGSN66dR2dsueLWQ==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.4 + react: 18.2.0 + dev: false + + /@radix-ui/react-focus-guards@1.0.1(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-Rect2dWbQ8waGzhMavsIbmSVCgYxkXLxxR3ZvCX79JOglzdEy4JXMb98lq4hPxUbLr77nP0UOGf4rcMU+s1pUA==} peerDependencies: '@types/react': '*' - '@types/react-dom': '*' react: ^16.8 || ^17.0 || ^18.0 - react-dom: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: '@types/react': optional: true - '@types/react-dom': - optional: true dependencies: - '@babel/runtime': 7.22.10 - '@radix-ui/react-slot': 1.0.2(@types/react@18.2.78)(react@18.2.0) + '@babel/runtime': 7.24.4 '@types/react': 18.2.78 - '@types/react-dom': 18.2.25 + react: 18.2.0 + dev: false + + /@radix-ui/react-focus-scope@1.0.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-C4SWtsULLGf/2L4oGeIHlvWQx7Rf+7cX/vKOAD2dXW0A1b5QXwi3wWeaEgW+wn+SEVrraMUk05vLU9fZZz5HbQ==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) + '@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.0(react@18.2.0) react: 18.2.0 react-dom: 18.2.0(react@18.2.0) dev: false - /@radix-ui/react-slot@1.0.2(@types/react@18.2.78)(react@18.2.0): - resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} + /@radix-ui/react-focus-scope@1.0.4(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-sL04Mgvf+FmyvZeYfNu1EPAaaxD+aw7cYeIB9L9Fvq8+urhltTRaEo5ysKOpHuKPclsZcSUMKlN05x4u+CINpA==} peerDependencies: '@types/react': '*' + '@types/react-dom': '*' react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: '@types/react': optional: true + '@types/react-dom': + optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.24.4 '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.78)(react@18.2.0) '@types/react': 18.2.78 + '@types/react-dom': 18.2.25 react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) dev: false - /@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.78)(react@18.2.0): - resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==} + /@radix-ui/react-id@1.0.0(react@18.2.0): + resolution: {integrity: sha512-Q6iAB/U7Tq3NTolBBQbHTgclPmGWE3OlktGGqrClPozSw4vkQ1DfQAOtzgRPecKsMdJINE05iaoDUG8tRzCBjw==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/react-use-layout-effect': 1.0.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@radix-ui/react-id@1.0.1(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-tI7sT/kqYp8p96yGWY1OAnLHrqDgzHefRBKQ2YAkBS5ja7QLcZ9Z/uY7bEjPUatf8RomoXM8/1sMj1IJaE5UzQ==} peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 @@ -5863,48 +6119,347 @@ packages: '@types/react': optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.24.4 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.78)(react@18.2.0) '@types/react': 18.2.78 react: 18.2.0 dev: false - /@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.78)(react@18.2.0): - resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} + /@radix-ui/react-popover@1.0.7(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-shtvVnlsxT6faMnK/a7n0wptwBD23xc1Z5mdrtKLwVEfsEMXodS0r5s0/g5P0hX//EKYZS2sxUjqfzlg52ZSnQ==} peerDependencies: '@types/react': '*' + '@types/react-dom': '*' react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: '@types/react': optional: true + '@types/react-dom': + optional: true dependencies: - '@babel/runtime': 7.22.10 - '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@babel/runtime': 7.24.4 + '@radix-ui/primitive': 1.0.1 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@radix-ui/react-dismissable-layer': 1.0.5(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-focus-guards': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@radix-ui/react-focus-scope': 1.0.4(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-id': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@radix-ui/react-popper': 1.1.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-portal': 1.0.4(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-presence': 1.0.1(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.78)(react@18.2.0) + '@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.78)(react@18.2.0) '@types/react': 18.2.78 + '@types/react-dom': 18.2.25 + aria-hidden: 1.2.4 react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-remove-scroll: 2.5.5(@types/react@18.2.78)(react@18.2.0) dev: false - /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.78)(react@18.2.0): - resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} + /@radix-ui/react-popper@1.1.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-cKpopj/5RHZWjrbF2846jBNacjQVwkP068DfmgrNJXpvVWrOvlAmE9xSiy5OqeE+Gi8D9fP+oDhUnPqNMY8/5w==} peerDependencies: '@types/react': '*' + '@types/react-dom': '*' react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 peerDependenciesMeta: '@types/react': optional: true + '@types/react-dom': + optional: true dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.24.4 + '@floating-ui/react-dom': 2.0.9(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@radix-ui/react-context': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@radix-ui/react-use-rect': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@radix-ui/react-use-size': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@radix-ui/rect': 1.0.1 '@types/react': 18.2.78 + '@types/react-dom': 18.2.25 react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) dev: false - /@replit/codemirror-css-color-picker@6.1.1(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.3): - resolution: {integrity: sha512-e/wYHcgt3HRDpvYuwqXyjv3LEY6VyFjJeDQK1UtFmaykp86R6Cbw3ULH9pvuJuelaW6nS4CVtIRHuOfbFLlqwQ==} + /@radix-ui/react-portal@1.0.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-a8qyFO/Xb99d8wQdu4o7qnigNjTPG123uADNecz0eX4usnQEj7o+cG4ZX4zkqq98NYekT7UoEQIjxBNWIFuqTA==} peerDependencies: - '@codemirror/language': ^6.0.0 - '@codemirror/state': ^6.0.0 - '@codemirror/view': ^6.0.0 + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 dependencies: - '@codemirror/language': 6.10.1 + '@babel/runtime': 7.24.4 + '@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-portal@1.0.4(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-Qki+C/EuGUVCQTOTD5vzJzJuMUlewbzuKyUy+/iHM2uwGiru9gZeBJtHAPKAEkB5KWGi9mP/CHKcY0wt1aW45Q==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + '@types/react': 18.2.78 + '@types/react-dom': 18.2.25 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-presence@1.0.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-A+6XEvN01NfVWiKu38ybawfHsBjWum42MRPnEuqPsBZ4eV7e/7K321B5VgYMPv3Xx5An6o1/l9ZuDBgmcmWK3w==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.0(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-presence@1.0.1(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-UXLW4UAbIY5ZjcvzjfRFo5gxva8QirC9hF7wRE4U5gz+TP0DbRk+//qyuAQ1McDxBt1xNMBTaciFGvEmJvAZCg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@types/react': 18.2.78 + '@types/react-dom': 18.2.25 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-primitive@1.0.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-EyXe6mnRlHZ8b6f4ilTDrXmkLShICIuOTTj0GX4w1rp+wSxf3+TD05u1UOITC8VsJ2a9nwHvdXtOXEOl0Cw/zQ==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/react-slot': 1.0.0(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-primitive@1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-yi58uVyoAcK/Nq1inRY56ZSjKypBNKTa/1mcL8qdl6oJeEaDbOldlzrGn7P6Q3Id5d+SYNGc5AJgc4vGhjs5+g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 + react-dom: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.78)(react@18.2.0) + '@types/react': 18.2.78 + '@types/react-dom': 18.2.25 + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@radix-ui/react-slot@1.0.0(react@18.2.0): + resolution: {integrity: sha512-3mrKauI/tWXo1Ll+gN5dHcxDPdm/Df1ufcDLCecn+pnCIVcdWE7CujXo8QaXOWRJyZyQWWbpB8eFwHzWXlv5mQ==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/react-compose-refs': 1.0.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@radix-ui/react-slot@1.0.2(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-YeTpuq4deV+6DusvVUW4ivBgnkHwECUu0BiN43L5UCDFgdhsRUWAghhTF5MbvNTPzmiFOx90asDSUjWuCNapwg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@types/react': 18.2.78 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-callback-ref@1.0.0(react@18.2.0): + resolution: {integrity: sha512-GZtyzoHz95Rhs6S63D2t/eqvdFCm7I+yHMLVQheKM7nBD8mbZIt+ct1jz4536MDnaOGKIxynJ8eHTkVGVVkoTg==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.4 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-callback-ref@1.0.1(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-D94LjX4Sp0xJFVaoQOd3OO9k7tpBYNOXdVhkltUbGv2Qb9OXdrg/CpsjlZv7ia14Sylv398LswWBVVu5nqKzAQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.4 + '@types/react': 18.2.78 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-controllable-state@1.0.0(react@18.2.0): + resolution: {integrity: sha512-FohDoZvk3mEXh9AWAVyRTYR4Sq7/gavuofglmiXB2g1aKyboUD4YtgWxKj8O5n+Uak52gXQ4wKz5IFST4vtJHg==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/react-use-callback-ref': 1.0.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@radix-ui/react-use-controllable-state@1.0.1(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-Svl5GY5FQeN758fWKrjM6Qb7asvXeiZltlT4U2gVfl8Gx5UAv2sMR0LWo8yhsIZh2oQ0eFdZ59aoOOMV7b47VA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.22.10 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@types/react': 18.2.78 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-escape-keydown@1.0.0(react@18.2.0): + resolution: {integrity: sha512-JwfBCUIfhXRxKExgIqGa4CQsiMemo1Xt0W/B4ei3fpzpvPENKpMKQ8mZSB6Acj3ebrAEgi2xiQvcI1PAAodvyg==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/react-use-callback-ref': 1.0.0(react@18.2.0) + react: 18.2.0 + dev: false + + /@radix-ui/react-use-escape-keydown@1.0.3(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-vyL82j40hcFicA+M4Ex7hVkB9vHgSse1ZWomAqV2Je3RleKGO5iM8KMOEtfoSB0PnIelMd2lATjTGMYqN5ylTg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@types/react': 18.2.78 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-layout-effect@1.0.0(react@18.2.0): + resolution: {integrity: sha512-6Tpkq+R6LOlmQb1R5NNETLG0B4YP0wc+klfXafpUCj6JGyaUc8il7/kUZ7m59rGbXGczE9Bs+iz2qloqsZBduQ==} + peerDependencies: + react: ^16.8 || ^17.0 || ^18.0 + dependencies: + '@babel/runtime': 7.24.4 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-layout-effect@1.0.1(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-v/5RegiJWYdoCvMnITBkNNx6bCj20fiaJnWtRkU18yITptraXjffz5Qbn05uOiQnOvi+dbkznkoaMltz1GnszQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.4 + '@types/react': 18.2.78 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-rect@1.0.1(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-Cq5DLuSiuYVKNU8orzJMbl15TXilTnJKUCltMVQg53BQOF1/C5toAaGrowkgksdBQ9H+SRL23g0HDmg9tvmxXw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/rect': 1.0.1 + '@types/react': 18.2.78 + react: 18.2.0 + dev: false + + /@radix-ui/react-use-size@1.0.1(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-ibay+VqrgcaI6veAojjofPATwledXiSmX+C0KrBk/xgpX9rBzPV3OsfwlhQdUOFbh+LKQorLYT+xTXW9V8yd0g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@babel/runtime': 7.24.4 + '@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.78)(react@18.2.0) + '@types/react': 18.2.78 + react: 18.2.0 + dev: false + + /@radix-ui/rect@1.0.1: + resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==} + dependencies: + '@babel/runtime': 7.24.4 + dev: false + + /@remirror/core-constants@2.0.2: + resolution: {integrity: sha512-dyHY+sMF0ihPus3O27ODd4+agdHMEmuRdyiZJ2CCWjPV5UFmn17ZbElvk6WOGVE4rdCJKZQCrPV2BcikOMLUGQ==} + dev: false + + /@replit/codemirror-css-color-picker@6.1.1(@codemirror/language@6.10.1)(@codemirror/state@6.4.1)(@codemirror/view@6.26.3): + resolution: {integrity: sha512-e/wYHcgt3HRDpvYuwqXyjv3LEY6VyFjJeDQK1UtFmaykp86R6Cbw3ULH9pvuJuelaW6nS4CVtIRHuOfbFLlqwQ==} + peerDependencies: + '@codemirror/language': ^6.0.0 + '@codemirror/state': ^6.0.0 + '@codemirror/view': ^6.0.0 + dependencies: + '@codemirror/language': 6.10.1 '@codemirror/state': 6.4.1 '@codemirror/view': 6.26.3 dev: false @@ -6022,7 +6577,7 @@ packages: deepmerge: 4.3.1 is-builtin-module: 3.2.1 is-module: 1.0.0 - resolve: 1.22.4 + resolve: 1.22.8 rollup: 3.29.4 dev: true @@ -6502,6 +7057,25 @@ packages: vue: 3.4.25(typescript@5.4.5) dev: false + /@scena/dragscroll@1.4.0: + resolution: {integrity: sha512-3O8daaZD9VXA9CP3dra6xcgt/qrm0mg0xJCwiX6druCteQ9FFsXffkF8PrqxY4Z4VJ58fFKEa0RlKqbsi/XnRA==} + dependencies: + '@daybrush/utils': 1.13.0 + '@scena/event-emitter': 1.0.5 + dev: false + + /@scena/event-emitter@1.0.5: + resolution: {integrity: sha512-AzY4OTb0+7ynefmWFQ6hxDdk0CySAq/D4efljfhtRHCOP7MBF9zUfhKG3TJiroVjASqVgkRJFdenS8ArZo6Olg==} + dependencies: + '@daybrush/utils': 1.13.0 + dev: false + + /@scena/matrix@1.1.1: + resolution: {integrity: sha512-JVKBhN0tm2Srl+Yt+Ywqu0oLgLcdemDQlD1OxmN9jaCTwaFPZ7tY8n6dhVgMEaR9qcR7r+kAlMXnSfNyYdE+Vg==} + dependencies: + '@daybrush/utils': 1.13.0 + dev: false + /@shikijs/core@1.3.0: resolution: {integrity: sha512-7fedsBfuILDTBmrYZNFI8B6ATTxhQAasUHllHmjvSZPnoq4bULWoTpHwmuQvZ8Aq03/tAa2IGo6RXqWtHdWaCA==} dev: false @@ -6877,6 +7451,18 @@ packages: zod: 3.23.0 dev: false + /@tailwindcss/typography@0.5.13(tailwindcss@3.4.3): + resolution: {integrity: sha512-ADGcJ8dX21dVVHIwTRgzrcunY6YY9uSlAHHGVKvkA+vLc5qLwEszvKts40lx7z0qc4clpjclwLeK5rVCV2P/uw==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + dependencies: + lodash.castarray: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.merge: 4.6.2 + postcss-selector-parser: 6.0.10 + tailwindcss: 3.4.3 + dev: false + /@tanstack/react-virtual@3.4.0(react-dom@18.2.0)(react@18.2.0): resolution: {integrity: sha512-GZN4xn/Tg5w7gvYeVcMVCeL4pEyUhvg+Cp6KX2Z01C4FRNxIWMgIQ9ibgMarNQfo+gt0PVLcEER4A9sNv/jlow==} peerDependencies: @@ -6888,36 +7474,376 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false - /@tanstack/virtual-core@3.4.0: - resolution: {integrity: sha512-75jXqXxqq5M5Veb9KP1STi8kA5u408uOOAefk2ftHDGCpUk3RP6zX++QqfbmHJTBiU72NQ+ghgCZVts/Wocz8Q==} + /@tanstack/virtual-core@3.4.0: + resolution: {integrity: sha512-75jXqXxqq5M5Veb9KP1STi8kA5u408uOOAefk2ftHDGCpUk3RP6zX++QqfbmHJTBiU72NQ+ghgCZVts/Wocz8Q==} + dev: false + + /@tanstack/vue-virtual@3.4.0(vue@3.4.25): + resolution: {integrity: sha512-OHZGsmE89rpouVDGDOCtJTu64gLUzVq5FGkL2YY/wtZXu5QRSi5ep3T25Ivd53HQI3A169H01uwVPD0mEXKm9A==} + peerDependencies: + vue: ^2.7.0 || ^3.0.0 + dependencies: + '@tanstack/virtual-core': 3.4.0 + vue: 3.4.25(typescript@5.4.5) + dev: false + + /@theguild/remark-mermaid@0.0.5(react@18.2.0): + resolution: {integrity: sha512-e+ZIyJkEv9jabI4m7q29wZtZv+2iwPGsXJ2d46Zi7e+QcFudiyuqhLhHG/3gX3ZEB+hxTch+fpItyMS8jwbIcw==} + peerDependencies: + react: ^18.2.0 + dependencies: + mermaid: 10.9.0 + react: 18.2.0 + unist-util-visit: 5.0.0 + transitivePeerDependencies: + - supports-color + dev: false + + /@theguild/remark-npm2yarn@0.2.1: + resolution: {integrity: sha512-jUTFWwDxtLEFtGZh/TW/w30ySaDJ8atKWH8dq2/IiQF61dPrGfETpl0WxD0VdBfuLOeU14/kop466oBSRO/5CA==} + dependencies: + npm-to-yarn: 2.2.1 + unist-util-visit: 5.0.0 + dev: false + + /@tiptap/core@2.3.2(@tiptap/pm@2.3.2): + resolution: {integrity: sha512-4sMpzYuxiG+fYMwPRXy+mLRVU315KEqzQUcBc2FEgSsmw9Kionykmkq3DvEco7rH8r0NdV/l9R49wVEtX54VqQ==} + peerDependencies: + '@tiptap/pm': ^2.0.0 + dependencies: + '@tiptap/pm': 2.3.2 + dev: false + + /@tiptap/extension-blockquote@2.3.2(@tiptap/core@2.3.2): + resolution: {integrity: sha512-dyXx1hHAW/0BSxCUNWcxc8UN+s0wRTdtH46u6IEf91z+IOWjJwmSxT00+UMYh6hdOYDDsJYxPe9gcuSWYCIkCg==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + dev: false + + /@tiptap/extension-bold@2.3.2(@tiptap/core@2.3.2): + resolution: {integrity: sha512-Mdc0qOPeJxxt5kSYKpNs7TzbQHeVpbpxwafUrxrvfD2iOnJlwlNxVWsVulc1t5EA8NpbTqYJTPmAtv2h/qmsfw==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + dev: false + + /@tiptap/extension-bubble-menu@2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2): + resolution: {integrity: sha512-hg+ncQmoNngdeoUWBQs2AWzDO8YIrlAIgLmIponC+OSCZoVrri7LZ4N1uSp5B/U0lz5fSGUvsUNUs0le+MMr/Q==} + peerDependencies: + '@tiptap/core': ^2.0.0 + '@tiptap/pm': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + '@tiptap/pm': 2.3.2 + tippy.js: 6.3.7 + dev: false + + /@tiptap/extension-bullet-list@2.3.2(@tiptap/core@2.3.2): + resolution: {integrity: sha512-nzvXSGxJuuZdQ6NE0gJ2GC+0gjXZTgU2+Z8TEKi7TYLUAjAoiU1Iniz1XA97cuFwVrNKp031IF1LivK085NqQA==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + dev: false + + /@tiptap/extension-code-block@2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2): + resolution: {integrity: sha512-Ng5dh8+FMD3pxaqZEDSRxTjgjPCNdEEVUTJnuljZXQ9ZxI9wVsKsGs53Hunpita4Qgk0DYhlfAvGUKCM0nCH4A==} + peerDependencies: + '@tiptap/core': ^2.0.0 + '@tiptap/pm': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + '@tiptap/pm': 2.3.2 + dev: false + + /@tiptap/extension-code@2.3.2(@tiptap/core@2.3.2): + resolution: {integrity: sha512-LyIRBFJCxbgi96ejoeewESvfUf5igfngamZJK+uegfTcznimP0AjSWs3whJwZ9QXUsQrB9tIrWIG4GBtatp6qw==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + dev: false + + /@tiptap/extension-color@2.3.2(@tiptap/core@2.3.2)(@tiptap/extension-text-style@2.3.2): + resolution: {integrity: sha512-xPJyqDFkDI/jPW0SKPhARuSgvIiIUdcMS/i+nc4wSlShvUugcGNbd00LgDHNCUW0VpKQA/MMMtWzj9ZOPcjquQ==} + peerDependencies: + '@tiptap/core': ^2.0.0 + '@tiptap/extension-text-style': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + '@tiptap/extension-text-style': 2.3.2(@tiptap/core@2.3.2) + dev: false + + /@tiptap/extension-document@2.3.2(@tiptap/core@2.3.2): + resolution: {integrity: sha512-EQcfkvA7lkZPKllhGo2jiEYLJyXhBFK7++oRatgbfgHEJ2uLBGv6ys7WLCeRA/ntcaWTH3rlS+HR/Y8/nnyQYg==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + dev: false + + /@tiptap/extension-dropcursor@2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2): + resolution: {integrity: sha512-r7JJn9dEnIRDdbnTCAUFCWX4OPsR48+4OEm5eGlysEaD2h4z0G1AaK5XXwOoQhP3WP2LHHjL4LahlYZvltzFzw==} + peerDependencies: + '@tiptap/core': ^2.0.0 + '@tiptap/pm': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + '@tiptap/pm': 2.3.2 + dev: false + + /@tiptap/extension-floating-menu@2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2): + resolution: {integrity: sha512-7MerFtr+7y0lThKEcNeM0B5LMWqP3RqmMZYJEOCIL20mIINYz5JzSIMQQujmeU5tcqI12O1u7jbRoxRmZrsXxw==} + peerDependencies: + '@tiptap/core': ^2.0.0 + '@tiptap/pm': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + '@tiptap/pm': 2.3.2 + tippy.js: 6.3.7 + dev: false + + /@tiptap/extension-gapcursor@2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2): + resolution: {integrity: sha512-PSry4JHUIOhXytvYUQGtYgfIKCIhnmbKksZ8/CfCaKgGJpjOpnzqRG5FnYXZB7NiqouABreM7+IgkH0mOLq6HQ==} + peerDependencies: + '@tiptap/core': ^2.0.0 + '@tiptap/pm': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + '@tiptap/pm': 2.3.2 + dev: false + + /@tiptap/extension-hard-break@2.3.2(@tiptap/core@2.3.2): + resolution: {integrity: sha512-Oy/Dj75kw/tyNyrcFf97r872NZggISfvabTptH8j1gFPg/XzT5ERcT2fvgpbsBx0WWlXOaFkC1owta6kS6MZpg==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + dev: false + + /@tiptap/extension-heading@2.3.2(@tiptap/core@2.3.2): + resolution: {integrity: sha512-KBew4QCnYASBPEJlZ4vKQnm4R9B206H8kE5+hq8OOyF3FVkR6FgF/AbY/E/4/+2blx82PGp+9gvPUVpEv36ifQ==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + dev: false + + /@tiptap/extension-highlight@2.3.2(@tiptap/core@2.3.2): + resolution: {integrity: sha512-OycPrcLTwRI+vi1p63J+d4ta3TESRoEBJP7qG1oxATLkCNvekNl+1LMgkdohJMBHMF3smCA9BAYUqtQqUhYD3w==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + dev: false + + /@tiptap/extension-history@2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2): + resolution: {integrity: sha512-LTon7ys+C6wLmN/nXYkr1pDxIiIv0Czn4US7I/1b8Ws2N6PU+nMm4r7Uj8hKrDYL8yPQUaS4gIs1hhOwJ8UjtA==} + peerDependencies: + '@tiptap/core': ^2.0.0 + '@tiptap/pm': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + '@tiptap/pm': 2.3.2 + dev: false + + /@tiptap/extension-horizontal-rule@2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2): + resolution: {integrity: sha512-nz4GcYvZmJOX20GAjR5ymZgzQCbhnK/rmcunQf4zkl4LA5sXm70P70I9bDtrT/mgmz5dnBUTkVAkLTtKbovdDQ==} + peerDependencies: + '@tiptap/core': ^2.0.0 + '@tiptap/pm': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + '@tiptap/pm': 2.3.2 + dev: false + + /@tiptap/extension-image@2.3.2(@tiptap/core@2.3.2): + resolution: {integrity: sha512-otkhqToHnjjpWOIswuotfK/PTPEOhhKRFPf1NuXvqHpMNulz+J1uIuA9R/B1m+bXkxZzCMKkWQi50vjqH9idVg==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + dev: false + + /@tiptap/extension-italic@2.3.2(@tiptap/core@2.3.2): + resolution: {integrity: sha512-6RJmexu/E+JP2+lhzJLV+5KZJiTrJE+p/hnDk13CBK2VgiwcJYmcZSVk+Yk6Suwrb1qTAosu8paKIwVJa/VMUg==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + dev: false + + /@tiptap/extension-link@2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2): + resolution: {integrity: sha512-Bs3PbYmXj5bzUzPdFkcuflxZkdI2nCIJY2YO5TykANos68FrRtxyRKCxSxyZABzKjctT/UUVSap7JUVQ+i/bSw==} + peerDependencies: + '@tiptap/core': ^2.0.0 + '@tiptap/pm': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + '@tiptap/pm': 2.3.2 + linkifyjs: 4.1.3 + dev: false + + /@tiptap/extension-list-item@2.3.2(@tiptap/core@2.3.2): + resolution: {integrity: sha512-vgT7tkSZd99xAEph9quPlVdRkgPU4GJp9K7bNS8Y7GnSLU0KkDHbtDpb0pyz76HVpeOnt/QGmtqF14Il9T2IPQ==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + dev: false + + /@tiptap/extension-ordered-list@2.3.2(@tiptap/core@2.3.2): + resolution: {integrity: sha512-eMnQDgWpaQ3sdlFg1M85oziFYl2h/GRBjUt4JhF5kyWpHOYDj1/bX1fndZOBQ5xaoNlbcaeEkIc53xVX4ZV9tw==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + dev: false + + /@tiptap/extension-paragraph@2.3.2(@tiptap/core@2.3.2): + resolution: {integrity: sha512-bKzL4NXp0pDM/Q5ZCpjLxjQU4DwoWc6CDww1M4B4dp1sfiXiE2P7EOCMM2TfJOqNPUFpp5RcFKKcxC2Suj8W4w==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + dev: false + + /@tiptap/extension-placeholder@2.0.3(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2): + resolution: {integrity: sha512-Z42jo0termRAf0S0L8oxrts94IWX5waU4isS2CUw8xCUigYyCFslkhQXkWATO1qRbjNFLKN2C9qvCgGf4UeBrw==} + peerDependencies: + '@tiptap/core': ^2.0.0 + '@tiptap/pm': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + '@tiptap/pm': 2.3.2 + dev: false + + /@tiptap/extension-strike@2.3.2(@tiptap/core@2.3.2): + resolution: {integrity: sha512-gi16YtLnXKPubxafvcGSAELac4i8S6Eb9Av0AaH6QH9H9zzSHN7qOrX930Tp2Pod5a/a82kk7kN7IB6htAeaYA==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + dev: false + + /@tiptap/extension-task-item@2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2): + resolution: {integrity: sha512-r5WKBFVtByYMGhAB6SSAsyYd8hktiJv1I5o/fgphyGf6hdYfq6nNgb/MjAkpRFEloO36ETKR1Nn1Az7Jhu+VxA==} + peerDependencies: + '@tiptap/core': ^2.0.0 + '@tiptap/pm': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + '@tiptap/pm': 2.3.2 + dev: false + + /@tiptap/extension-task-list@2.3.2(@tiptap/core@2.3.2): + resolution: {integrity: sha512-EP6AhjUorjwralLjSfTHU28m5AzS0Y6oRsOiK8wptwWYC6DnObuPCJEukxM3nhSM4r8SRqcAVWgCuJNBBuJRMA==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + dev: false + + /@tiptap/extension-text-style@2.3.2(@tiptap/core@2.3.2): + resolution: {integrity: sha512-y0ye1BqDSVqewLTcW9Rg4hXykZ8eTOEhb5KCLbcYYsX4LeKQv/gNQjj/Oy9+w177ts32gvbEuypOEKJJo/oBBw==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + dev: false + + /@tiptap/extension-text@2.3.2(@tiptap/core@2.3.2): + resolution: {integrity: sha512-a3whwDyyOsrmOQbfeY+Fm5XypSRgT3IGqWgz0r4U7oko57/X6Env08F1Ie2e2UkQw9B1MoW9cm3dC6jvrdzzYA==} + peerDependencies: + '@tiptap/core': ^2.0.0 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) dev: false - /@tanstack/vue-virtual@3.4.0(vue@3.4.25): - resolution: {integrity: sha512-OHZGsmE89rpouVDGDOCtJTu64gLUzVq5FGkL2YY/wtZXu5QRSi5ep3T25Ivd53HQI3A169H01uwVPD0mEXKm9A==} + /@tiptap/extension-underline@2.3.2(@tiptap/core@2.3.2): + resolution: {integrity: sha512-ZmhWG8gMXk62AhpIMuOofe8GWbkXBW1uYHG55Q9r7MmglESLJm13S5k8JVfOmOMKGzfE23A6yQkojnksAiSGoQ==} peerDependencies: - vue: ^2.7.0 || ^3.0.0 + '@tiptap/core': ^2.0.0 dependencies: - '@tanstack/virtual-core': 3.4.0 - vue: 3.4.25(typescript@5.4.5) + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) dev: false - /@theguild/remark-mermaid@0.0.5(react@18.2.0): - resolution: {integrity: sha512-e+ZIyJkEv9jabI4m7q29wZtZv+2iwPGsXJ2d46Zi7e+QcFudiyuqhLhHG/3gX3ZEB+hxTch+fpItyMS8jwbIcw==} + /@tiptap/pm@2.3.2: + resolution: {integrity: sha512-39Bmg7XqWWJg/G5YvWc3QVEPmFNpuMa05gw0Ap7KAKHnHiwl87hosOIDD8dtdcMrtgJL9NwBfUjEJ3ne53U9Ag==} + dependencies: + prosemirror-changeset: 2.2.1 + prosemirror-collab: 1.3.1 + prosemirror-commands: 1.5.2 + prosemirror-dropcursor: 1.8.1 + prosemirror-gapcursor: 1.3.2 + prosemirror-history: 1.4.0 + prosemirror-inputrules: 1.4.0 + prosemirror-keymap: 1.2.2 + prosemirror-markdown: 1.12.0 + prosemirror-menu: 1.2.4 + prosemirror-model: 1.21.0 + prosemirror-schema-basic: 1.2.2 + prosemirror-schema-list: 1.3.0 + prosemirror-state: 1.4.3 + prosemirror-tables: 1.3.7 + prosemirror-trailing-node: 2.0.8(prosemirror-model@1.21.0)(prosemirror-state@1.4.3)(prosemirror-view@1.33.6) + prosemirror-transform: 1.9.0 + prosemirror-view: 1.33.6 + dev: false + + /@tiptap/react@2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-NDvt3XfPn/6V3iAX3lqYGIuFPQgirUGKRyzfHl7ssIfpoY5VR5tRJkU4NigOr63NONrsgCgqJISG/nPY6YGw8w==} peerDependencies: - react: ^18.2.0 + '@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: - mermaid: 10.9.0 + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + '@tiptap/extension-bubble-menu': 2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2) + '@tiptap/extension-floating-menu': 2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2) + '@tiptap/pm': 2.3.2 react: 18.2.0 - unist-util-visit: 5.0.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + + /@tiptap/starter-kit@2.3.2(@tiptap/pm@2.3.2): + resolution: {integrity: sha512-7KdOxnYcmg2x2XGOAYssoz7iHLGDznoS5cNHjiOzuca+mO+5YutQ3j5yr/6+ithkX9/HZZwHJFQ6KORIARoNQg==} + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + '@tiptap/extension-blockquote': 2.3.2(@tiptap/core@2.3.2) + '@tiptap/extension-bold': 2.3.2(@tiptap/core@2.3.2) + '@tiptap/extension-bullet-list': 2.3.2(@tiptap/core@2.3.2) + '@tiptap/extension-code': 2.3.2(@tiptap/core@2.3.2) + '@tiptap/extension-code-block': 2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2) + '@tiptap/extension-document': 2.3.2(@tiptap/core@2.3.2) + '@tiptap/extension-dropcursor': 2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2) + '@tiptap/extension-gapcursor': 2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2) + '@tiptap/extension-hard-break': 2.3.2(@tiptap/core@2.3.2) + '@tiptap/extension-heading': 2.3.2(@tiptap/core@2.3.2) + '@tiptap/extension-history': 2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2) + '@tiptap/extension-horizontal-rule': 2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2) + '@tiptap/extension-italic': 2.3.2(@tiptap/core@2.3.2) + '@tiptap/extension-list-item': 2.3.2(@tiptap/core@2.3.2) + '@tiptap/extension-ordered-list': 2.3.2(@tiptap/core@2.3.2) + '@tiptap/extension-paragraph': 2.3.2(@tiptap/core@2.3.2) + '@tiptap/extension-strike': 2.3.2(@tiptap/core@2.3.2) + '@tiptap/extension-text': 2.3.2(@tiptap/core@2.3.2) transitivePeerDependencies: - - supports-color + - '@tiptap/pm' dev: false - /@theguild/remark-npm2yarn@0.2.1: - resolution: {integrity: sha512-jUTFWwDxtLEFtGZh/TW/w30ySaDJ8atKWH8dq2/IiQF61dPrGfETpl0WxD0VdBfuLOeU14/kop466oBSRO/5CA==} + /@tiptap/suggestion@2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2): + resolution: {integrity: sha512-3s1vDaBX4rEsVtVB0udi+v9h1koiGyIKu9BFFxaOSqHks9HvHYC3nagOFOkE4kmrbv8XJUigPuZ4K4XvH7iqKQ==} + peerDependencies: + '@tiptap/core': ^2.0.0 + '@tiptap/pm': ^2.0.0 dependencies: - npm-to-yarn: 2.2.1 - unist-util-visit: 5.0.0 + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + '@tiptap/pm': 2.3.2 dev: false /@trysound/sax@0.2.0: @@ -7125,6 +8051,17 @@ packages: resolution: {integrity: sha512-lZuNAY9xeJt7Bx4t4dx0rYCDqGPW8RXhQZK1td7d4H6E9zYbLoOtjBvfwdTKpsyxQI/2jv+armjX/RW+ZNpXOQ==} dev: false + /@types/linkify-it@3.0.5: + resolution: {integrity: sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==} + dev: false + + /@types/markdown-it@13.0.8: + resolution: {integrity: sha512-V+KmpgiipS+zoypeUSS9ojesWtY/0k4XfqcK2fnVrX/qInJhX7rsCxZ/rygiPH2zxlPPrhfuW0I6ddMcWTKLsg==} + dependencies: + '@types/linkify-it': 3.0.5 + '@types/mdurl': 1.0.5 + dev: false + /@types/mdast@3.0.12: resolution: {integrity: sha512-DT+iNIRNX884cx0/Q1ja7NyUPpZuv0KPyL5rGNxm1WC1OtHstl7n4Jb7nk+xacNShQMbczJjt8uFzznpp6kYBg==} dependencies: @@ -7137,6 +8074,10 @@ packages: '@types/unist': 2.0.7 dev: false + /@types/mdurl@1.0.5: + resolution: {integrity: sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==} + dev: false + /@types/mdx@2.0.6: resolution: {integrity: sha512-sVcwEG10aFU2KcM7cIA0M410UPv/DesOPyG8zMVk0QUDexHA3lYmGucpEpZ2dtWWhi2ip3CG+5g/iH0PwoW4Fw==} dev: false @@ -7191,6 +8132,10 @@ packages: resolution: {integrity: sha512-vmYJF0REqDyyU0gviezF/KHq/fYaUbFhkcNbQCuPGFQj6VTbXuHZoxs/Y7mutWe73C8AC6l9fFu8mSYiBAqkGA==} dev: false + /@types/node@18.15.3: + resolution: {integrity: sha512-p6ua9zBxz5otCmbpb5D3U4B5Nanw6Pk3PPyX05xnxbB/fRv71N7CPmORg7uAD5P70T0xmx1pzAx/FUfa5X+3cw==} + dev: false + /@types/node@20.11.30: resolution: {integrity: sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==} dependencies: @@ -8727,7 +9672,6 @@ packages: /any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - dev: true /anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} @@ -8783,7 +9727,6 @@ packages: /arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} - dev: true /argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} @@ -8794,6 +9737,13 @@ packages: /argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + /aria-hidden@1.2.4: + resolution: {integrity: sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==} + engines: {node: '>=10'} + dependencies: + tslib: 2.6.2 + dev: false + /aria-query@5.3.0: resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} dependencies: @@ -9133,7 +10083,7 @@ packages: postcss: ^8.1.0 dependencies: browserslist: 4.21.10 - caniuse-lite: 1.0.30001520 + caniuse-lite: 1.0.30001612 fraction.js: 4.2.0 normalize-range: 0.1.2 picocolors: 1.0.0 @@ -9416,7 +10366,7 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001520 + caniuse-lite: 1.0.30001612 electron-to-chromium: 1.4.746 node-releases: 2.0.13 update-browserslist-db: 1.0.11(browserslist@4.21.10) @@ -9623,7 +10573,6 @@ packages: /camelcase-css@2.0.1: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - dev: true /camelcase-keys@6.2.2: resolution: {integrity: sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==} @@ -9651,13 +10600,10 @@ packages: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} dependencies: browserslist: 4.23.0 - caniuse-lite: 1.0.30001520 + caniuse-lite: 1.0.30001612 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 - /caniuse-lite@1.0.30001520: - resolution: {integrity: sha512-tahF5O9EiiTzwTUqAeFjIZbn4Dnqxzz7ktrgGlMYNLH43Ul26IgTMH/zvL3DG0lZxBYnlT04axvInszUsZULdA==} - /caniuse-lite@1.0.30001612: resolution: {integrity: sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==} @@ -9898,6 +10844,19 @@ packages: resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} engines: {node: '>=0.10.0'} + /cmdk@0.2.1(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-U6//9lQ6JvT47+6OF6Gi8BvkxYQ8SCRRSKIJkthIMsFsLZRG0cKvTtuTaefyIKMQb8rvvXy0wGdpTNq/jPtm+g==} + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + dependencies: + '@radix-ui/react-dialog': 1.0.0(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + transitivePeerDependencies: + - '@types/react' + dev: false + /code-red@1.0.4: resolution: {integrity: sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==} dependencies: @@ -9989,7 +10948,6 @@ packages: /commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} - dev: true /commander@7.2.0: resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} @@ -10199,12 +11157,25 @@ packages: domutils: 3.1.0 nth-check: 2.1.1 + /css-styled@1.0.8: + resolution: {integrity: sha512-tCpP7kLRI8dI95rCh3Syl7I+v7PP+2JYOzWkl0bUEoSbJM+u8ITbutjlQVf0NC2/g4ULROJPi16sfwDIO8/84g==} + dependencies: + '@daybrush/utils': 1.13.0 + dev: false + + /css-to-mat@1.1.1: + resolution: {integrity: sha512-kvpxFYZb27jRd2vium35G7q5XZ2WJ9rWjDUMNT36M3Hc41qCrLXFM5iEKMGXcrPsKfXEN+8l/riB4QzwwwiEyQ==} + dependencies: + '@daybrush/utils': 1.13.0 + '@scena/matrix': 1.1.1 + dev: false + /css-tree@2.2.1: resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} dependencies: mdn-data: 2.0.28 - source-map-js: 1.0.2 + source-map-js: 1.2.0 /css-tree@2.3.1: resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} @@ -10731,7 +11702,7 @@ packages: resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} engines: {node: '>=0.11'} dependencies: - '@babel/runtime': 7.22.10 + '@babel/runtime': 7.24.4 /dax-sh@0.39.2: resolution: {integrity: sha512-gpuGEkBQM+5y6p4cWaw9+ePy5TNon+fdwFVtTI8leU3UhwhsBfPewRxMXGuQNC+M2b/MDGMlfgpqynkcd0C3FQ==} @@ -10969,6 +11940,10 @@ packages: resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} engines: {node: '>=8'} + /detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + dev: false + /deterministic-object-hash@2.0.2: resolution: {integrity: sha512-KxektNH63SrbfUyDiwXqRb1rLwKt33AmMv+5Nhsw1kqZ13SJBRTgZHtGbE+hH3a1mVW1cz+4pqSWVPAtLVXTzQ==} engines: {node: '>=18'} @@ -10991,7 +11966,6 @@ packages: /didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - dev: true /diff-sequences@29.6.3: resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} @@ -12665,6 +13639,10 @@ packages: /fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} + /framework-utils@1.1.0: + resolution: {integrity: sha512-KAfqli5PwpFJ8o3psRNs8svpMGyCSAe8nmGcjQ0zZBWN2H6dZDnq+ABp3N3hdUmFeMrLtjOCTXD4yplUJIWceg==} + dev: false + /fresh@0.5.2: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} @@ -12789,6 +13767,13 @@ packages: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} + /gesto@1.19.4: + resolution: {integrity: sha512-hfr/0dWwh0Bnbb88s3QVJd1ZRJeOWcgHPPwmiH6NnafDYvhTsxg+SLYu+q/oPNh9JS3V+nlr6fNs8kvPAtcRDQ==} + dependencies: + '@daybrush/utils': 1.13.0 + '@scena/event-emitter': 1.0.5 + dev: false + /get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -12819,6 +13804,11 @@ packages: has-symbols: 1.0.3 hasown: 2.0.2 + /get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + dev: false + /get-own-enumerable-property-symbols@3.0.2: resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==} dev: false @@ -12963,7 +13953,6 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 - dev: true /glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} @@ -13027,7 +14016,7 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: dir-glob: 3.0.1 - fast-glob: 3.3.1 + fast-glob: 3.3.2 ignore: 5.2.4 merge2: 1.4.1 slash: 4.0.0 @@ -13669,6 +14658,12 @@ packages: resolution: {integrity: sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==} dev: false + /invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + dependencies: + loose-envify: 1.4.0 + dev: false + /ioredis@5.3.2: resolution: {integrity: sha512-1DKMMzlIHM02eBBVOFQ1+AolGjs6+xEcM4PDL7NqOS6szq7H9jSaEkIUH6/a5Hl241LzW6JLSiAbNvTQjUupUA==} engines: {node: '>=12.22.0'} @@ -14176,6 +15171,22 @@ packages: '@sideway/pinpoint': 2.0.0 dev: true + /jotai@2.8.0(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-yZNMC36FdLOksOr8qga0yLf14miCJlEThlp5DeFJNnqzm2+ZG7wLcJzoOyij5K6U6Xlc5ljQqPDlJRgqW0Y18g==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=17.0.0' + react: '>=17.0.0' + peerDependenciesMeta: + '@types/react': + optional: true + react: + optional: true + dependencies: + '@types/react': 18.2.78 + react: 18.2.0 + dev: false + /joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} @@ -14297,6 +15308,19 @@ packages: commander: 8.3.0 dev: false + /keycode@2.2.1: + resolution: {integrity: sha512-Rdgz9Hl9Iv4QKi8b0OlCRQEzp4AgVxyCtz5S/+VIHezDmrDhkp2N2TqBWOLz0/gbeREXOOiI9/4b8BY9uw2vFg==} + dev: false + + /keycon@1.4.0: + resolution: {integrity: sha512-p1NAIxiRMH3jYfTeXRs2uWbVJ1WpEjpi8ktzUyBJsX7/wn2qu2VRXktneBLNtKNxJmlUYxRi9gOJt1DuthXR7A==} + dependencies: + '@cfcs/core': 0.0.6 + '@daybrush/utils': 1.13.0 + '@scena/event-emitter': 1.0.5 + keycode: 2.2.1 + dev: false + /keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} dependencies: @@ -14411,6 +15435,16 @@ packages: /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + /linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + dependencies: + uc.micro: 2.1.0 + dev: false + + /linkifyjs@4.1.3: + resolution: {integrity: sha512-auMesunaJ8yfkHvK4gfg1K0SaKX/6Wn9g2Aac/NwX+l5VdmFZzo/hdPGxEOETj+ryRa4/fiOPjeeKURSAJx1sg==} + dev: false + /listhen@1.7.2: resolution: {integrity: sha512-7/HamOm5YD9Wb7CFgAZkKgVPA96WwhcTQoqtm2VTZGVbVVn3IWKRBTgrU7cchA3Q8k9iCsG8Osoi9GX4JsGM9g==} hasBin: true @@ -14483,6 +15517,10 @@ packages: resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} dev: false + /lodash.castarray@4.4.0: + resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==} + dev: false + /lodash.defaults@4.2.0: resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} @@ -14493,6 +15531,10 @@ packages: /lodash.isarguments@3.1.0: resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==} + /lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + dev: false + /lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} @@ -14596,6 +15638,14 @@ packages: es5-ext: 0.10.64 dev: true + /lucide-react@0.368.0(react@18.2.0): + resolution: {integrity: sha512-soryVrCjheZs8rbXKdINw9B8iPi5OajBJZMJ1HORig89ljcOcEokKKAgGbg3QWxSXel7JwHOfDFUdDHAKyUAMw==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 + dependencies: + react: 18.2.0 + dev: false + /magic-string-ast@0.3.0: resolution: {integrity: sha512-0shqecEPgdFpnI3AP90epXyxZy9g6CRZ+SZ7BcqFwYmtFEnZ1jpevcV5HoyVnlDS9gCnc1UIg3Rsvp3Ci7r8OA==} engines: {node: '>=16.14.0'} @@ -14685,6 +15735,22 @@ packages: engines: {node: '>=0.10.0'} dev: false + /markdown-it-task-lists@2.1.1: + resolution: {integrity: sha512-TxFAc76Jnhb2OUu+n3yz9RMu4CwGfaT788br6HhEDlvWfdeJcLUsxk1Hgw2yJio0OXsxv7pyIPmvECY7bMbluA==} + dev: false + + /markdown-it@14.1.0: + resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} + hasBin: true + dependencies: + argparse: 2.0.1 + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + dev: false + /markdown-table@3.0.3: resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==} dev: false @@ -15041,6 +16107,10 @@ packages: /mdn-data@2.0.30: resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + /mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + dev: false + /media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} @@ -16044,7 +17114,6 @@ packages: any-promise: 1.3.0 object-assign: 4.1.1 thenify-all: 1.6.0 - dev: true /nanoid@3.3.6: resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} @@ -16115,6 +17184,16 @@ packages: react-dom: 18.2.0(react@18.2.0) dev: false + /next-themes@0.3.0(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==} + peerDependencies: + react: ^16.8 || ^17 || ^18 + react-dom: ^16.8 || ^17 || ^18 + dependencies: + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /next-tick@1.1.0: resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} dev: true @@ -16442,7 +17521,7 @@ packages: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: hosted-git-info: 2.8.9 - resolve: 1.22.4 + resolve: 1.22.8 semver: 5.7.2 validate-npm-package-license: 3.0.4 dev: false @@ -16469,6 +17548,46 @@ packages: engines: {node: '>=14.16'} dev: false + /novel@0.3.1(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-om5ETtpo23BvKbN6wynSkSEwsJCWIEJjuBPYPk9jy9ktVqNUJjvVGGtCeah7Gr1L7Iy3Jtif1cMFokqsyzZQPw==} + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + dependencies: + '@radix-ui/react-slot': 1.0.2(@types/react@18.2.78)(react@18.2.0) + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + '@tiptap/extension-color': 2.3.2(@tiptap/core@2.3.2)(@tiptap/extension-text-style@2.3.2) + '@tiptap/extension-highlight': 2.3.2(@tiptap/core@2.3.2) + '@tiptap/extension-horizontal-rule': 2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2) + '@tiptap/extension-image': 2.3.2(@tiptap/core@2.3.2) + '@tiptap/extension-link': 2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2) + '@tiptap/extension-placeholder': 2.0.3(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2) + '@tiptap/extension-task-item': 2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2) + '@tiptap/extension-task-list': 2.3.2(@tiptap/core@2.3.2) + '@tiptap/extension-text-style': 2.3.2(@tiptap/core@2.3.2) + '@tiptap/extension-underline': 2.3.2(@tiptap/core@2.3.2) + '@tiptap/pm': 2.3.2 + '@tiptap/react': 2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2)(react-dom@18.2.0)(react@18.2.0) + '@tiptap/starter-kit': 2.3.2(@tiptap/pm@2.3.2) + '@tiptap/suggestion': 2.3.2(@tiptap/core@2.3.2)(@tiptap/pm@2.3.2) + '@types/node': 18.15.3 + cmdk: 0.2.1(@types/react@18.2.78)(react-dom@18.2.0)(react@18.2.0) + jotai: 2.8.0(@types/react@18.2.78)(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + react-markdown: 8.0.7(@types/react@18.2.78)(react@18.2.0) + react-moveable: 0.56.0 + tippy.js: 6.3.7 + tiptap-extension-auto-joiner: 0.1.3 + tiptap-extension-global-drag-handle: 0.1.6 + tiptap-markdown: 0.8.10(@tiptap/core@2.3.2) + tunnel-rat: 0.1.2(@types/react@18.2.78)(react@18.2.0) + transitivePeerDependencies: + - '@types/react' + - immer + - supports-color + dev: false + /npm-bundled@2.0.1: resolution: {integrity: sha512-gZLxXdjEzE/+mOstGDqR6b0EkhJ+kM6fxM6vUuckuctuVPh80Q6pw/rSZj9s4Gex9GxWtIicO1pc8DB9KZWudw==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} @@ -16987,7 +18106,6 @@ packages: /object-hash@3.0.0: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} - dev: true /object-inspect@1.12.3: resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} @@ -17180,6 +18298,10 @@ packages: strip-ansi: 7.1.0 dev: false + /orderedmap@2.1.1: + resolution: {integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==} + dev: false + /os-tmpdir@1.0.2: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} @@ -17193,6 +18315,12 @@ packages: resolution: {integrity: sha512-Ou3dJ6bA/UJ5GVHxah4LnqDwZRwAmWxrG3wtrHrbGnP4RnLCtA64A4F+ae7Y8ww660JaddSoArUR5HjipWSHAQ==} dev: false + /overlap-area@1.1.0: + resolution: {integrity: sha512-3dlJgJCaVeXH0/eZjYVJvQiLVVrPO4U1ZGqlATtx6QGO3b5eNM6+JgUKa7oStBTdYuGTk7gVoABCW6Tp+dhRdw==} + dependencies: + '@daybrush/utils': 1.13.0 + dev: false + /p-cancelable@3.0.0: resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==} engines: {node: '>=12.20'} @@ -17479,7 +18607,6 @@ packages: /pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} - dev: true /pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} @@ -17514,7 +18641,6 @@ packages: /pirates@4.0.6: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} - dev: true /pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} @@ -17564,7 +18690,7 @@ packages: postcss: ^8.2.2 dependencies: postcss: 8.4.38 - postcss-selector-parser: 6.0.13 + postcss-selector-parser: 6.0.16 postcss-value-parser: 4.2.0 /postcss-colormin@6.0.0(postcss@8.4.38): @@ -17691,7 +18817,6 @@ packages: postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.4 - dev: true /postcss-js@4.0.1(postcss@8.4.38): resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} @@ -17701,7 +18826,6 @@ packages: dependencies: camelcase-css: 2.0.1 postcss: 8.4.38 - dev: true /postcss-load-config@3.1.4(postcss@8.4.38): resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} @@ -17720,6 +18844,22 @@ packages: yaml: 1.10.2 dev: false + /postcss-load-config@4.0.1: + resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 2.1.0 + yaml: 2.4.1 + dev: true + /postcss-load-config@4.0.1(postcss@8.4.38): resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==} engines: {node: '>= 14'} @@ -17735,7 +18875,6 @@ packages: lilconfig: 2.1.0 postcss: 8.4.38 yaml: 2.3.1 - dev: true /postcss-load-config@5.0.3(postcss@8.4.38): resolution: {integrity: sha512-90pBBI5apUVruIEdCxZic93Wm+i9fTrp7TXbgdUCH+/L+2WnfpITSpq5dFU/IPvbv7aNiMlQISpUkAm3fEcvgQ==} @@ -17785,7 +18924,7 @@ packages: caniuse-api: 3.0.0 cssnano-utils: 4.0.0(postcss@8.4.38) postcss: 8.4.38 - postcss-selector-parser: 6.0.13 + postcss-selector-parser: 6.0.16 dev: true /postcss-merge-rules@6.1.1(postcss@8.4.38): @@ -17872,7 +19011,7 @@ packages: postcss: ^8.2.15 dependencies: postcss: 8.4.38 - postcss-selector-parser: 6.0.13 + postcss-selector-parser: 6.0.16 dev: true /postcss-minify-selectors@6.0.4(postcss@8.4.38): @@ -18143,6 +19282,14 @@ packages: postcss: 8.4.38 dev: false + /postcss-selector-parser@6.0.10: + resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + dev: false + /postcss-selector-parser@6.0.13: resolution: {integrity: sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==} engines: {node: '>=4'} @@ -18185,7 +19332,7 @@ packages: postcss: ^8.2.15 dependencies: postcss: 8.4.38 - postcss-selector-parser: 6.0.13 + postcss-selector-parser: 6.0.16 dev: true /postcss-unique-selectors@6.0.4(postcss@8.4.38): @@ -18373,44 +19520,186 @@ packages: /process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - /process-warning@3.0.0: - resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==} + /process-warning@3.0.0: + resolution: {integrity: sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==} + + /process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + + /promise-inflight@1.0.1: + resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} + peerDependencies: + bluebird: '*' + peerDependenciesMeta: + bluebird: + optional: true + + /promise-retry@2.0.1: + resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} + engines: {node: '>=10'} + dependencies: + err-code: 2.0.3 + retry: 0.12.0 + + /prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + /prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + dependencies: + loose-envify: 1.4.0 + object-assign: 4.1.1 + react-is: 16.13.1 + + /property-information@6.2.0: + resolution: {integrity: sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg==} + dev: false + + /prosemirror-changeset@2.2.1: + resolution: {integrity: sha512-J7msc6wbxB4ekDFj+n9gTW/jav/p53kdlivvuppHsrZXCaQdVgRghoZbSS3kwrRyAstRVQ4/+u5k7YfLgkkQvQ==} + dependencies: + prosemirror-transform: 1.9.0 + dev: false + + /prosemirror-collab@1.3.1: + resolution: {integrity: sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ==} + dependencies: + prosemirror-state: 1.4.3 + dev: false + + /prosemirror-commands@1.5.2: + resolution: {integrity: sha512-hgLcPaakxH8tu6YvVAaILV2tXYsW3rAdDR8WNkeKGcgeMVQg3/TMhPdVoh7iAmfgVjZGtcOSjKiQaoeKjzd2mQ==} + dependencies: + prosemirror-model: 1.21.0 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.9.0 + dev: false + + /prosemirror-dropcursor@1.8.1: + resolution: {integrity: sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw==} + dependencies: + prosemirror-state: 1.4.3 + prosemirror-transform: 1.9.0 + prosemirror-view: 1.33.6 + dev: false + + /prosemirror-gapcursor@1.3.2: + resolution: {integrity: sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ==} + dependencies: + prosemirror-keymap: 1.2.2 + prosemirror-model: 1.21.0 + prosemirror-state: 1.4.3 + prosemirror-view: 1.33.6 + dev: false + + /prosemirror-history@1.4.0: + resolution: {integrity: sha512-UUiGzDVcqo1lovOPdi9YxxUps3oBFWAIYkXLu3Ot+JPv1qzVogRbcizxK3LhHmtaUxclohgiOVesRw5QSlMnbQ==} + dependencies: + prosemirror-state: 1.4.3 + prosemirror-transform: 1.9.0 + prosemirror-view: 1.33.6 + rope-sequence: 1.3.4 + dev: false + + /prosemirror-inputrules@1.4.0: + resolution: {integrity: sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg==} + dependencies: + prosemirror-state: 1.4.3 + prosemirror-transform: 1.9.0 + dev: false + + /prosemirror-keymap@1.2.2: + resolution: {integrity: sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ==} + dependencies: + prosemirror-state: 1.4.3 + w3c-keyname: 2.2.8 + dev: false + + /prosemirror-markdown@1.12.0: + resolution: {integrity: sha512-6F5HS8Z0HDYiS2VQDZzfZP6A0s/I0gbkJy8NCzzDMtcsz3qrfqyroMMeoSjAmOhDITyon11NbXSzztfKi+frSQ==} + dependencies: + markdown-it: 14.1.0 + prosemirror-model: 1.21.0 + dev: false + + /prosemirror-menu@1.2.4: + resolution: {integrity: sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA==} + dependencies: + crelt: 1.0.6 + prosemirror-commands: 1.5.2 + prosemirror-history: 1.4.0 + prosemirror-state: 1.4.3 + dev: false + + /prosemirror-model@1.21.0: + resolution: {integrity: sha512-zLpS1mVCZLA7VTp82P+BfMiYVPcX1/z0Mf3gsjKZtzMWubwn2pN7CceMV0DycjlgE5JeXPR7UF4hJPbBV98oWA==} + dependencies: + orderedmap: 2.1.1 + dev: false - /process@0.11.10: - resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} - engines: {node: '>= 0.6.0'} + /prosemirror-schema-basic@1.2.2: + resolution: {integrity: sha512-/dT4JFEGyO7QnNTe9UaKUhjDXbTNkiWTq/N4VpKaF79bBjSExVV2NXmJpcM7z/gD7mbqNjxbmWW5nf1iNSSGnw==} + dependencies: + prosemirror-model: 1.21.0 + dev: false - /promise-inflight@1.0.1: - resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} - peerDependencies: - bluebird: '*' - peerDependenciesMeta: - bluebird: - optional: true + /prosemirror-schema-list@1.3.0: + resolution: {integrity: sha512-Hz/7gM4skaaYfRPNgr421CU4GSwotmEwBVvJh5ltGiffUJwm7C8GfN/Bc6DR1EKEp5pDKhODmdXXyi9uIsZl5A==} + dependencies: + prosemirror-model: 1.21.0 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.9.0 + dev: false - /promise-retry@2.0.1: - resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} - engines: {node: '>=10'} + /prosemirror-state@1.4.3: + resolution: {integrity: sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q==} dependencies: - err-code: 2.0.3 - retry: 0.12.0 + prosemirror-model: 1.21.0 + prosemirror-transform: 1.9.0 + prosemirror-view: 1.33.6 + dev: false - /prompts@2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} + /prosemirror-tables@1.3.7: + resolution: {integrity: sha512-oEwX1wrziuxMtwFvdDWSFHVUWrFJWt929kVVfHvtTi8yvw+5ppxjXZkMG/fuTdFo+3DXyIPSKfid+Be1npKXDA==} dependencies: - kleur: 3.0.3 - sisteransi: 1.0.5 + prosemirror-keymap: 1.2.2 + prosemirror-model: 1.21.0 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.9.0 + prosemirror-view: 1.33.6 + dev: false - /prop-types@15.8.1: - resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + /prosemirror-trailing-node@2.0.8(prosemirror-model@1.21.0)(prosemirror-state@1.4.3)(prosemirror-view@1.33.6): + resolution: {integrity: sha512-ujRYhSuhQb1Jsarh1IHqb2KoSnRiD7wAMDGucP35DN7j5af6X7B18PfdPIrbwsPTqIAj0fyOvxbuPsWhNvylmA==} + peerDependencies: + prosemirror-model: ^1.19.0 + prosemirror-state: ^1.4.2 + prosemirror-view: ^1.31.2 dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 - react-is: 16.13.1 + '@remirror/core-constants': 2.0.2 + escape-string-regexp: 4.0.0 + prosemirror-model: 1.21.0 + prosemirror-state: 1.4.3 + prosemirror-view: 1.33.6 + dev: false - /property-information@6.2.0: - resolution: {integrity: sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg==} + /prosemirror-transform@1.9.0: + resolution: {integrity: sha512-5UXkr1LIRx3jmpXXNKDhv8OyAOeLTGuXNwdVfg8x27uASna/wQkr9p6fD3eupGOi4PLJfbezxTyi/7fSJypXHg==} + dependencies: + prosemirror-model: 1.21.0 + dev: false + + /prosemirror-view@1.33.6: + resolution: {integrity: sha512-zRLUNgLIQfd8IfGprsXxWTjdA8xEAFJe8cDNrOptj6Mop9sj+BMeVbJvceyAYCm5G2dOdT2prctH7K9dfnpIMw==} + dependencies: + prosemirror-model: 1.21.0 + prosemirror-state: 1.4.3 + prosemirror-transform: 1.9.0 dev: false /proto-list@1.2.4: @@ -18453,6 +19742,11 @@ packages: dev: false optional: true + /punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + dev: false + /punycode@2.3.0: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} @@ -18541,6 +19835,13 @@ packages: strip-json-comments: 2.0.1 dev: false + /react-css-styled@1.1.9: + resolution: {integrity: sha512-M7fJZ3IWFaIHcZEkoFOnkjdiUFmwd8d+gTh2bpqMOcnxy/0Gsykw4dsL4QBiKsxcGow6tETUa4NAUcmJF+/nfw==} + dependencies: + css-styled: 1.0.8 + framework-utils: 1.1.0 + dev: false + /react-dom@18.2.0(react@18.2.0): resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} peerDependencies: @@ -18564,11 +19865,133 @@ packages: /react-is@18.2.0: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + /react-markdown@8.0.7(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-bvWbzG4MtOU62XqBx3Xx+zB2raaFFsq4mYiAzfjXJMEz2sixgeAfraA3tvzULF02ZdOMUOKTBFFaZJDDrq+BJQ==} + peerDependencies: + '@types/react': '>=16' + react: '>=16' + dependencies: + '@types/hast': 2.3.5 + '@types/prop-types': 15.7.5 + '@types/react': 18.2.78 + '@types/unist': 2.0.7 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 2.0.1 + prop-types: 15.8.1 + property-information: 6.2.0 + react: 18.2.0 + react-is: 18.2.0 + remark-parse: 10.0.2 + remark-rehype: 10.1.0 + space-separated-tokens: 2.0.2 + style-to-object: 0.4.2 + unified: 10.1.2 + unist-util-visit: 4.1.2 + vfile: 5.3.7 + transitivePeerDependencies: + - supports-color + dev: false + + /react-moveable@0.56.0: + resolution: {integrity: sha512-FmJNmIOsOA36mdxbrc/huiE4wuXSRlmon/o+/OrfNhSiYYYL0AV5oObtPluEhb2Yr/7EfYWBHTxF5aWAvjg1SA==} + dependencies: + '@daybrush/utils': 1.13.0 + '@egjs/agent': 2.4.3 + '@egjs/children-differ': 1.0.1 + '@egjs/list-differ': 1.0.1 + '@scena/dragscroll': 1.4.0 + '@scena/event-emitter': 1.0.5 + '@scena/matrix': 1.1.1 + css-to-mat: 1.1.1 + framework-utils: 1.1.0 + gesto: 1.19.4 + overlap-area: 1.1.0 + react-css-styled: 1.1.9 + react-selecto: 1.26.3 + dev: false + /react-refresh@0.14.0: resolution: {integrity: sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==} engines: {node: '>=0.10.0'} dev: false + /react-remove-scroll-bar@2.3.6(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-DtSYaao4mBmX+HDo5YWYdBWQwYIQQshUV/dVxFxK+KM26Wjwp1gZ6rv6OC3oujI6Bfu6Xyg3TwK533AQutsn/g==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@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 + dev: false + + /react-remove-scroll@2.5.4(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-xGVKJJr0SJGQVirVFAUZ2k1QLyO6m+2fy0l8Qawbp5Jgrv3DeLalrfMNBFSlmz5kriGGzsVBtGVnf4pTKIhhWA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.78 + react: 18.2.0 + react-remove-scroll-bar: 2.3.6(@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.2(@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-remove-scroll@2.5.5(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-ImKhrzJJsyXJfBZ4bzu8Bwpka14c/fQt0k+cyFp/PBhTfyDnU5hjOtM4AG/0AMyy8oKzOTR0lDgJIM7pYXI0kw==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.78 + react: 18.2.0 + react-remove-scroll-bar: 2.3.6(@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.2(@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-selecto@1.26.3: + resolution: {integrity: sha512-Ubik7kWSnZyQEBNro+1k38hZaI1tJarE+5aD/qsqCOA1uUBSjgKVBy3EWRzGIbdmVex7DcxznFZLec/6KZNvwQ==} + dependencies: + selecto: 1.26.3 + dev: false + + /react-style-singleton@2.2.1(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-ZWj0fHEMyWkHzKYUr2Bs/4zU6XLmq9HsgBURm7g5pAVfyn49DgUiNgY2d4lXRlYSiCif9YBGpQleewkcqddc7g==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@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@18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} engines: {node: '>=0.10.0'} @@ -18579,7 +20002,6 @@ packages: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} dependencies: pify: 2.3.0 - dev: true /read-package-json-fast@3.0.2: resolution: {integrity: sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==} @@ -19018,7 +20440,7 @@ packages: resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} hasBin: true dependencies: - is-core-module: 2.13.0 + is-core-module: 2.13.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -19249,6 +20671,10 @@ packages: '@rollup/rollup-win32-x64-msvc': 4.16.2 fsevents: 2.3.3 + /rope-sequence@1.3.4: + resolution: {integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==} + dev: false + /run-applescript@5.0.0: resolution: {integrity: sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==} engines: {node: '>=12'} @@ -19369,6 +20795,21 @@ packages: /secure-json-parse@2.7.0: resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + /selecto@1.26.3: + resolution: {integrity: sha512-gZHgqMy5uyB6/2YDjv3Qqaf7bd2hTDOpPdxXlrez4R3/L0GiEWDCFaUfrflomgqdb3SxHF2IXY0Jw0EamZi7cw==} + dependencies: + '@daybrush/utils': 1.13.0 + '@egjs/children-differ': 1.0.1 + '@scena/dragscroll': 1.4.0 + '@scena/event-emitter': 1.0.5 + css-styled: 1.0.8 + css-to-mat: 1.1.1 + framework-utils: 1.1.0 + gesto: 1.19.4 + keycon: 1.4.0 + overlap-area: 1.1.0 + dev: false + /selfsigned@2.4.1: resolution: {integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==} engines: {node: '>=10'} @@ -19747,6 +21188,16 @@ packages: dependencies: atomic-sleep: 1.0.0 + /sonner@1.4.41(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-uG511ggnnsw6gcn/X+YKkWPo5ep9il9wYi3QJxHsYe7yTZ4+cOd1wuodOUmOpFuXL+/RE3R04LczdNCDygTDgQ==} + peerDependencies: + react: ^18.0.0 + react-dom: ^18.0.0 + dependencies: + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /sorcery@0.11.0: resolution: {integrity: sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==} hasBin: true @@ -20126,7 +21577,7 @@ packages: dependencies: browserslist: 4.21.10 postcss: 8.4.38 - postcss-selector-parser: 6.0.13 + postcss-selector-parser: 6.0.16 dev: true /stylehacks@6.1.1(postcss@8.4.38): @@ -20155,7 +21606,6 @@ packages: mz: 2.7.0 pirates: 4.0.6 ts-interface-checker: 0.1.13 - dev: true /superjson@2.2.1: resolution: {integrity: sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA==} @@ -20392,6 +21842,14 @@ packages: '@babel/runtime': 7.24.4 dev: false + /tailwindcss-animate@1.0.7(tailwindcss@3.4.3): + resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + dependencies: + tailwindcss: 3.4.3 + dev: true + /tailwindcss@3.4.3: resolution: {integrity: sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==} engines: {node: '>=14.0.0'} @@ -20421,7 +21879,6 @@ packages: sucrase: 3.34.0 transitivePeerDependencies: - ts-node - dev: true /tapable@2.2.1: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} @@ -20534,13 +21991,11 @@ packages: engines: {node: '>=0.8'} dependencies: thenify: 3.3.1 - dev: true /thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} dependencies: any-promise: 1.3.0 - dev: true /thread-stream@2.6.0: resolution: {integrity: sha512-t4eNiKdGwd1EV6tx76mRbrOqwvkxz+ssOiQXEXw88m4p/Xp6679vg16sf39BAstRjHOiWIqp5+J2ylHk3pU30g==} @@ -20575,6 +22030,32 @@ packages: resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==} engines: {node: '>=14.0.0'} + /tippy.js@6.3.7: + resolution: {integrity: sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==} + dependencies: + '@popperjs/core': 2.11.8 + dev: false + + /tiptap-extension-auto-joiner@0.1.3: + resolution: {integrity: sha512-nY3aKeCpVb2WjjVEZkLtEqxsK3KU1zGioyglMhK1sUFNjKDccOfRyz/YDKrHRAVsKJPGnk2A8VA1827iGEAXWQ==} + dev: false + + /tiptap-extension-global-drag-handle@0.1.6: + resolution: {integrity: sha512-kjRFd/glJGTHEglHPNWtML1iINuEBG4eWvWbNIuuXE2LbylFXYHKVgLvZgxilqXSBH/o+lKDEp7/iL3lKvnxGw==} + dev: false + + /tiptap-markdown@0.8.10(@tiptap/core@2.3.2): + resolution: {integrity: sha512-iDVkR2BjAqkTDtFX0h94yVvE2AihCXlF0Q7RIXSJPRSR5I0PA1TMuAg6FHFpmqTn4tPxJ0by0CK7PUMlnFLGEQ==} + peerDependencies: + '@tiptap/core': ^2.0.3 + dependencies: + '@tiptap/core': 2.3.2(@tiptap/pm@2.3.2) + '@types/markdown-it': 13.0.8 + markdown-it: 14.1.0 + markdown-it-task-lists: 2.1.1 + prosemirror-markdown: 1.12.0 + dev: false + /title@3.5.3: resolution: {integrity: sha512-20JyowYglSEeCvZv3EZ0nZ046vLarO37prvV0mbtQV7C8DJPGgN967r8SJkqd3XK3K3lD3/Iyfp3avjfil8Q2Q==} hasBin: true @@ -20690,7 +22171,6 @@ packages: /ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - dev: true /ts-json-schema-generator@1.5.1: resolution: {integrity: sha512-apX5qG2+NA66j7b4AJm8q/DpdTeOsjfh7A3LpKsUiil0FepkNwtN28zYgjrsiiya2/OPhsr/PSjX5FUYg79rCg==} @@ -20787,6 +22267,45 @@ packages: - ts-node dev: true + /tsup@8.0.2(typescript@5.4.5): + resolution: {integrity: sha512-NY8xtQXdH7hDUAZwcQdY/Vzlw9johQsaqf7iwZ6g1DOUlFYQ5/AtVAjTvihhEyeRlGo4dLRVHtrRaL35M1daqQ==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.5.0' + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + dependencies: + bundle-require: 4.0.1(esbuild@0.19.2) + cac: 6.7.14 + chokidar: 3.5.3 + debug: 4.3.4 + esbuild: 0.19.2 + execa: 5.1.1 + globby: 11.1.0 + joycon: 3.1.1 + postcss-load-config: 4.0.1 + resolve-from: 5.0.0 + rollup: 4.16.2 + source-map: 0.8.0-beta.0 + sucrase: 3.34.0 + tree-kill: 1.2.2 + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + - ts-node + dev: true + /tsx@4.7.2: resolution: {integrity: sha512-BCNd4kz6fz12fyrgCTEdZHGJ9fWTGeUzXmQysh0RVocDY3h4frk05ZNCXSy4kIenF7y/QnrdiVpTsyNRn6vlAw==} engines: {node: '>=18.0.0'} @@ -20830,6 +22349,16 @@ packages: dev: false optional: true + /tunnel-rat@0.1.2(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-lR5VHmkPhzdhrM092lI2nACsLO4QubF0/yoOhzX7c+wIpbN1GjHNzCc91QlpxBi+cnx8vVJ+Ur6vL5cEoQPFpQ==} + dependencies: + zustand: 4.5.2(@types/react@18.2.78)(react@18.2.0) + transitivePeerDependencies: + - '@types/react' + - immer + - react + dev: false + /turbo-darwin-64@1.13.2: resolution: {integrity: sha512-CCSuD8CfmtncpohCuIgq7eAzUas0IwSbHfI8/Q3vKObTdXyN8vAo01gwqXjDGpzG9bTEVedD0GmLbD23dR0MLA==} cpu: [x64] @@ -21031,6 +22560,10 @@ packages: engines: {node: '>=14.17'} hasBin: true + /uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + dev: false + /ufo@1.5.3: resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==} @@ -21678,6 +23211,46 @@ packages: /urlpattern-polyfill@8.0.2: resolution: {integrity: sha512-Qp95D4TPJl1kC9SKigDcqgyM2VDVO4RiJc2d4qe5GrYm+zbIQCWWKAFaJNQ4BhdFeDGwBmAxqJBwWSJDb9T3BQ==} + /use-callback-ref@1.3.2(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-elOQwe6Q8gqZgDA8mrh44qRTQqpIHDcZ3hXTLjBe1i4ph8XpNJnO+aQf3NaG+lriLopI4HMx9VjQLfPQ6vhnoA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': ^16.8.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.78 + react: 18.2.0 + tslib: 2.6.2 + dev: false + + /use-debounce@9.0.4(react@18.2.0): + resolution: {integrity: sha512-6X8H/mikbrt0XE8e+JXRtZ8yYVvKkdYRfmIhWZYsP8rcNs9hk3APV8Ua2mFkKRLcJKVdnX2/Vwrmg2GWKUQEaQ==} + engines: {node: '>= 10.0.0'} + peerDependencies: + react: '>=16.8.0' + dependencies: + react: 18.2.0 + dev: false + + /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: + '@types/react': ^16.9.0 || ^17.0.0 || ^18.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + dependencies: + '@types/react': 18.2.78 + detect-node-es: 1.1.0 + react: 18.2.0 + tslib: 2.6.2 + dev: false + /use-sync-external-store@1.2.0(react@18.2.0): resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} peerDependencies: @@ -21923,7 +23496,7 @@ packages: chokidar: 3.6.0 commander: 8.3.0 eslint: 8.57.0 - fast-glob: 3.3.1 + fast-glob: 3.3.2 fs-extra: 11.2.0 npm-run-path: 4.0.1 semver: 7.5.4 @@ -22877,7 +24450,6 @@ packages: /yaml@2.3.1: resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==} engines: {node: '>= 14'} - dev: true /yaml@2.4.1: resolution: {integrity: sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==} @@ -22970,6 +24542,26 @@ packages: /zod@3.23.0: resolution: {integrity: sha512-OFLT+LTocvabn6q76BTwVB0hExEBS0IduTr3cqZyMqEDbOnYmcU+y0tUAYbND4uwclpBGi4I4UUBGzylWpjLGA==} + /zustand@4.5.2(@types/react@18.2.78)(react@18.2.0): + resolution: {integrity: sha512-2cN1tPkDVkwCy5ickKrI7vijSjPksFRfqS6237NzT0vqSsztTNnQdHw9mmN7uBdk3gceVXU0a+21jFzFzAc9+g==} + engines: {node: '>=12.7.0'} + peerDependencies: + '@types/react': '>=16.8' + immer: '>=9.0.6' + react: '>=16.8' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + dependencies: + '@types/react': 18.2.78 + react: 18.2.0 + use-sync-external-store: 1.2.0(react@18.2.0) + dev: false + /zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} dev: false