diff --git a/package.json b/package.json index bf0868c..fbcdbd1 100644 --- a/package.json +++ b/package.json @@ -9,11 +9,16 @@ "start": "next start" }, "dependencies": { - "tiktoken": "^1.0.11", "@radix-ui/react-checkbox": "^1.0.3", "@radix-ui/react-popover": "^1.0.5", "@radix-ui/react-select": "^1.2.0", "@tanstack/react-query": "^4.20.2", + "@tiptap/core": "^2.3.0", + "@tiptap/extension-document": "^2.3.0", + "@tiptap/extension-paragraph": "^2.3.0", + "@tiptap/extension-text": "^2.3.0", + "@tiptap/pm": "^2.3.0", + "@tiptap/react": "^2.3.0", "@trpc/client": "^10.9.0", "@trpc/next": "^10.9.0", "@trpc/react-query": "^10.9.0", @@ -31,6 +36,7 @@ "superjson": "1.9.1", "tailwind-merge": "^1.10.0", "tailwindcss-animate": "^1.0.5", + "tiktoken": "^1.0.11", "zod": "^3.20.6" }, "devDependencies": { diff --git a/src/components/RichEditor.tsx b/src/components/RichEditor.tsx new file mode 100644 index 0000000..d33879a --- /dev/null +++ b/src/components/RichEditor.tsx @@ -0,0 +1,227 @@ +import Document from "@tiptap/extension-document"; +import Paragraph from "@tiptap/extension-paragraph"; +import Text from "@tiptap/extension-text"; +import { + EditorContent, + Extension, + useEditor, + type JSONContent, +} from "@tiptap/react"; +import { useEffect, useMemo } from "react"; +import { Plugin, PluginKey } from "@tiptap/pm/state"; + +import { type Node } from "@tiptap/pm/model"; +import { Decoration, DecorationSet } from "@tiptap/pm/view"; +import Graphemer from "graphemer"; +import { cn } from "~/utils/cn"; +import { type UserModelChoice, getUserSelectedEncoder } from "~/utils/model"; + +const COLORS = [ + "bg-sky-200", + "bg-amber-200", + "bg-blue-200", + "bg-green-200", + "bg-orange-200", + "bg-cyan-200", + "bg-gray-200", + "bg-purple-200", + "bg-indigo-200", + "bg-lime-200", + "bg-rose-200", + "bg-violet-200", + "bg-yellow-200", + "bg-emerald-200", + "bg-zinc-200", + "bg-red-200", + "bg-fuchsia-200", + "bg-pink-200", + "bg-teal-200", +]; + +function convertTextToJSONContent(content: string | null | undefined) { + if (content == null) return []; + const lines = content.split("\n"); + return lines.map( + (line): JSONContent => ({ + type: "paragraph", + content: line ? [{ type: "text", text: line }] : [], + }) + ); +} + +function convertMessageToJSONContent( + content: string | null | undefined +): JSONContent { + if (typeof content === "string") { + return { + type: "doc", + content: convertTextToJSONContent(content), + }; + } + + return { type: "doc", content: [] }; +} + +const key = new PluginKey("tiktokenizer"); + +function binarySearch(haystack: number[], needle: number) { + let left = 0; + let right = haystack.length - 1; + + while (left <= right) { + const cursor = (left + right) >> 1; + if (haystack[cursor]! <= needle) left = cursor + 1; + else right = cursor - 1; + } + + return needle + left; +} + +export const TokenHighlighter = Extension.create<{ model: UserModelChoice }>({ + name: "colorHighlighter", + + addProseMirrorPlugins() { + const encoder = getUserSelectedEncoder(this.options.model); + + const graphemer = new Graphemer(); + const textDecoder = new TextDecoder(); + + function getTokenDecorations(doc: Node): DecorationSet { + let text = ""; + const bounds: number[] = []; + + doc.descendants((node, position) => { + const insert = (position > 0 ? `\n` : "") + node.textContent; + bounds.push(text.length); + text += insert; + + return false; + }); + + const encoding = encoder.encode(text, "all"); + + let textAcc = 0; + let byteAcc: number[] = []; + let tokenAcc: number[] = []; + let inputGraphemes = graphemer.splitGraphemes(text); + + const decorations: Decoration[] = []; + for (let idx = 0; idx < encoding.length; idx++) { + const token = encoding[idx]!; + byteAcc.push(...encoder.decode_single_token_bytes(token)); + tokenAcc.push(token); + + const segmentText = textDecoder.decode(new Uint8Array(byteAcc)); + const graphemes = graphemer.splitGraphemes(segmentText); + + if (graphemes.every((item, idx) => inputGraphemes[idx] === item)) { + decorations.push( + Decoration.inline( + binarySearch(bounds, textAcc), + binarySearch(bounds, textAcc + segmentText.length), + { class: cn(COLORS[decorations.length % COLORS.length]) } + ) + ); + + textAcc += segmentText.length; + + byteAcc = []; + tokenAcc = []; + inputGraphemes = inputGraphemes.slice(graphemes.length); + } + } + + return DecorationSet.create(doc, decorations); + } + + return [ + new Plugin({ + key, + state: { + init: (_, { doc }) => getTokenDecorations(doc), + apply: (transaction, oldState) => + transaction.docChanged + ? getTokenDecorations(transaction.doc) + : oldState, + }, + props: { + decorations(state) { + return this.getState(state); + }, + }, + }), + ]; + }, +}); + +export function RichEditor(props: { + value: string; + onChange: (value: string) => void; + model: UserModelChoice; +}) { + const content = useMemo( + () => convertMessageToJSONContent(props.value), + [props.value] + ); + + const editor = useEditor( + { + extensions: [ + Document, + Paragraph, + Text, + TokenHighlighter.configure({ model: props.model }), + ], + editorProps: { + attributes: { class: cn("outline-none p-3 border rounded-md") }, + }, + + content, + onUpdate: ({ editor }) => { + const json = editor.getJSON(); + const values: Array<{ type: "text"; text: string }> = []; + + // assume root is type="doc" + for (const child of json.content ?? []) { + switch (child.type) { + case "paragraph": { + const text = ( + child.content + ?.map((i) => i.text) + .filter((x): x is string => x != null) ?? [] + ).join(""); + + values.push({ type: "text" as const, text }); + break; + } + case "text": { + if (child.text) + values.push({ type: "text" as const, text: child.text }); + break; + } + } + } + + let result: string = values + .filter((i): i is { type: "text"; text: string } => i.type === "text") + .map((i) => i.text) + .join("\n"); + props.onChange?.(result); + }, + }, + [props.model] + ); + + useEffect(() => { + if (!editor) return; + let { from, to } = editor.state.selection; + editor.commands.setContent(content, false, { preserveWhitespace: "full" }); + editor.commands.setTextSelection({ from, to }); + }, [editor, content]); + + return ( +
+ +
+ ); +} diff --git a/src/pages/index.tsx b/src/pages/index.tsx index eb845c3..07417f4 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -16,41 +16,11 @@ import { } from "~/sections/EncoderSelect"; import { TokenViewer } from "~/sections/TokenViewer"; import { TextArea } from "~/components/Input"; -import { - encoding_for_model, - get_encoding, - type TiktokenModel, - type TiktokenEncoding, -} from "tiktoken"; +import { type TiktokenModel, type TiktokenEncoding } from "tiktoken"; import { getSegments } from "~/utils/segments"; import { useRouter } from "next/router"; - -function getUserSelectedEncoder( - params: { model: TiktokenModel } | { encoder: TiktokenEncoding } -) { - if ("model" in params) { - if ( - params.model === "gpt-4" || - params.model === "gpt-4-32k" || - params.model === "gpt-3.5-turbo" || - params.model === "gpt-4-1106-preview" - ) { - return encoding_for_model(params.model, { - "<|im_start|>": 100264, - "<|im_end|>": 100265, - "<|im_sep|>": 100266, - }); - } - - return encoding_for_model(params.model); - } - - if ("encoder" in params) { - return get_encoding(params.encoder); - } - - throw new Error("Invalid params"); -} +import { RichEditor } from "~/components/RichEditor"; +import { getUserSelectedEncoder } from "../utils/model"; function isChatModel( params: { model: TiktokenModel } | { encoder: TiktokenEncoding } @@ -130,6 +100,8 @@ const Home: NextPage> = ( /> + +
{isChatModel(params) && ( diff --git a/src/utils/model.tsx b/src/utils/model.tsx new file mode 100644 index 0000000..b7fe640 --- /dev/null +++ b/src/utils/model.tsx @@ -0,0 +1,35 @@ +import { + encoding_for_model, + get_encoding, + type TiktokenModel, + type TiktokenEncoding, +} from "tiktoken"; + +export type UserModelChoice = + | { model: TiktokenModel } + | { encoder: TiktokenEncoding }; + +export function getUserSelectedEncoder(params: UserModelChoice) { + if ("model" in params) { + if ( + params.model === "gpt-4" || + params.model === "gpt-4-32k" || + params.model === "gpt-3.5-turbo" || + params.model === "gpt-4-1106-preview" + ) { + return encoding_for_model(params.model, { + "<|im_start|>": 100264, + "<|im_end|>": 100265, + "<|im_sep|>": 100266, + }); + } + + return encoding_for_model(params.model); + } + + if ("encoder" in params) { + return get_encoding(params.encoder); + } + + throw new Error("Invalid params"); +} diff --git a/yarn.lock b/yarn.lock index ef0bfc7..5fd8ba0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -293,6 +293,11 @@ tiny-glob "^0.2.9" tslib "^2.4.0" +"@popperjs/core@^2.9.0": + version "2.11.8" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.11.8.tgz#6b79032e760a0899cd4204710beede972a3a185f" + integrity sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A== + "@radix-ui/number@1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-1.0.0.tgz#4c536161d0de750b3f5d55860fc3de46264f897b" @@ -705,6 +710,11 @@ dependencies: "@babel/runtime" "^7.13.10" +"@remirror/core-constants@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@remirror/core-constants/-/core-constants-2.0.2.tgz#f05eccdc69e3a65e7d524b52548f567904a11a1a" + integrity sha512-dyHY+sMF0ihPus3O27ODd4+agdHMEmuRdyiZJ2CCWjPV5UFmn17ZbElvk6WOGVE4rdCJKZQCrPV2BcikOMLUGQ== + "@rushstack/eslint-patch@^1.1.3": version "1.2.0" resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz#8be36a1f66f3265389e90b5f9c9962146758f728" @@ -730,6 +740,72 @@ "@tanstack/query-core" "4.24.10" use-sync-external-store "^1.2.0" +"@tiptap/core@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.3.0.tgz#5a0b41b63af62860dec6d6b689e2893118f76e83" + integrity sha512-Gk2JN3i5CMkYGmsbyFI7cBUftWa+F7QYmeCLTWfbuy+hCM2OBsnYVKxhggFPGXRL5KLBEgBWeCeWMHfIw3B2MA== + +"@tiptap/extension-bubble-menu@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.3.0.tgz#3447dcc68aaaa76c8327cb636976164986b270c7" + integrity sha512-dqyfQ8idTlhapvt0fxCGvkyjw92pBEwPqmkJ01h3EE8wTh53j0ytOHyMSf1KBuzardxpd8Yya3zlrAcR0Z3DlQ== + dependencies: + tippy.js "^6.3.7" + +"@tiptap/extension-document@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.3.0.tgz#a15e17a48f6d24f317f73a7fff79385a2524f081" + integrity sha512-WC55SMrtlsNOnHXpzbXDzJOp7eKmZV0rXooKmvCDqoiLO/DKpyQXyF+0UHfcRPmUAi2GWFPaer7+p1H9xzcjXg== + +"@tiptap/extension-floating-menu@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.3.0.tgz#ac61ffeac479cdf019a270d23464fd08af6ab931" + integrity sha512-bNY43/yU/+wGfmk2eDV7EPDAN/akbC+YnSKTA5VPJADzscvlrL2HlQrxbd/STIdlwKqdPU5MokcvCChhfZ4f6w== + dependencies: + tippy.js "^6.3.7" + +"@tiptap/extension-paragraph@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.3.0.tgz#959928b57785f4647d807fffe76e63719f2e53c4" + integrity sha512-peCpA7DFqkd0cHb+cHv4YHNoMsXG8tKFNJlCHpLmsZWl2hWmpKgKmUrXAUfzjcFSvkZxn0xYc5oWbqUgg+2LzA== + +"@tiptap/extension-text@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.3.0.tgz#2ebd13dcb4f54b9f72af25fc1015eec474afe89d" + integrity sha512-zkudl0TyKRy/8vHtyo5dMzjBRD0HEUnsS8YOsjR4xwQq5EYUXleRgM1s6lb6Yms2sLUAZRWdDddoQ686iq4zQg== + +"@tiptap/pm@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@tiptap/pm/-/pm-2.3.0.tgz#3f971d5d26401ba0db306f2ee1e317acb8ff6c91" + integrity sha512-4WYqShZBwDyReKvapC0nmeYdOtZbZ31y4MjolpKQaSD4I7kg/oZspC+byUGdvIRsNpRN7i2X0IyvdISKk8gw5Q== + 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.3.2" + prosemirror-inputrules "^1.3.0" + prosemirror-keymap "^1.2.2" + prosemirror-markdown "^1.12.0" + prosemirror-menu "^1.2.4" + prosemirror-model "^1.19.4" + prosemirror-schema-basic "^1.2.2" + prosemirror-schema-list "^1.3.0" + prosemirror-state "^1.4.3" + prosemirror-tables "^1.3.5" + prosemirror-trailing-node "^2.0.7" + prosemirror-transform "^1.8.0" + prosemirror-view "^1.32.7" + +"@tiptap/react@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-2.3.0.tgz#b9a7c29a8bae38a28a3d6ab910da11290addcc58" + integrity sha512-ThgFJQTWYKRClTV2Zg0wBRqfy0EGz3U4NOey7jwncUjSjx5+o9nXbfQAYWDKQFfWyE+wnrBTYfddEP9pHNX5cQ== + dependencies: + "@tiptap/extension-bubble-menu" "^2.3.0" + "@tiptap/extension-floating-menu" "^2.3.0" + "@trpc/client@^10.9.0": version "10.13.2" resolved "https://registry.yarnpkg.com/@trpc/client/-/client-10.13.2.tgz#9303f6b47d587cbf5d3d1cccfa0032174dbe9fae" @@ -1325,6 +1401,11 @@ copy-anything@^3.0.2: dependencies: is-what "^4.1.8" +crelt@^1.0.0: + version "1.0.6" + resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.6.tgz#7cc898ea74e190fb6ef9dae57f8f81cf7302df72" + integrity sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g== + cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -1486,6 +1567,11 @@ enhanced-resolve@^5.10.0: graceful-fs "^4.2.4" tapable "^2.2.0" +entities@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + es-abstract@^1.19.0, es-abstract@^1.20.4: version "1.21.1" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.21.1.tgz#e6105a099967c08377830a0c9cb589d570dd86c6" @@ -2441,6 +2527,13 @@ lilconfig@^2.0.5, lilconfig@^2.0.6: resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4" integrity sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg== +linkify-it@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-5.0.0.tgz#9ef238bfa6dc70bd8e7f9572b52d369af569b421" + integrity sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ== + dependencies: + uc.micro "^2.0.0" + local-pkg@^0.4.3: version "0.4.3" resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.4.3.tgz#0ff361ab3ae7f1c19113d9bb97b98b905dbc4963" @@ -2496,6 +2589,18 @@ magic-string@^0.30.0: dependencies: "@jridgewell/sourcemap-codec" "^1.4.13" +markdown-it@^14.0.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-14.1.0.tgz#3c3c5992883c633db4714ccb4d7b5935d98b7d45" + integrity sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg== + dependencies: + argparse "^2.0.1" + entities "^4.4.0" + linkify-it "^5.0.0" + mdurl "^2.0.0" + punycode.js "^2.3.1" + uc.micro "^2.1.0" + md5-hex@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-3.0.1.tgz#be3741b510591434b2784d79e556eefc2c9a8e5c" @@ -2503,6 +2608,11 @@ md5-hex@^3.0.1: dependencies: blueimp-md5 "^2.10.0" +mdurl@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-2.0.0.tgz#80676ec0433025dd3e17ee983d0fe8de5a2237e0" + integrity sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w== + merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" @@ -2704,6 +2814,11 @@ optionator@^0.9.1: type-check "^0.4.0" word-wrap "^1.2.3" +orderedmap@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/orderedmap/-/orderedmap-2.1.1.tgz#61481269c44031c449915497bf5a4ad273c512d2" + integrity sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g== + p-limit@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" @@ -2886,6 +3001,164 @@ prop-types@^15.8.1: object-assign "^4.1.1" react-is "^16.13.1" +prosemirror-changeset@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/prosemirror-changeset/-/prosemirror-changeset-2.2.1.tgz#dae94b63aec618fac7bb9061648e6e2a79988383" + integrity sha512-J7msc6wbxB4ekDFj+n9gTW/jav/p53kdlivvuppHsrZXCaQdVgRghoZbSS3kwrRyAstRVQ4/+u5k7YfLgkkQvQ== + dependencies: + prosemirror-transform "^1.0.0" + +prosemirror-collab@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/prosemirror-collab/-/prosemirror-collab-1.3.1.tgz#0e8c91e76e009b53457eb3b3051fb68dad029a33" + integrity sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ== + dependencies: + prosemirror-state "^1.0.0" + +prosemirror-commands@^1.0.0, prosemirror-commands@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/prosemirror-commands/-/prosemirror-commands-1.5.2.tgz#e94aeea52286f658cd984270de9b4c3fff580852" + integrity sha512-hgLcPaakxH8tu6YvVAaILV2tXYsW3rAdDR8WNkeKGcgeMVQg3/TMhPdVoh7iAmfgVjZGtcOSjKiQaoeKjzd2mQ== + dependencies: + prosemirror-model "^1.0.0" + prosemirror-state "^1.0.0" + prosemirror-transform "^1.0.0" + +prosemirror-dropcursor@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/prosemirror-dropcursor/-/prosemirror-dropcursor-1.8.1.tgz#49b9fb2f583e0d0f4021ff87db825faa2be2832d" + integrity sha512-M30WJdJZLyXHi3N8vxN6Zh5O8ZBbQCz0gURTfPmTIBNQ5pxrdU7A58QkNqfa98YEjSAL1HUyyU34f6Pm5xBSGw== + dependencies: + prosemirror-state "^1.0.0" + prosemirror-transform "^1.1.0" + prosemirror-view "^1.1.0" + +prosemirror-gapcursor@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/prosemirror-gapcursor/-/prosemirror-gapcursor-1.3.2.tgz#5fa336b83789c6199a7341c9493587e249215cb4" + integrity sha512-wtjswVBd2vaQRrnYZaBCbyDqr232Ed4p2QPtRIUK5FuqHYKGWkEwl08oQM4Tw7DOR0FsasARV5uJFvMZWxdNxQ== + dependencies: + prosemirror-keymap "^1.0.0" + prosemirror-model "^1.0.0" + prosemirror-state "^1.0.0" + prosemirror-view "^1.0.0" + +prosemirror-history@^1.0.0, prosemirror-history@^1.3.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/prosemirror-history/-/prosemirror-history-1.4.0.tgz#1edbce630aaf21b808e5a5cd798a09976ecb1827" + integrity sha512-UUiGzDVcqo1lovOPdi9YxxUps3oBFWAIYkXLu3Ot+JPv1qzVogRbcizxK3LhHmtaUxclohgiOVesRw5QSlMnbQ== + dependencies: + prosemirror-state "^1.2.2" + prosemirror-transform "^1.0.0" + prosemirror-view "^1.31.0" + rope-sequence "^1.3.0" + +prosemirror-inputrules@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/prosemirror-inputrules/-/prosemirror-inputrules-1.4.0.tgz#ef1519bb2cb0d1e0cec74bad1a97f1c1555068bb" + integrity sha512-6ygpPRuTJ2lcOXs9JkefieMst63wVJBgHZGl5QOytN7oSZs3Co/BYbc3Yx9zm9H37Bxw8kVzCnDsihsVsL4yEg== + dependencies: + prosemirror-state "^1.0.0" + prosemirror-transform "^1.0.0" + +prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.1.2, prosemirror-keymap@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/prosemirror-keymap/-/prosemirror-keymap-1.2.2.tgz#14a54763a29c7b2704f561088ccf3384d14eb77e" + integrity sha512-EAlXoksqC6Vbocqc0GtzCruZEzYgrn+iiGnNjsJsH4mrnIGex4qbLdWWNza3AW5W36ZRrlBID0eM6bdKH4OStQ== + dependencies: + prosemirror-state "^1.0.0" + w3c-keyname "^2.2.0" + +prosemirror-markdown@^1.12.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/prosemirror-markdown/-/prosemirror-markdown-1.12.0.tgz#d2de09d37897abf7adb6293d925ff132dac5b0a6" + integrity sha512-6F5HS8Z0HDYiS2VQDZzfZP6A0s/I0gbkJy8NCzzDMtcsz3qrfqyroMMeoSjAmOhDITyon11NbXSzztfKi+frSQ== + dependencies: + markdown-it "^14.0.0" + prosemirror-model "^1.0.0" + +prosemirror-menu@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/prosemirror-menu/-/prosemirror-menu-1.2.4.tgz#3cfdc7c06d10f9fbd1bce29082c498bd11a0a79a" + integrity sha512-S/bXlc0ODQup6aiBbWVsX/eM+xJgCTAfMq/nLqaO5ID/am4wS0tTCIkzwytmao7ypEtjj39i7YbJjAgO20mIqA== + dependencies: + crelt "^1.0.0" + prosemirror-commands "^1.0.0" + prosemirror-history "^1.0.0" + prosemirror-state "^1.0.0" + +prosemirror-model@^1.0.0, prosemirror-model@^1.19.0, prosemirror-model@^1.19.4, prosemirror-model@^1.20.0, prosemirror-model@^1.8.1: + version "1.20.0" + resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.20.0.tgz#4bdc5221f7a58de9fb35d0919687b7e0c765ad53" + integrity sha512-q7AY7vMjKYqDCeoedgUiAgrLabliXxndJuuFmcmc2+YU1SblvnOiG2WEACF2lwAZsMlfLpiAilA3L+TWlDqIsQ== + dependencies: + orderedmap "^2.0.0" + +prosemirror-schema-basic@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/prosemirror-schema-basic/-/prosemirror-schema-basic-1.2.2.tgz#6695f5175e4628aab179bf62e5568628b9cfe6c7" + integrity sha512-/dT4JFEGyO7QnNTe9UaKUhjDXbTNkiWTq/N4VpKaF79bBjSExVV2NXmJpcM7z/gD7mbqNjxbmWW5nf1iNSSGnw== + dependencies: + prosemirror-model "^1.19.0" + +prosemirror-schema-list@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/prosemirror-schema-list/-/prosemirror-schema-list-1.3.0.tgz#05374702cf35a3ba5e7ec31079e355a488d52519" + integrity sha512-Hz/7gM4skaaYfRPNgr421CU4GSwotmEwBVvJh5ltGiffUJwm7C8GfN/Bc6DR1EKEp5pDKhODmdXXyi9uIsZl5A== + dependencies: + prosemirror-model "^1.0.0" + prosemirror-state "^1.0.0" + prosemirror-transform "^1.7.3" + +prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.3.1, prosemirror-state@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/prosemirror-state/-/prosemirror-state-1.4.3.tgz#94aecf3ffd54ec37e87aa7179d13508da181a080" + integrity sha512-goFKORVbvPuAQaXhpbemJFRKJ2aixr+AZMGiquiqKxaucC6hlpHNZHWgz5R7dS4roHiwq9vDctE//CZ++o0W1Q== + dependencies: + prosemirror-model "^1.0.0" + prosemirror-transform "^1.0.0" + prosemirror-view "^1.27.0" + +prosemirror-tables@^1.3.5: + version "1.3.7" + resolved "https://registry.yarnpkg.com/prosemirror-tables/-/prosemirror-tables-1.3.7.tgz#9d296bd432d2bc7dca90f14e5c3b5c5f61277f7a" + integrity sha512-oEwX1wrziuxMtwFvdDWSFHVUWrFJWt929kVVfHvtTi8yvw+5ppxjXZkMG/fuTdFo+3DXyIPSKfid+Be1npKXDA== + dependencies: + prosemirror-keymap "^1.1.2" + prosemirror-model "^1.8.1" + prosemirror-state "^1.3.1" + prosemirror-transform "^1.2.1" + prosemirror-view "^1.13.3" + +prosemirror-trailing-node@^2.0.7: + version "2.0.8" + resolved "https://registry.yarnpkg.com/prosemirror-trailing-node/-/prosemirror-trailing-node-2.0.8.tgz#233ddcbda72de06f9b5d758d2a65a8cac482ea10" + integrity sha512-ujRYhSuhQb1Jsarh1IHqb2KoSnRiD7wAMDGucP35DN7j5af6X7B18PfdPIrbwsPTqIAj0fyOvxbuPsWhNvylmA== + dependencies: + "@remirror/core-constants" "^2.0.2" + escape-string-regexp "^4.0.0" + +prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.2.1, prosemirror-transform@^1.7.3, prosemirror-transform@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.8.0.tgz#a47c64a3c373c1bd0ff46e95be3210c8dda0cd11" + integrity sha512-BaSBsIMv52F1BVVMvOmp1yzD3u65uC3HTzCBQV1WDPqJRQ2LuHKcyfn0jwqodo8sR9vVzMzZyI+Dal5W9E6a9A== + dependencies: + prosemirror-model "^1.0.0" + +prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3, prosemirror-view@^1.27.0, prosemirror-view@^1.31.0, prosemirror-view@^1.32.7: + version "1.33.5" + resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.33.5.tgz#6b41ad9f3de64d8a836ea9cf9999376586af217c" + integrity sha512-AbYYLgg2h5CLARLcTtbNrMARlMwV51jTrezcJkV0NS9J4vi28+rhJ45iIWVSjCcRY209BoySDuJ58b8wIFqdmQ== + dependencies: + prosemirror-model "^1.20.0" + prosemirror-state "^1.0.0" + prosemirror-transform "^1.1.0" + +punycode.js@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode.js/-/punycode.js-2.3.1.tgz#6b53e56ad75588234e79f4affa90972c7dd8cdb7" + integrity sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA== + punycode@^2.1.0: version "2.3.0" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" @@ -3045,6 +3318,11 @@ rollup@^3.18.0: optionalDependencies: fsevents "~2.3.2" +rope-sequence@^1.3.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/rope-sequence/-/rope-sequence-1.3.4.tgz#df85711aaecd32f1e756f76e43a415171235d425" + integrity sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ== + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -3315,6 +3593,13 @@ tinyspy@^2.1.0: resolved "https://registry.yarnpkg.com/tinyspy/-/tinyspy-2.1.0.tgz#bd6875098f988728e6456cfd5ab8cc06498ecdeb" integrity sha512-7eORpyqImoOvkQJCSkL0d0mB4NHHIFAy4b1u8PHdDa7SjGS2njzl6/lyGoZLm+eyYEtlUmFGE0rFj66SWxZgQQ== +tippy.js@^6.3.7: + version "6.3.7" + resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.3.7.tgz#8ccfb651d642010ed9a32ff29b0e9e19c5b8c61c" + integrity sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ== + dependencies: + "@popperjs/core" "^2.9.0" + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -3380,6 +3665,11 @@ typescript@^4.9.5: resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== +uc.micro@^2.0.0, uc.micro@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-2.1.0.tgz#f8d3f7d0ec4c3dea35a7e3c8efa4cb8b45c9e7ee" + integrity sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A== + ufo@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.1.1.tgz#e70265e7152f3aba425bd013d150b2cdf4056d7c" @@ -3496,6 +3786,11 @@ vitest@^0.30.0: vite-node "0.30.0" why-is-node-running "^2.2.2" +w3c-keyname@^2.2.0: + version "2.2.8" + resolved "https://registry.yarnpkg.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz#7b17c8c6883d4e8b86ac8aba79d39e880f8869c5" + integrity sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ== + well-known-symbols@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/well-known-symbols/-/well-known-symbols-2.0.0.tgz#e9c7c07dbd132b7b84212c8174391ec1f9871ba5"