diff --git a/examples/07-collaboration/10-versioning/src/style.css b/examples/07-collaboration/10-versioning/src/style.css index a122f6f54d..0986d3b19f 100644 --- a/examples/07-collaboration/10-versioning/src/style.css +++ b/examples/07-collaboration/10-versioning/src/style.css @@ -1,5 +1,11 @@ +.mantine-AppShell-main { + padding-inline-start: 0 !important; + padding-inline-end: 0 !important; + padding: 0 !important; + height: 100%; +} .wrapper { - height: calc(100vh - 20px); + height: 100%; } .wrapper > .bn-container { @@ -11,14 +17,14 @@ .layout { display: flex; gap: 8px; - height: calc(100vh - 20px); + height: 100vh; + margin-left: 8px; } .editor-panel { display: flex; flex: 1; flex-direction: column; - height: calc(100vh - 20px); min-width: 0; overflow: auto; } @@ -39,7 +45,7 @@ background-color: var(--bn-colors-disabled-background); display: flex; flex-direction: column; - height: calc(100vh - 20px); + height: 100vh; overflow: auto; width: 350px; } @@ -164,7 +170,7 @@ ins { } ins:hover::after { - content: attr(data-user); + content: attr(data-description); position: absolute; top: 100%; left: 50%; @@ -198,7 +204,7 @@ del { } del:hover::after { - content: attr(data-user); + content: attr(data-description); position: absolute; top: 100%; left: 50%; diff --git a/examples/07-collaboration/11-yhub/src/style.css b/examples/07-collaboration/11-yhub/src/style.css index e136fe5913..2296f5fa14 100644 --- a/examples/07-collaboration/11-yhub/src/style.css +++ b/examples/07-collaboration/11-yhub/src/style.css @@ -5,7 +5,7 @@ ins { } ins:hover::after { - content: attr(data-user); + content: attr(data-description); position: absolute; top: 100%; left: 50%; @@ -39,7 +39,7 @@ del { } del:hover::after { - content: attr(data-user); + content: attr(data-description); position: absolute; top: 100%; left: 50%; diff --git a/examples/07-collaboration/14-multi-doc-versioning/.bnexample.json b/examples/07-collaboration/14-multi-doc-versioning/.bnexample.json new file mode 100644 index 0000000000..df85ffb096 --- /dev/null +++ b/examples/07-collaboration/14-multi-doc-versioning/.bnexample.json @@ -0,0 +1,12 @@ +{ + "playground": true, + "docs": false, + "author": "nperez0111", + "tags": ["Advanced", "Collaboration"], + "dependencies": { + "@y/protocols": "^1.0.6-rc.1", + "@y/websocket": "^4.0.0-3", + "@y/y": "^14.0.0-rc.16", + "lib0": "1.0.0-rc.13" + } +} diff --git a/examples/07-collaboration/14-multi-doc-versioning/README.md b/examples/07-collaboration/14-multi-doc-versioning/README.md new file mode 100644 index 0000000000..073064409a --- /dev/null +++ b/examples/07-collaboration/14-multi-doc-versioning/README.md @@ -0,0 +1,17 @@ +# Multi-Document Collaboration with Version History + +This example shows a multi-document collaborative editor with per-document version history, using BlockNote's `VersioningExtension` and Y.js v14. + +**Features:** + +- User picker (per-tab identity via `sessionStorage`) +- Left sidebar with document list (create, rename, delete) +- Collaborative editing with Y.js (including suggestion mode) +- Right sidebar with version history powered by `VersioningSidebar` +- Per-document versioning backed by `localStorage` +- Open multiple tabs with different users via the `?as=` URL param + +**Relevant Docs:** + +- [Versioning](https://www.blocknotejs.org/docs/collaboration/versioning) +- [Y.js Collaboration](https://www.blocknotejs.org/docs/collaboration) diff --git a/examples/07-collaboration/14-multi-doc-versioning/index.html b/examples/07-collaboration/14-multi-doc-versioning/index.html new file mode 100644 index 0000000000..72baf92ec8 --- /dev/null +++ b/examples/07-collaboration/14-multi-doc-versioning/index.html @@ -0,0 +1,14 @@ + + + + + Multi-Document Collaboration with Version History + + + +
+ + + diff --git a/examples/07-collaboration/14-multi-doc-versioning/main.tsx b/examples/07-collaboration/14-multi-doc-versioning/main.tsx new file mode 100644 index 0000000000..1260513388 --- /dev/null +++ b/examples/07-collaboration/14-multi-doc-versioning/main.tsx @@ -0,0 +1,11 @@ +// AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY +import React from "react"; +import { createRoot } from "react-dom/client"; +import App from "./src/App.jsx"; + +const root = createRoot(document.getElementById("root")!); +root.render( + + + , +); diff --git a/examples/07-collaboration/14-multi-doc-versioning/package.json b/examples/07-collaboration/14-multi-doc-versioning/package.json new file mode 100644 index 0000000000..3d1d97cd87 --- /dev/null +++ b/examples/07-collaboration/14-multi-doc-versioning/package.json @@ -0,0 +1,34 @@ +{ + "name": "@blocknote/example-collaboration-multi-doc-versioning", + "description": "AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY", + "type": "module", + "private": true, + "version": "0.12.4", + "scripts": { + "start": "vp dev", + "dev": "vp dev", + "build:prod": "tsc && vp build", + "preview": "vp preview" + }, + "dependencies": { + "@blocknote/ariakit": "latest", + "@blocknote/core": "latest", + "@blocknote/mantine": "latest", + "@blocknote/react": "latest", + "@blocknote/shadcn": "latest", + "@mantine/core": "^9.0.2", + "@mantine/hooks": "^9.0.2", + "react": "^19.2.3", + "react-dom": "^19.2.3", + "@y/protocols": "^1.0.6-rc.1", + "@y/websocket": "^4.0.0-3", + "@y/y": "^14.0.0-rc.16", + "lib0": "1.0.0-rc.13" + }, + "devDependencies": { + "@types/react": "^19.2.3", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^6.0.1", + "vite-plus": "catalog:" + } +} diff --git a/examples/07-collaboration/14-multi-doc-versioning/src/App.tsx b/examples/07-collaboration/14-multi-doc-versioning/src/App.tsx new file mode 100644 index 0000000000..0d04bd3fff --- /dev/null +++ b/examples/07-collaboration/14-multi-doc-versioning/src/App.tsx @@ -0,0 +1,262 @@ +import { useEffect, useRef, useState } from "react"; + +import "./style.css"; +import { USERS } from "./userdata.js"; +import { useCurrentUser, setCurrentUser } from "./identity.js"; +import { useHashRoute, replaceRoute, navigate } from "./router.js"; +import { useDocIndex } from "./docIndex.js"; +import { generateRandomId } from "./utils.js"; +import { LoginScreen } from "./LoginScreen.js"; +import { DocumentList } from "./DocumentList.js"; +import { DocumentEditor } from "./DocumentEditor.js"; +import { preloadDemoDocument } from "./preloadVersions.js"; + +// Seed a demo document with pre-built version history on first load +preloadDemoDocument(); + +export default function App() { + const user = useCurrentUser(); + const segments = useHashRoute(); + + // Route table: + // [] -> if logged in, ensure workspace; else login + // ['login'] -> login screen + // ['w', wsId] -> workspace, no doc selected + // ['w', wsId, docId] -> workspace + doc editor + const [seg0, seg1, seg2] = segments; + + useEffect(() => { + if (user && seg0 !== "w") { + replaceRoute(`/w/${generateRandomId(10)}`); + } + }, [user, seg0]); + + if (!user) { + return ; + } + + if (seg0 !== "w" || !seg1) { + return
Loading...
; + } + + const workspaceId = seg1; + const docId = seg2 || null; + + return ; +} + +function Workspace({ + user, + workspaceId, + docId, +}: { + user: (typeof USERS)[0]; + workspaceId: string; + docId: string | null; +}) { + const index = useDocIndex(); + const activeDoc = docId ? index.docs.find((d) => d.id === docId) : null; + const [copied, setCopied] = useState(false); + + const shareWorkspace = () => { + setCopied(true); + setTimeout(() => setCopied(false), 1800); + const url = window.location.href; + navigator.clipboard?.writeText(url).catch(() => { + window.prompt("Copy this URL to share the workspace", url); + }); + }; + + const signOut = () => { + setCurrentUser(null); + navigate("/"); + }; + + const switchUser = (id: string) => { + if (id === user.id) { + return; + } + setCurrentUser(id); + }; + + return ( +
+
+
+ + + {workspaceId} + + {activeDoc && /} + {activeDoc && ( + {activeDoc.title} + )} +
+
+ + +
+
+
+ + {activeDoc ? ( + index.touch(activeDoc.id)} + /> + ) : ( + 0} + onCreate={() => { + const id = index.create(); + if (id) { + navigate(`/w/${workspaceId}/${id}`); + } + }} + /> + )} +
+
+ ); +} + +function UserMenu({ + user, + onSwitch, + onSignOut, +}: { + user: (typeof USERS)[0]; + onSwitch: (id: string) => void; + onSignOut: () => void; +}) { + const [open, setOpen] = useState(false); + const rootRef = useRef(null); + + useEffect(() => { + if (!open) { + return undefined; + } + const onDocClick = (e: MouseEvent) => { + if (!rootRef.current?.contains(e.target as Node)) { + setOpen(false); + } + }; + const onKey = (e: KeyboardEvent) => { + if (e.key === "Escape") { + setOpen(false); + } + }; + document.addEventListener("mousedown", onDocClick); + document.addEventListener("keydown", onKey); + return () => { + document.removeEventListener("mousedown", onDocClick); + document.removeEventListener("keydown", onKey); + }; + }, [open]); + + const pick = (id: string) => { + setOpen(false); + onSwitch(id); + }; + + return ( +
+ + {open && ( +
+
Switch user
+ {USERS.map((u) => { + const isCurrent = u.id === user.id; + return ( + + ); + })} +
+ +
+ )} +
+ ); +} + +function EmptyDocPane({ + hasDocs, + onCreate, +}: { + hasDocs: boolean; + onCreate: () => void; +}) { + return ( +
+
+

+ {hasDocs ? "Pick a document from the sidebar" : "No documents yet"} +

+

+ {hasDocs + ? "Or create a new one to start writing." + : "Create your first document to start writing and collaborating."} +

+ +
+
+ ); +} diff --git a/examples/07-collaboration/14-multi-doc-versioning/src/DocumentEditor.tsx b/examples/07-collaboration/14-multi-doc-versioning/src/DocumentEditor.tsx new file mode 100644 index 0000000000..aec59a1012 --- /dev/null +++ b/examples/07-collaboration/14-multi-doc-versioning/src/DocumentEditor.tsx @@ -0,0 +1,262 @@ +import "@blocknote/core/fonts/inter.css"; +import { withCollaboration, SuggestionsExtension } from "@blocknote/core/y"; +import { VersioningExtension } from "@blocknote/core/extensions"; +import { + BlockNoteViewEditor, + useCreateBlockNote, + useExtension, + useExtensionState, +} from "@blocknote/react"; +import { BlockNoteView } from "@blocknote/mantine"; +import "@blocknote/mantine/style.css"; +import { useEffect, useMemo, useRef, useState } from "react"; +import * as Y from "@y/y"; +import { fromBase64 } from "lib0/buffer"; +import { WebsocketProvider } from "@y/websocket"; + +import type { DemoUser } from "./userdata.js"; +import { createLocalStorageVersioningEndpoints } from "./localStorageEndpoints.js"; +import { HistorySidebar } from "./HistorySidebar.js"; + +/** + * DocumentEditor mounts one collaborative editor at a time, keyed by docId. + * Switching documents unmounts + remounts this component (via `key` in App). + */ +export function DocumentEditor({ + workspaceId, + docId, + user, + docTitle, + onTouch, +}: { + workspaceId: string; + docId: string; + user: DemoUser; + docTitle: string; + onTouch: () => void; +}) { + const roomName = `bn-multi-doc-${workspaceId}-${docId}`; + + // Stable refs for Y.js resources that persist for this mount + const resourcesRef = useRef<{ + doc: Y.Doc; + suggestionDoc: Y.Doc; + provider: WebsocketProvider; + suggestionProvider: WebsocketProvider; + attributionManager: ReturnType; + versioningEndpoints: ReturnType< + typeof createLocalStorageVersioningEndpoints + >; + } | null>(null); + + if (!resourcesRef.current) { + const doc = new Y.Doc(); + + // Apply pre-seeded document state if available (one-time) + const docStateKey = `bn-doc-state-${docId}`; + const savedState = localStorage.getItem(docStateKey); + if (savedState) { + Y.applyUpdateV2(doc, fromBase64(savedState)); + localStorage.removeItem(docStateKey); + } + + const suggestionDoc = new Y.Doc({ isSuggestionDoc: true }); + const provider = new WebsocketProvider( + "wss://demos.yjs.dev/ws", + roomName, + doc, + { connect: false }, + ); + const suggestionProvider = new WebsocketProvider( + "wss://demos.yjs.dev/ws", + roomName + "-suggestions", + suggestionDoc, + { connect: false }, + ); + const attributionManager = Y.createAttributionManagerFromDiff( + doc, + suggestionDoc, + ); + + provider.connectBc(); + suggestionProvider.connectBc(); + + const versioningEndpoints = createLocalStorageVersioningEndpoints( + `bn-versioning-${docId}`, + ); + + resourcesRef.current = { + doc, + suggestionDoc, + provider, + suggestionProvider, + attributionManager, + versioningEndpoints, + }; + } + + const { + doc, + suggestionDoc, + provider, + suggestionProvider, + attributionManager, + versioningEndpoints, + } = resourcesRef.current; + + // Clean up on unmount + useEffect(() => { + return () => { + provider.destroy(); + suggestionProvider.destroy(); + doc.destroy(); + suggestionDoc.destroy(); + }; + }, []); + + // Throttled touch callback for updatedAt + const touchRef = useRef(onTouch); + touchRef.current = onTouch; + const lastTouchRef = useRef(0); + + useEffect(() => { + const scheduleTouch = () => { + const now = Date.now(); + if (now - lastTouchRef.current >= 5000) { + lastTouchRef.current = now; + touchRef.current(); + } + }; + const onUpdate = ( + _u: Uint8Array, + _origin: unknown, + _doc: Y.Doc, + tr: { local: boolean }, + ) => { + if (tr.local) { + scheduleTouch(); + } + }; + doc.on("update", onUpdate); + return () => { + doc.off("update", onUpdate); + }; + }, [doc]); + + // Connection status tracking + const [connStatus, setConnStatus] = useState("connecting"); + useEffect(() => { + const onStatus = (e: { status: string }) => setConnStatus(e.status); + provider.on("status", onStatus); + if (provider.wsconnected) { + setConnStatus("connected"); + } + return () => { + provider.off("status", onStatus); + }; + }, [provider]); + + const editor = useCreateBlockNote( + withCollaboration({ + collaboration: { + provider, + suggestionDoc, + attributionManager, + fragment: doc.get(), + user: { color: user.color, name: user.name }, + versioningEndpoints, + }, + }), + ); + + // Load existing snapshots on mount so pre-seeded versions show up + const versioning = useExtension(VersioningExtension, { editor }); + useEffect(() => { + versioning.listSnapshots(); + }, [versioning]); + + const { previewedSnapshotId } = useExtensionState(VersioningExtension, { + editor, + }); + + const { enableSuggestions, disableSuggestions, viewSuggestions } = + useExtension(SuggestionsExtension, { editor }); + + const [editingMode, setEditingMode] = useState< + "editing" | "suggestions" | "view-suggestions" + >("editing"); + + // Exit suggestion modes when entering version preview + useEffect(() => { + if (previewedSnapshotId !== undefined && editingMode !== "editing") { + disableSuggestions(); + setEditingMode("editing"); + } + }, [previewedSnapshotId]); + + const modeOptions = useMemo( + () => [ + { value: "editing" as const, label: "Editing" }, + { value: "view-suggestions" as const, label: "Viewing Suggestions" }, + { value: "suggestions" as const, label: "Suggesting" }, + ], + [], + ); + + const changeMode = (next: typeof editingMode) => { + if (next === editingMode) { + return; + } + if (next === "editing") { + disableSuggestions(); + } else if (next === "view-suggestions") { + viewSuggestions(); + } else if (next === "suggestions") { + enableSuggestions(); + } + setEditingMode(next); + }; + + return ( + +
+
+
+
+

{docTitle || "Untitled"}

+
+ {previewedSnapshotId === undefined && ( + + )} + + {connStatus} + +
+
+
+
+ +
+
+ +
+
+ ); +} diff --git a/examples/07-collaboration/14-multi-doc-versioning/src/DocumentList.tsx b/examples/07-collaboration/14-multi-doc-versioning/src/DocumentList.tsx new file mode 100644 index 0000000000..f76e83d0cb --- /dev/null +++ b/examples/07-collaboration/14-multi-doc-versioning/src/DocumentList.tsx @@ -0,0 +1,134 @@ +import { useState } from "react"; + +import type { useDocIndex } from "./docIndex.js"; +import { navigate } from "./router.js"; +import { formatRelative } from "./utils.js"; + +type DocIndex = ReturnType; + +export function DocumentList({ + index, + workspaceId, + activeDocId, +}: { + index: DocIndex; + workspaceId: string; + activeDocId: string | null; +}) { + const [editingId, setEditingId] = useState(null); + const [editingValue, setEditingValue] = useState(""); + + const startEdit = (doc: { id: string; title: string }) => { + setEditingId(doc.id); + setEditingValue(doc.title); + }; + const commitEdit = () => { + if (editingId) { + index.rename(editingId, editingValue.trim() || "Untitled"); + } + setEditingId(null); + setEditingValue(""); + }; + const cancelEdit = () => { + setEditingId(null); + setEditingValue(""); + }; + + const onCreate = () => { + const id = index.create(); + if (id) { + navigate(`/w/${workspaceId}/${id}`); + } + }; + + const onOpen = (id: string) => { + navigate(`/w/${workspaceId}/${id}`); + }; + + const onDelete = (id: string, title: string) => { + if ( + window.confirm(`Delete "${title}"? This can't be undone in the demo.`) + ) { + index.remove(id); + if (activeDocId === id) { + navigate(`/w/${workspaceId}`); + } + } + }; + + return ( + + ); +} diff --git a/examples/07-collaboration/14-multi-doc-versioning/src/HistorySidebar.tsx b/examples/07-collaboration/14-multi-doc-versioning/src/HistorySidebar.tsx new file mode 100644 index 0000000000..851fc01189 --- /dev/null +++ b/examples/07-collaboration/14-multi-doc-versioning/src/HistorySidebar.tsx @@ -0,0 +1,35 @@ +import { VersioningSidebar } from "@blocknote/react"; +import { useState } from "react"; + +export function HistorySidebar() { + const [filter, setFilter] = useState<"named" | "all">("all"); + + return ( + + ); +} diff --git a/examples/07-collaboration/14-multi-doc-versioning/src/LoginScreen.tsx b/examples/07-collaboration/14-multi-doc-versioning/src/LoginScreen.tsx new file mode 100644 index 0000000000..2dfd838f91 --- /dev/null +++ b/examples/07-collaboration/14-multi-doc-versioning/src/LoginScreen.tsx @@ -0,0 +1,39 @@ +import { setCurrentUser } from "./identity.js"; +import { navigate } from "./router.js"; +import { USERS } from "./userdata.js"; + +export function LoginScreen({ redirectTo }: { redirectTo: string }) { + const handlePick = (id: string) => { + setCurrentUser(id); + navigate(redirectTo || "/"); + }; + + return ( +
+
+

Welcome

+

+ Pick a user to continue. This is a demo — there are no passwords. +

+
+ {USERS.map((u) => ( + + ))} +
+
+
+ ); +} diff --git a/examples/07-collaboration/14-multi-doc-versioning/src/docIndex.ts b/examples/07-collaboration/14-multi-doc-versioning/src/docIndex.ts new file mode 100644 index 0000000000..c5571cf85d --- /dev/null +++ b/examples/07-collaboration/14-multi-doc-versioning/src/docIndex.ts @@ -0,0 +1,125 @@ +import { useCallback, useEffect, useMemo, useState } from "react"; + +import { generateDocTitle, generateRandomId } from "./utils.js"; + +export type DocEntry = { + id: string; + title: string; + createdAt: number; + updatedAt: number; +}; + +const STORAGE_KEY = "bn-multi-doc-index"; + +function readDocs(): DocEntry[] { + try { + const raw = localStorage.getItem(STORAGE_KEY); + if (!raw) { + return []; + } + const docs = JSON.parse(raw) as DocEntry[]; + return docs.sort((a, b) => a.createdAt - b.createdAt); + } catch { + return []; + } +} + +function writeDocs(docs: DocEntry[]) { + localStorage.setItem(STORAGE_KEY, JSON.stringify(docs)); +} + +/** + * Simple localStorage-backed document index. Provides create, rename, delete, + * and touch (update timestamp) operations. Uses a custom event to sync across + * hook instances within the same tab. + */ +export function useDocIndex() { + const [docs, setDocs] = useState(readDocs); + + // Listen for changes from other calls within the same tab + useEffect(() => { + const handler = () => setDocs(readDocs()); + window.addEventListener("bn-doc-index-change", handler); + window.addEventListener("storage", (e) => { + if (e.key === STORAGE_KEY) { + handler(); + } + }); + return () => { + window.removeEventListener("bn-doc-index-change", handler); + }; + }, []); + + const notify = useCallback(() => { + window.dispatchEvent(new Event("bn-doc-index-change")); + }, []); + + const create = useCallback( + (title?: string): string => { + const id = generateRandomId(6); + const now = Date.now(); + const entry: DocEntry = { + id, + title: title ?? generateDocTitle(), + createdAt: now, + updatedAt: now, + }; + const current = readDocs(); + current.push(entry); + writeDocs(current); + notify(); + return id; + }, + [notify], + ); + + const rename = useCallback( + (id: string, title: string) => { + const current = readDocs(); + const entry = current.find((d) => d.id === id); + if (!entry) { + return; + } + entry.title = title; + entry.updatedAt = Date.now(); + writeDocs(current); + notify(); + }, + [notify], + ); + + const remove = useCallback( + (id: string) => { + const current = readDocs().filter((d) => d.id !== id); + writeDocs(current); + // Also clean up versioning data for this doc + try { + localStorage.removeItem(`bn-versioning-${id}`); + localStorage.removeItem(`bn-versioning-${id}-contents`); + } catch { + /* ignore */ + } + notify(); + }, + [notify], + ); + + const touch = useCallback( + (id: string) => { + const current = readDocs(); + const entry = current.find((d) => d.id === id); + if (!entry) { + return; + } + entry.updatedAt = Date.now(); + writeDocs(current); + notify(); + }, + [notify], + ); + + return useMemo( + () => ({ docs, create, rename, remove, touch }), + [docs, create, rename, remove, touch], + ); +} diff --git a/examples/07-collaboration/14-multi-doc-versioning/src/identity.ts b/examples/07-collaboration/14-multi-doc-versioning/src/identity.ts new file mode 100644 index 0000000000..6bd101a297 --- /dev/null +++ b/examples/07-collaboration/14-multi-doc-versioning/src/identity.ts @@ -0,0 +1,61 @@ +import { useEffect, useState } from "react"; + +import { type DemoUser, USERS } from "./userdata.js"; + +const STORAGE_KEY = "bn-multi-doc-user"; + +/** + * Per-tab identity via sessionStorage so two browser tabs can hold different + * users simultaneously. The `?as=` URL param takes precedence and is + * persisted into sessionStorage. + */ +export const getCurrentUser = (): DemoUser | null => { + try { + const fromUrl = new URLSearchParams(window.location.search).get("as"); + if (fromUrl && USERS.some((u) => u.id === fromUrl)) { + sessionStorage.setItem(STORAGE_KEY, fromUrl); + return USERS.find((u) => u.id === fromUrl)!; + } + const id = sessionStorage.getItem(STORAGE_KEY); + return USERS.find((u) => u.id === id) ?? null; + } catch { + return null; + } +}; + +export const setCurrentUser = (id: string | null): void => { + try { + if (id) { + sessionStorage.setItem(STORAGE_KEY, id); + } else { + sessionStorage.removeItem(STORAGE_KEY); + } + } catch { + /* ignore */ + } + // Keep the ?as= URL param in sync + try { + const url = new URL(window.location.href); + if (url.searchParams.has("as")) { + if (id) { + url.searchParams.set("as", id); + } else { + url.searchParams.delete("as"); + } + window.history.replaceState(null, "", url.toString()); + } + } catch { + /* ignore */ + } + window.dispatchEvent(new Event("bn-identity-change")); +}; + +export const useCurrentUser = (): DemoUser | null => { + const [user, setUser] = useState(getCurrentUser); + useEffect(() => { + const handler = () => setUser(getCurrentUser()); + window.addEventListener("bn-identity-change", handler); + return () => window.removeEventListener("bn-identity-change", handler); + }, []); + return user; +}; diff --git a/examples/07-collaboration/14-multi-doc-versioning/src/localStorageEndpoints.ts b/examples/07-collaboration/14-multi-doc-versioning/src/localStorageEndpoints.ts new file mode 100644 index 0000000000..6ac57db8ba --- /dev/null +++ b/examples/07-collaboration/14-multi-doc-versioning/src/localStorageEndpoints.ts @@ -0,0 +1,119 @@ +import * as Y from "@y/y"; +import { toBase64, fromBase64 } from "lib0/buffer"; + +import { + type CreateSnapshotOptions, + sortSnapshotsNewestFirst, + type VersioningEndpoints, + type VersionSnapshot, +} from "@blocknote/core/extensions"; + +function getContentsKey(storageKey: string) { + return `${storageKey}-contents`; +} + +function readSnapshots(storageKey: string): VersionSnapshot[] { + return sortSnapshotsNewestFirst( + JSON.parse(localStorage.getItem(storageKey) ?? "[]") as VersionSnapshot[], + ); +} + +function writeSnapshots(storageKey: string, snapshots: VersionSnapshot[]) { + localStorage.setItem( + storageKey, + JSON.stringify(sortSnapshotsNewestFirst(snapshots)), + ); +} + +function readContents(storageKey: string): Record { + return JSON.parse( + localStorage.getItem(getContentsKey(storageKey)) ?? "{}", + ) as Record; +} + +function writeContents(storageKey: string, contents: Record) { + localStorage.setItem(getContentsKey(storageKey), JSON.stringify(contents)); +} + +/** + * Per-document localStorage-backed versioning endpoints. + * Each document gets its own storage key so snapshots are isolated. + */ +export function createLocalStorageVersioningEndpoints( + storageKey: string, +): VersioningEndpoints { + const listSnapshots: VersioningEndpoints["list"] = async () => + readSnapshots(storageKey); + + const createSnapshot = async ( + fragment: Y.Type, + options?: CreateSnapshotOptions, + ): Promise => { + const snapshot = { + id: crypto.randomUUID(), + name: options?.name, + createdAt: Date.now(), + updatedAt: Date.now(), + restoredFromSnapshotId: options?.restoredFromSnapshotId, + } satisfies VersionSnapshot; + + const contents = readContents(storageKey); + contents[snapshot.id] = toBase64(Y.encodeStateAsUpdateV2(fragment.doc!)); + writeContents(storageKey, contents); + + writeSnapshots(storageKey, [snapshot, ...readSnapshots(storageKey)]); + + return snapshot; + }; + + const fetchSnapshotContent: VersioningEndpoints["getContent"] = async ( + id, + ) => { + const encoded = readContents(storageKey)[id]; + if (encoded === undefined) { + throw new Error(`Document snapshot ${id} could not be found.`); + } + return fromBase64(encoded); + }; + + const restoreSnapshot: VersioningEndpoints["restore"] = async ( + fragment, + id, + ) => { + await createSnapshot(fragment, { name: "Backup" }); + + const snapshotContent = await fetchSnapshotContent(id); + const yDoc = new Y.Doc(); + Y.applyUpdateV2(yDoc, snapshotContent); + + await createSnapshot(yDoc.get(), { + name: "Restored Snapshot", + restoredFromSnapshotId: id, + }); + + return snapshotContent; + }; + + const updateSnapshotName: VersioningEndpoints["updateSnapshotName"] = async ( + id, + name, + ) => { + const snapshots = readSnapshots(storageKey); + const snapshot = snapshots.find((s) => s.id === id); + if (snapshot === undefined) { + throw new Error(`Document snapshot ${id} could not be found.`); + } + + snapshot.name = name; + snapshot.updatedAt = Date.now(); + writeSnapshots(storageKey, snapshots); + }; + + return { + list: listSnapshots, + create: createSnapshot, + getContent: fetchSnapshotContent, + restore: restoreSnapshot, + updateSnapshotName, + }; +} diff --git a/examples/07-collaboration/14-multi-doc-versioning/src/preloadVersions.ts b/examples/07-collaboration/14-multi-doc-versioning/src/preloadVersions.ts new file mode 100644 index 0000000000..f259446b66 --- /dev/null +++ b/examples/07-collaboration/14-multi-doc-versioning/src/preloadVersions.ts @@ -0,0 +1,245 @@ +import * as Y from "@y/y"; +import { toBase64 } from "lib0/buffer"; +import { BlockNoteEditor, type PartialBlock } from "@blocknote/core"; +import { withCollaboration } from "@blocknote/core/y"; +import { + sortSnapshotsNewestFirst, + type VersionSnapshot, +} from "@blocknote/core/extensions"; + +import versionData from "./versionData.json"; + +export const DEMO_DOC_ID = "demo-doc"; +export const DEMO_DOC_TITLE = "La Suite Docs"; + +const STORAGE_KEY = "bn-multi-doc-index"; +const VERSIONING_KEY = `bn-versioning-${DEMO_DOC_ID}`; +const VERSIONING_CONTENTS_KEY = `${VERSIONING_KEY}-contents`; +const DOC_STATE_KEY = `bn-doc-state-${DEMO_DOC_ID}`; + +// --------------------------------------------------------------------------- +// Version data types +// +// versionData.json describes an initial document state plus a series of +// transitions (incremental edits). Each transition has a name and a list of +// operations (insert / update / delete) that are applied in order. +// --------------------------------------------------------------------------- + +type Operation = + | { type: "insert"; index: number; block: PartialBlock } + | { type: "update"; index: number; block: PartialBlock } + | { type: "delete"; index: number }; + +type Transition = { + name: string; + operations: Operation[]; +}; + +type VersionData = { + initialVersion: string; + initialBlocks: PartialBlock[]; + transitions: Transition[]; +}; + +const data = versionData as unknown as VersionData; + +// Spread versions across the last 4 hours, oldest first +const TOTAL_SPAN_MS = 4 * 60 * 60 * 1000; // 4 hours +const NEWEST_OFFSET_MS = 5 * 60 * 1000; // 5 minutes ago + +// Total number of snapshots = 1 (initial) + transitions.length +const TOTAL_VERSIONS = 1 + data.transitions.length; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +/** + * Applies a single transition's operations to the editor. + * + * Operations are applied **sequentially in order**. Each operation's `index` + * references the document state after all prior operations in the same + * transition have already been applied. This means no index adjustment + * logic is needed – just apply them one by one. + */ +function applyTransition( + editor: BlockNoteEditor, + transition: Transition, +): void { + for (const op of transition.operations) { + switch (op.type) { + case "update": { + const block = editor.document[op.index]; + if (block) { + editor.updateBlock(block, op.block); + } + break; + } + case "delete": { + const block = editor.document[op.index]; + if (block) { + editor.removeBlocks([block]); + } + break; + } + case "insert": { + const refBlock = editor.document[op.index]; + if (refBlock) { + editor.insertBlocks([op.block], refBlock, "before"); + } else { + // Past the end – append after last block + const lastBlock = editor.document[editor.document.length - 1]; + if (lastBlock) { + editor.insertBlocks([op.block], lastBlock, "after"); + } + } + break; + } + } + } +} + +/** + * Builds all version snapshots using a single Y.Doc that is progressively + * mutated via the transition operations. Each snapshot captures the cumulative + * Y.Doc state at that point, so all snapshots share the same Yjs history and + * produce meaningful diffs when compared. + * + * Returns an array of { name, base64 } in chronological order (oldest first). + */ +function buildAllSnapshots(): { name: string; base64: string }[] { + const doc = new Y.Doc(); + const fragment = doc.get(); + + const editor = BlockNoteEditor.create( + withCollaboration({ + collaboration: { + fragment, + user: { name: "System", color: "#000000" }, + provider: undefined, + }, + }), + ); + + // Mount so ProseMirror initializes + const el = document.createElement("div"); + editor.mount(el); + + const results: { name: string; base64: string }[] = []; + + // 1. Set initial content and snapshot + editor.replaceBlocks(editor.document, data.initialBlocks); + results.push({ + name: data.initialVersion, + base64: toBase64(Y.encodeStateAsUpdateV2(doc)), + }); + + // 2. Apply each transition incrementally and snapshot after each + for (const transition of data.transitions) { + applyTransition(editor, transition); + results.push({ + name: transition.name, + base64: toBase64(Y.encodeStateAsUpdateV2(doc)), + }); + } + + // Clean up + editor.unmount(); + doc.destroy(); + + return results; +} + +// --------------------------------------------------------------------------- +// Preload entry point +// --------------------------------------------------------------------------- + +/** + * Seeds a demo document with pre-built version history into localStorage. + * This is idempotent -- if the versioning data already exists, it does nothing. + * + * Also ensures a DocEntry exists in the doc index so the document appears + * in the sidebar immediately. + */ +export function preloadDemoDocument(): void { + // Guard: don't overwrite existing version data + if (localStorage.getItem(VERSIONING_KEY)) { + // Still ensure the doc index entry exists + ensureDocIndexEntry(); + return; + } + + const now = Date.now(); + const builtSnapshots = buildAllSnapshots(); + const snapshots: VersionSnapshot[] = []; + const contents: Record = {}; + + for (let i = 0; i < builtSnapshots.length; i++) { + const snap = builtSnapshots[i]!; + const id = crypto.randomUUID(); + // Spread evenly: oldest = TOTAL_SPAN_MS ago, newest = NEWEST_OFFSET_MS ago + const offsetMs = + TOTAL_SPAN_MS - + (i / (TOTAL_VERSIONS - 1)) * (TOTAL_SPAN_MS - NEWEST_OFFSET_MS); + const ts = now - offsetMs; + + snapshots.push({ + id, + name: snap.name, + createdAt: ts, + updatedAt: ts, + }); + + contents[id] = snap.base64; + } + + // Write versioning data + localStorage.setItem( + VERSIONING_KEY, + JSON.stringify(sortSnapshotsNewestFirst(snapshots)), + ); + localStorage.setItem(VERSIONING_CONTENTS_KEY, JSON.stringify(contents)); + + // Store the final version's Y.Doc state so the editor can load it + const lastBase64 = builtSnapshots[builtSnapshots.length - 1]!.base64; + localStorage.setItem(DOC_STATE_KEY, lastBase64); + + // Ensure the doc appears in the sidebar + ensureDocIndexEntry(); +} + +/** + * Ensures a DocEntry for the demo document exists in the doc index. + */ +function ensureDocIndexEntry(): void { + type DocEntry = { + id: string; + title: string; + createdAt: number; + updatedAt: number; + }; + + let docs: DocEntry[]; + try { + docs = JSON.parse(localStorage.getItem(STORAGE_KEY) ?? "[]") as DocEntry[]; + } catch { + docs = []; + } + + if (docs.some((d) => d.id === DEMO_DOC_ID)) { + return; + } + + const now = Date.now(); + docs.push({ + id: DEMO_DOC_ID, + title: DEMO_DOC_TITLE, + createdAt: now - TOTAL_SPAN_MS, // match first version timestamp + updatedAt: now - NEWEST_OFFSET_MS, // match latest version timestamp + }); + + localStorage.setItem(STORAGE_KEY, JSON.stringify(docs)); + + // Notify other hook instances within the same tab + window.dispatchEvent(new Event("bn-doc-index-change")); +} diff --git a/examples/07-collaboration/14-multi-doc-versioning/src/router.ts b/examples/07-collaboration/14-multi-doc-versioning/src/router.ts new file mode 100644 index 0000000000..634e9034e4 --- /dev/null +++ b/examples/07-collaboration/14-multi-doc-versioning/src/router.ts @@ -0,0 +1,36 @@ +import { useEffect, useState } from "react"; + +const parse = (): string[] => { + const raw = window.location.hash.replace(/^#\/?/, ""); + const segments = raw.split("?")[0].split("/").filter(Boolean); + return segments; +}; + +export const useHashRoute = (): string[] => { + const [segments, setSegments] = useState(parse); + useEffect(() => { + const handler = () => setSegments(parse()); + window.addEventListener("hashchange", handler); + return () => window.removeEventListener("hashchange", handler); + }, []); + return segments; +}; + +export const navigate = (path: string): void => { + const target = path.startsWith("#") + ? path + : "#" + (path.startsWith("/") ? path : "/" + path); + if (window.location.hash === target) { + return; + } + window.location.hash = target.slice(1); +}; + +export const replaceRoute = (path: string): void => { + const target = path.startsWith("#") + ? path + : "#" + (path.startsWith("/") ? path : "/" + path); + const url = window.location.pathname + window.location.search + target; + window.history.replaceState(null, "", url); + window.dispatchEvent(new HashChangeEvent("hashchange")); +}; diff --git a/examples/07-collaboration/14-multi-doc-versioning/src/style.css b/examples/07-collaboration/14-multi-doc-versioning/src/style.css new file mode 100644 index 0000000000..3a59c020c0 --- /dev/null +++ b/examples/07-collaboration/14-multi-doc-versioning/src/style.css @@ -0,0 +1,854 @@ +/* ===== Theme tokens ===== */ + +:root { + --bg: #ffffff; + --bg-elevated: #f8f9fb; + --bg-inset: #f1f3f6; + --bg-hover: #eef0f4; + --bg-active: #e6e9ef; + --border: #e3e6ec; + --border-strong: #cfd3da; + --text: #1a1d22; + --text-muted: #5b6370; + --text-subtle: #8a909b; + --accent: #2564eb; + --accent-hover: #1d4fc2; + --accent-soft: #eaf0ff; + --danger: #d64545; + --danger-hover: #b13535; + --success: #1e9968; + --shadow-sm: + 0 1px 2px rgba(15, 23, 42, 0.04), 0 1px 1px rgba(15, 23, 42, 0.04); + --shadow-md: + 0 4px 10px rgba(15, 23, 42, 0.06), 0 1px 2px rgba(15, 23, 42, 0.04); + --shadow-lg: + 0 20px 40px rgba(15, 23, 42, 0.12), 0 4px 10px rgba(15, 23, 42, 0.06); + --radius-sm: 6px; + --radius-md: 8px; + --radius-lg: 12px; + --ins-bg: rgba(30, 153, 104, 0.18); + --ins-border: rgba(30, 153, 104, 0.7); + --del-bg: rgba(214, 69, 69, 0.14); + --del-border: rgba(214, 69, 69, 0.75); + --del-text: rgba(214, 69, 69, 0.9); + --mod-bg: rgba(24, 122, 220, 0.16); + --mod-border: rgba(24, 122, 220, 0.7); +} + +[data-mantine-color-scheme="dark"] { + --bg: #15171c; + --bg-elevated: #1b1e24; + --bg-inset: #20242c; + --bg-hover: #262a33; + --bg-active: #2f343e; + --border: #2a2f38; + --border-strong: #3a404b; + --text: #e9ebef; + --text-muted: #9aa2b1; + --text-subtle: #6e7682; + --accent: #5b8cff; + --accent-hover: #769fff; + --accent-soft: #1b2744; + --danger: #e96a6a; + --danger-hover: #f18787; + --success: #3db987; + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3); + --shadow-md: 0 4px 10px rgba(0, 0, 0, 0.4); + --shadow-lg: 0 20px 40px rgba(0, 0, 0, 0.5), 0 4px 10px rgba(0, 0, 0, 0.4); + --ins-bg: rgba(61, 185, 135, 0.28); + --ins-border: rgba(103, 214, 165, 0.85); + --del-bg: rgba(233, 106, 106, 0.24); + --del-border: rgba(240, 160, 160, 0.85); + --del-text: #f0a0a0; + --mod-bg: rgba(91, 140, 255, 0.28); + --mod-border: rgba(166, 190, 255, 0.85); +} + +/* ===== Base ===== */ + +* { + box-sizing: border-box; +} + +html, +body, +#root { + height: 100%; + margin: 0; +} + +body { + background: var(--bg); + color: var(--text); + font-family: + -apple-system, BlinkMacSystemFont, "Segoe UI", "Inter", system-ui, + sans-serif; + font-size: 14px; + line-height: 1.5; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +button { + font: inherit; + color: inherit; + background: none; + border: none; + cursor: pointer; + padding: 0; +} + +/* ===== Shared primitives ===== */ + +.btn { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 6px 12px; + border-radius: var(--radius-sm); + background: var(--bg-elevated); + color: var(--text); + border: 1px solid var(--border); + cursor: pointer; + transition: + background 0.12s ease, + border-color 0.12s ease, + transform 0.05s ease; + white-space: nowrap; + font-weight: 500; +} +.btn:hover:not(:disabled) { + background: var(--bg-hover); + border-color: var(--border-strong); +} +.btn:active:not(:disabled) { + transform: translateY(0.5px); +} +.btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} +.btn-sm { + padding: 4px 10px; + font-size: 12.5px; +} +.btn-primary { + background: var(--accent); + color: white; + border-color: var(--accent); +} +.btn-primary:hover:not(:disabled) { + background: var(--accent-hover); + border-color: var(--accent-hover); +} +.btn-icon { + display: inline-flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + border-radius: var(--radius-sm); + color: var(--text-muted); + transition: + background 0.12s ease, + color 0.12s ease; +} +.btn-icon:hover { + background: var(--bg-hover); + color: var(--text); +} +.btn-icon-danger:hover { + background: var(--bg-hover); + color: var(--danger); +} + +/* ===== Login screen ===== */ + +.login-screen { + min-height: 100vh; + display: flex; + align-items: center; + justify-content: center; + background: var(--bg); +} +.login-card { + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: var(--radius-lg); + padding: 48px 40px; + max-width: 420px; + width: 100%; + box-shadow: var(--shadow-lg); +} +.login-title { + margin: 0 0 8px; + font-size: 28px; + font-weight: 600; + letter-spacing: -0.01em; +} +.login-subtitle { + margin: 0 0 28px; + color: var(--text-muted); + font-size: 14px; +} +.login-users { + display: flex; + flex-direction: column; + gap: 10px; +} +.login-user { + display: flex; + align-items: center; + gap: 14px; + padding: 12px 14px; + border: 1px solid var(--border); + border-radius: var(--radius-md); + background: var(--bg); + transition: + background 0.12s ease, + border-color 0.12s ease; + text-align: left; +} +.login-user:hover { + background: var(--bg-hover); + border-color: var(--user-color, var(--border-strong)); +} +.login-avatar { + width: 32px; + height: 32px; + border-radius: 50%; + display: inline-flex; + align-items: center; + justify-content: center; + color: white; + font-weight: 600; + font-size: 14px; + flex-shrink: 0; +} +.login-user-name { + font-size: 15px; + font-weight: 500; +} + +/* ===== App shell ===== */ + +.app-shell { + display: flex; + flex-direction: column; + height: 100vh; + background: var(--bg); +} + +.app-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px 16px; + border-bottom: 1px solid var(--border); + background: var(--bg-elevated); + min-height: 52px; + flex-shrink: 0; +} +.app-header-left, +.app-header-right { + display: flex; + align-items: center; + gap: 10px; +} +.workspace-badge { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 4px 10px; + background: var(--bg-inset); + border: 1px solid var(--border); + border-radius: 999px; + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, monospace; + font-size: 12px; + color: var(--text-muted); +} +.workspace-badge-dot { + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--success); +} +.app-header-sep { + color: var(--text-subtle); +} +.app-header-doctitle { + font-weight: 500; + color: var(--text); + max-width: 400px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.user-menu { + position: relative; + display: inline-block; +} +.user-pill { + display: inline-flex; + align-items: center; + gap: 8px; + padding: 4px 10px 4px 6px; + border: 1px solid var(--border); + border-radius: 999px; + background: var(--bg); + cursor: pointer; + transition: + background 0.12s ease, + border-color 0.12s ease; +} +.user-pill:hover { + background: var(--bg-hover); + border-color: var(--border-strong); +} +.user-avatar { + width: 22px; + height: 22px; + border-radius: 50%; + display: inline-flex; + align-items: center; + justify-content: center; + color: white; + font-weight: 600; + font-size: 11px; + flex-shrink: 0; +} +.user-name { + font-size: 13px; + font-weight: 500; +} +.user-caret { + font-size: 10px; + color: var(--text-muted); + margin-left: -2px; +} +.user-menu-panel { + position: absolute; + top: calc(100% + 6px); + right: 0; + min-width: 200px; + padding: 6px; + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: var(--radius-md); + box-shadow: var(--shadow-lg); + z-index: 50; + display: flex; + flex-direction: column; + gap: 2px; +} +.user-menu-label { + font-size: 11px; + text-transform: uppercase; + letter-spacing: 0.04em; + color: var(--text-muted); + padding: 6px 8px 4px; +} +.user-menu-item { + display: flex; + align-items: center; + gap: 10px; + padding: 6px 8px; + border-radius: var(--radius-sm); + text-align: left; + font-size: 13px; + color: var(--text); + cursor: pointer; + transition: background 0.1s ease; +} +.user-menu-item:hover { + background: var(--bg-hover); +} +.user-menu-item-name { + flex: 1; + font-weight: 500; +} +.user-menu-check { + color: var(--text-muted); + font-size: 12px; +} +.user-menu-divider { + height: 1px; + background: var(--border); + margin: 4px 0; +} +.user-menu-item-signout { + color: var(--text-muted); +} +.user-menu-item-signout:hover { + color: var(--text); +} + +/* Override BlockNote's .bn-container defaults (set by playground) */ +.app-body .bn-container { + margin: 0; + max-width: none; + padding: 0; + height: 100%; +} + +.app-body { + flex: 1; + display: grid; + grid-template-columns: 260px 1fr; + min-height: 0; +} + +/* ===== Document list (left sidebar) ===== */ + +.doc-list { + border-right: 1px solid var(--border); + background: var(--bg-elevated); + overflow-y: auto; + display: flex; + flex-direction: column; +} +.doc-list-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 14px 16px 8px; + position: sticky; + top: 0; + background: var(--bg-elevated); +} +.doc-list-label { + font-size: 11px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.06em; + color: var(--text-subtle); +} +.doc-list-empty { + padding: 40px 16px; + text-align: center; + color: var(--text-muted); + font-size: 13px; + line-height: 1.6; +} +.doc-list-items { + list-style: none; + padding: 4px 6px 8px; + margin: 0; + display: flex; + flex-direction: column; + gap: 2px; +} +.doc-list-item { + display: flex; + align-items: center; + gap: 4px; + padding: 2px 4px; + border-radius: var(--radius-sm); + position: relative; +} +.doc-list-item:hover { + background: var(--bg-hover); +} +.doc-list-item.active { + background: var(--bg-active); +} +.doc-list-item-open { + flex: 1; + text-align: left; + padding: 6px 8px; + display: flex; + flex-direction: column; + gap: 2px; + min-width: 0; +} +.doc-list-item-title { + font-size: 13.5px; + font-weight: 500; + color: var(--text); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.doc-list-item-meta { + font-size: 11.5px; + color: var(--text-subtle); +} +.doc-list-item-input { + flex: 1; + padding: 6px 8px; + border: 1px solid var(--accent); + border-radius: var(--radius-sm); + background: var(--bg); + color: var(--text); + font: inherit; + outline: none; +} +.doc-list-item-actions { + display: none; + gap: 2px; + padding-right: 4px; +} +.doc-list-item:hover .doc-list-item-actions { + display: inline-flex; +} + +/* ===== Empty doc pane ===== */ + +.doc-empty { + display: flex; + align-items: center; + justify-content: center; + background: var(--bg); +} +.doc-empty-inner { + text-align: center; + padding: 40px; + max-width: 420px; +} +.doc-empty-title { + font-size: 20px; + font-weight: 600; + margin: 0 0 8px; + color: var(--text); +} +.doc-empty-sub { + color: var(--text-muted); + font-size: 14px; + margin: 0 0 20px; +} + +/* ===== Document workspace (editor + history) ===== */ + +.doc-workspace { + display: grid; + grid-template-columns: 1fr 320px; + min-width: 0; + min-height: 0; + height: 100%; + overflow: hidden; +} + +.doc-main { + display: flex; + flex-direction: column; + min-height: 0; + min-width: 0; + background: var(--bg); + overflow: hidden; +} + +.doc-main-header { + padding: 14px 24px; + border-bottom: 1px solid var(--border); + flex-shrink: 0; +} +.doc-main-title-row { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; +} +.doc-main-title { + font-size: 18px; + font-weight: 600; + margin: 0; + color: var(--text); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.doc-main-controls { + display: flex; + align-items: center; + gap: 10px; + flex-shrink: 0; +} + +.mode-select { + appearance: none; + -webkit-appearance: none; + padding: 6px 28px 6px 12px; + background: var(--bg-elevated); + border: 1px solid var(--border); + border-radius: var(--radius-sm); + color: var(--text); + font: inherit; + font-size: 13px; + font-weight: 500; + cursor: pointer; + background-image: url("data:image/svg+xml;utf8,"); + background-repeat: no-repeat; + background-position: right 10px center; + transition: + background-color 0.12s ease, + border-color 0.12s ease; +} +.mode-select:hover { + background-color: var(--bg-hover); + border-color: var(--border-strong); +} +.mode-select:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 1px; +} + +.doc-status { + align-self: flex-start; + font-size: 10.5px; + padding: 1px 7px; + border-radius: 999px; + text-transform: capitalize; + font-weight: 500; + letter-spacing: 0.01em; + background: var(--bg-inset); + color: var(--text-muted); +} +.doc-status-connected { + background: rgba(30, 153, 104, 0.12); + color: var(--success); +} +.doc-status-connecting { + background: rgba(255, 188, 66, 0.18); + color: #b97c00; +} +.doc-status-disconnected { + background: rgba(214, 69, 69, 0.12); + color: var(--danger); +} + +.doc-main-editor { + flex: 1; + overflow: auto; + min-height: 0; + min-width: 0; + padding: 24px 0; +} +.doc-main-editor .bn-editor { + background-color: var(--bg); +} + +/* ===== History sidebar (right) ===== */ + +.history-sidebar { + border-left: 1px solid var(--border); + background: var(--bg-elevated); + display: flex; + flex-direction: column; + min-height: 0; + overflow: hidden; +} +.history-header { + padding: 14px 16px 8px; + display: flex; + align-items: center; + justify-content: space-between; + flex-shrink: 0; +} +.history-title { + font-size: 11px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.06em; + color: var(--text-subtle); +} +.history-filter { + display: inline-flex; + border: 1px solid var(--border); + border-radius: var(--radius-sm); + overflow: hidden; +} +.history-filter-btn { + padding: 3px 10px; + font-size: 11.5px; + font-weight: 500; + color: var(--text-muted); + background: var(--bg); + transition: + background 0.12s ease, + color 0.12s ease; + border: none; + cursor: pointer; +} +.history-filter-btn:not(:last-child) { + border-right: 1px solid var(--border); +} +.history-filter-btn:hover { + background: var(--bg-hover); + color: var(--text); +} +.history-filter-btn.active { + background: var(--accent-soft); + color: var(--accent); + font-weight: 600; +} +.history-content { + flex: 1; + overflow-y: auto; + padding: 0 8px 16px; +} + +/* ===== BlockNote versioning sidebar (snapshot cards) ===== */ + +.history-content .bn-versioning-sidebar { + border: none; + background: transparent; + padding-inline: 8px; +} + +.bn-snapshot { + background-color: var(--bg); + border: 1px solid var(--border); + border-radius: var(--radius-md); + box-shadow: var(--shadow-sm); + color: var(--text); + cursor: pointer; + display: flex; + flex-direction: column; + gap: 12px; + margin-bottom: 8px; + overflow: visible; + padding: 14px 18px; + width: 100%; + transition: + border-color 0.12s ease, + box-shadow 0.12s ease; +} +.bn-snapshot:hover { + border-color: var(--border-strong); + box-shadow: var(--shadow-md); +} + +.bn-snapshot.selected { + background-color: var(--accent-soft); + border: 2px solid var(--accent); +} + +.bn-snapshot-body { + display: flex; + flex-direction: column; + font-size: 12px; + gap: 4px; + color: var(--text-muted); +} + +.bn-snapshot-name { + background: transparent; + border: none; + color: var(--text); + font-size: 14px; + font-weight: 600; + padding: 0; + width: 100%; + font-family: inherit; +} +.bn-snapshot-name:focus { + outline: none; +} +.bn-snapshot-name::placeholder { + color: var(--text-subtle); +} + +.bn-snapshot-date { + color: var(--text-subtle); + font-size: 12px; +} + +.bn-snapshot-original-date { + color: var(--text-subtle); + font-size: 11px; + font-style: italic; +} + +.bn-snapshot-secondary-label { + color: var(--text-subtle); + font-size: 11px; +} + +.bn-snapshot-button { + background-color: var(--accent); + border: none; + border-radius: var(--radius-sm); + color: white; + cursor: pointer; + font-size: 12px; + font-weight: 600; + padding: 4px 10px; + width: fit-content; + transition: background-color 0.12s ease; +} +.bn-snapshot-button:hover { + background-color: var(--accent-hover); +} + +/* ===== Suggestion marks ===== */ + +.doc-main-editor ins { + background: var(--ins-bg); + border-bottom: 2px solid var(--ins-border); + color: inherit; + text-decoration: none; +} + +.doc-main-editor del { + color: inherit; + text-decoration: line-through; + text-decoration-color: var(--del-border); + text-decoration-thickness: 2px; + background: var(--del-bg); +} + +.doc-main-editor [data-type="modification"] { + background: var(--mod-bg); + border-bottom: 2px solid var(--mod-border); + color: inherit; + text-decoration: none; +} + +/* ===== Remote cursor ===== */ + +.ProseMirror-yjs-cursor { + position: relative; + margin-left: -1px; + margin-right: -1px; + border-left: 1px solid black; + border-right: 1px solid black; + border-color: var(--user-color, orange); + word-break: normal; + pointer-events: none; +} +.ProseMirror-yjs-cursor > div { + position: absolute; + top: -1.25em; + left: -1px; + font-size: 11.5px; + background-color: var(--user-color, rgb(250, 129, 0)); + font-style: normal; + font-weight: 500; + line-height: 1.4; + user-select: none; + color: white; + padding: 0 6px; + border-radius: 4px; + white-space: nowrap; + letter-spacing: 0.01em; +} +.ProseMirror-yjs-selection { + background-color: color-mix( + in srgb, + var(--user-color, orange) 30%, + transparent + ); + border-radius: 2px; +} + +/* ===== Misc ===== */ + +.page-loading { + display: flex; + align-items: center; + justify-content: center; + height: 100vh; + color: var(--text-muted); + font-size: 14px; +} diff --git a/examples/07-collaboration/14-multi-doc-versioning/src/userdata.ts b/examples/07-collaboration/14-multi-doc-versioning/src/userdata.ts new file mode 100644 index 0000000000..3f2a7b9a73 --- /dev/null +++ b/examples/07-collaboration/14-multi-doc-versioning/src/userdata.ts @@ -0,0 +1,33 @@ +export type DemoUser = { + id: string; + name: string; + color: string; + colorLight: string; +}; + +export const USERS: DemoUser[] = [ + { + id: "alice", + name: "Alice", + color: "#30bced", + colorLight: "#30bced33", + }, + { + id: "bob", + name: "Bob", + color: "#6eeb83", + colorLight: "#6eeb8333", + }, + { + id: "charlie", + name: "Charlie", + color: "#ffbc42", + colorLight: "#ffbc4233", + }, + { + id: "dana", + name: "Dana", + color: "#ee6352", + colorLight: "#ee635233", + }, +]; diff --git a/examples/07-collaboration/14-multi-doc-versioning/src/utils.ts b/examples/07-collaboration/14-multi-doc-versioning/src/utils.ts new file mode 100644 index 0000000000..08eb873511 --- /dev/null +++ b/examples/07-collaboration/14-multi-doc-versioning/src/utils.ts @@ -0,0 +1,106 @@ +const ID_CHARS = "abcdefghjkmnpqrstuvwxyz23456789"; + +export const generateRandomId = (length: number): string => { + const bytes = new Uint8Array(length); + crypto.getRandomValues(bytes); + let id = ""; + for (let i = 0; i < bytes.length; i++) { + id += ID_CHARS[bytes[i] % ID_CHARS.length]; + } + return id; +}; + +const DOC_ADJECTIVES = [ + "Quiet", + "Bright", + "Gentle", + "Curious", + "Tangled", + "Shimmering", + "Restless", + "Polished", + "Folded", + "Loose", + "Scattered", + "Hidden", + "Patient", + "Stubborn", + "Winding", + "Borrowed", + "Plain", + "Dusty", + "Silver", + "Wild", + "Half", + "Unfinished", + "Morning", + "Midnight", + "Parallel", + "Open", + "Stray", + "Sunlit", + "Crooked", + "Spare", +]; + +const DOC_NOUNS = [ + "Draft", + "Notebook", + "Sketch", + "Memo", + "Chapter", + "Outline", + "Margin", + "Thought", + "Idea", + "Plan", + "Passage", + "Letter", + "Log", + "Journal", + "Scrap", + "Leaf", + "Manuscript", + "Record", + "Fragment", + "Brief", + "Entry", + "Column", + "Folder", + "Canvas", + "Report", + "Section", + "Page", + "Transcript", + "Ledger", + "Dossier", +]; + +export const generateDocTitle = (): string => { + const adj = DOC_ADJECTIVES[Math.floor(Math.random() * DOC_ADJECTIVES.length)]; + const noun = DOC_NOUNS[Math.floor(Math.random() * DOC_NOUNS.length)]; + return adj + " " + noun; +}; + +export const formatRelative = ( + ts: number, + { justNowMs = 60_000 } = {}, +): string => { + if (!ts) { + return ""; + } + const diff = Date.now() - ts; + if (diff < justNowMs) { + return "just now"; + } + if (diff < 3_600_000) { + return Math.floor(diff / 60_000) + "m ago"; + } + if (diff < 86_400_000) { + return Math.floor(diff / 3_600_000) + "h ago"; + } + if (diff < 7 * 86_400_000) { + return Math.floor(diff / 86_400_000) + "d ago"; + } + return new Date(ts).toLocaleDateString(); +}; diff --git a/examples/07-collaboration/14-multi-doc-versioning/src/versionData.json b/examples/07-collaboration/14-multi-doc-versioning/src/versionData.json new file mode 100644 index 0000000000..98b06f07ab --- /dev/null +++ b/examples/07-collaboration/14-multi-doc-versioning/src/versionData.json @@ -0,0 +1,4414 @@ +{ + "initialVersion": "Remove GNU Make Link", + "initialBlocks": [ + { + "type": "image", + "props": { + "name": "Docs", + "url": "/docs/assets/docs-logo.png", + "previewWidth": 300 + } + }, + { + "type": "paragraph", + "content": " Welcome to Docs! The open source document editor where your notes can become knowledge through live collaboration " + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": " " + }, + { + "type": "link", + "href": "https://matrix.to/#/#docs-official:matrix.org", + "content": [ + { + "type": "text", + "text": " Chat on Matrix " + } + ] + }, + { + "type": "text", + "text": " - " + }, + { + "type": "link", + "href": "/docs/", + "content": [ + { + "type": "text", + "text": " Documentation " + } + ] + }, + { + "type": "text", + "text": " - " + }, + { + "type": "link", + "href": "#getting-started-", + "content": [ + { + "type": "text", + "text": " Getting started " + } + ] + }, + { + "type": "text", + "text": " - " + }, + { + "type": "link", + "href": "mailto:docs@numerique.gouv.fr", + "content": [ + { + "type": "text", + "text": " Reach out " + } + ] + }, + { + "type": "text", + "text": " " + } + ] + }, + { + "type": "image", + "props": { + "name": "", + "url": "/docs/assets/docs_live_collaboration_light.gif" + } + }, + { + "type": "heading", + "props": { + "level": 2 + }, + "content": "Why use Docs ❓" + }, + { + "type": "paragraph", + "content": "Docs is a collaborative text editor designed to address common challenges in knowledge building and sharing." + }, + { + "type": "heading", + "props": { + "level": 3 + }, + "content": "Write" + }, + { + "type": "bulletListItem", + "content": "😌 Simple collaborative editing without the formatting complexity of markdown" + }, + { + "type": "bulletListItem", + "content": "🔌 Offline? No problem, keep writing, your edits will get synced when back online" + }, + { + "type": "bulletListItem", + "content": "💅 Create clean documents with limited but beautiful formatting options and focus on content" + }, + { + "type": "bulletListItem", + "content": "🧱 Built for productivity (markdown support, many block types, slash commands, keyboard shortcuts)." + }, + { + "type": "bulletListItem", + "content": "✨ Save time thanks to our AI actions (generate, sum up, correct, translate)" + }, + { + "type": "heading", + "props": { + "level": 3 + }, + "content": "Collaborate" + }, + { + "type": "bulletListItem", + "content": "🤝 Collaborate with your team in real time" + }, + { + "type": "bulletListItem", + "content": "🔒 Granular access control to ensure your information is secure and only shared with the right people" + }, + { + "type": "bulletListItem", + "content": "📑 Professional document exports in multiple formats (.odt, .doc, .pdf) with customizable templates" + }, + { + "type": "bulletListItem", + "content": [ + { + "type": "text", + "text": "📚 Built-in wiki functionality to turn your team's collaborative work into organized knowledge " + }, + { + "type": "text", + "text": "ETA 02/2025", + "styles": { + "code": true + } + } + ] + }, + { + "type": "heading", + "props": { + "level": 3 + }, + "content": "Self-host" + }, + { + "type": "bulletListItem", + "content": "🚀 Easy to install, scalable and secure alternative to Notion, Outline or Confluence" + }, + { + "type": "heading", + "props": { + "level": 2 + }, + "content": "Getting started 🔧" + }, + { + "type": "heading", + "props": { + "level": 3 + }, + "content": "Test it" + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "Test Docs on your browser by logging in on this " + }, + { + "type": "link", + "href": "https://impress-preprod.beta.numerique.gouv.fr/", + "content": [ + { + "type": "text", + "text": "environment" + } + ] + } + ] + }, + { + "type": "codeBlock", + "props": { + "language": "text" + }, + "content": "email: test.docs@yopmail.com\npassword: I'd<3ToTestDocs" + }, + { + "type": "heading", + "props": { + "level": 3 + }, + "content": "Run it locally" + }, + { + "type": "quote", + "content": "⚠️ Running Docs locally using the methods described below is for testing purposes only. It is based on building Docs using Minio as the S3 storage solution but you can choose any S3 compatible object storage of your choice." + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "Prerequisite", + "styles": { + "bold": true + } + } + ] + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "Make sure you have a recent version of Docker and " + }, + { + "type": "link", + "href": "https://docs.docker.com/compose/install", + "content": [ + { + "type": "text", + "text": "Docker Compose" + } + ] + }, + { + "type": "text", + "text": " installed on your laptop:" + } + ] + }, + { + "type": "codeBlock", + "props": { + "language": "shellscript" + }, + "content": "$ docker -v\n\nDocker version 20.10.2, build 2291f61\n\n$ docker compose version\n\nDocker Compose version v2.32.4" + }, + { + "type": "quote", + "content": [ + { + "type": "text", + "text": "⚠️ You may need to run the following commands with sudo but this can be avoided by adding your user to the " + }, + { + "type": "text", + "text": "docker", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": " group." + } + ] + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "Project bootstrap", + "styles": { + "bold": true + } + } + ] + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "The easiest way to start working on the project is to use " + }, + { + "type": "link", + "href": "https://www.gnu.org/software/make/", + "content": [ + { + "type": "text", + "text": "GNU Make" + } + ] + }, + { + "type": "text", + "text": ":" + } + ] + }, + { + "type": "codeBlock", + "props": { + "language": "shellscript" + }, + "content": "$ make bootstrap FLUSH_ARGS='--no-input'" + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "This command builds the " + }, + { + "type": "text", + "text": "app", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": " container, installs dependencies, performs database migrations and compile translations. It's a good idea to use this command each time you are pulling code from the project repository to avoid dependency-related or migration-related issues." + } + ] + }, + { + "type": "paragraph", + "content": "Your Docker services should now be up and running 🎉" + }, + { + "type": "paragraph", + "content": "You can access to the project by going to ." + }, + { + "type": "paragraph", + "content": "You will be prompted to log in, the default credentials are:" + }, + { + "type": "codeBlock", + "props": { + "language": "text" + }, + "content": "username: impress\npassword: impress" + }, + { + "type": "paragraph", + "content": "📝 Note that if you need to run them afterwards, you can use the eponym Make rule:" + }, + { + "type": "codeBlock", + "props": { + "language": "shellscript" + }, + "content": "$ make run" + }, + { + "type": "paragraph", + "content": "⚠️ For the frontend developer, it is often better to run the frontend in development mode locally." + }, + { + "type": "paragraph", + "content": "To do so, install the frontend dependencies with the following command:" + }, + { + "type": "codeBlock", + "props": { + "language": "shellscript" + }, + "content": "$ make frontend-development-install" + }, + { + "type": "paragraph", + "content": "And run the frontend locally in development mode with the following command:" + }, + { + "type": "codeBlock", + "props": { + "language": "shellscript" + }, + "content": "$ make run-frontend-development" + }, + { + "type": "paragraph", + "content": "To start all the services, except the frontend container, you can use the following command:" + }, + { + "type": "codeBlock", + "props": { + "language": "shellscript" + }, + "content": "$ make run-backend" + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "Adding content\n", + "styles": { + "bold": true + } + }, + { + "type": "text", + "text": " You can create a basic demo site by running:" + } + ] + }, + { + "type": "codeBlock", + "props": { + "language": "shellscript" + }, + "content": "$ make demo" + }, + { + "type": "paragraph", + "content": "Finally, you can check all available Make rules using:" + }, + { + "type": "codeBlock", + "props": { + "language": "shellscript" + }, + "content": "$ make help" + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "Django admin", + "styles": { + "bold": true + } + } + ] + }, + { + "type": "paragraph", + "content": "You can access the Django admin site at" + }, + { + "type": "paragraph", + "content": "." + }, + { + "type": "paragraph", + "content": "You first need to create a superuser account:" + }, + { + "type": "codeBlock", + "props": { + "language": "shellscript" + }, + "content": "$ make superuser" + }, + { + "type": "heading", + "props": { + "level": 2 + }, + "content": "Feedback 🙋‍♂️🙋‍♀️" + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "We'd love to hear your thoughts and hear about your experiments, so come and say hi on " + }, + { + "type": "link", + "href": "https://matrix.to/#/#docs-official:matrix.org", + "content": [ + { + "type": "text", + "text": "Matrix" + } + ] + }, + { + "type": "text", + "text": "." + } + ] + }, + { + "type": "heading", + "props": { + "level": 2 + }, + "content": "Roadmap" + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "Want to know where the project is headed? " + }, + { + "type": "link", + "href": "https://github.com/orgs/numerique-gouv/projects/13/views/11", + "content": [ + { + "type": "text", + "text": "🗺️ Checkout our roadmap" + } + ] + } + ] + }, + { + "type": "heading", + "props": { + "level": 2 + }, + "content": "Licence 📝" + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "This work is released under the MIT License (see " + }, + { + "type": "link", + "href": "https://github.com/suitenumerique/docs/blob/main/LICENSE", + "content": [ + { + "type": "text", + "text": "LICENSE" + } + ] + }, + { + "type": "text", + "text": ")." + } + ] + }, + { + "type": "paragraph", + "content": "While Docs is a public driven initiative our licence choice is an invitation for private sector actors to use, sell and contribute to the project." + }, + { + "type": "heading", + "props": { + "level": 2 + }, + "content": "Contributing 🙌" + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "This project is intended to be community-driven, so please, do not hesitate to " + }, + { + "type": "link", + "href": "https://matrix.to/#/#docs-official:matrix.org", + "content": [ + { + "type": "text", + "text": "get in touch" + } + ] + }, + { + "type": "text", + "text": " if you have any question related to our implementation or design decisions." + } + ] + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "You can help us with translations on " + }, + { + "type": "link", + "href": "https://crowdin.com/project/lasuite-docs", + "content": [ + { + "type": "text", + "text": "Crowdin" + } + ] + }, + { + "type": "text", + "text": "." + } + ] + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "If you intend to make pull requests see " + }, + { + "type": "link", + "href": "https://github.com/suitenumerique/docs/blob/main/CONTRIBUTING.md", + "content": [ + { + "type": "text", + "text": "CONTRIBUTING" + } + ] + }, + { + "type": "text", + "text": " for guidelines." + } + ] + }, + { + "type": "paragraph", + "content": "Directory structure:" + }, + { + "type": "codeBlock", + "props": { + "language": "markdown" + }, + "content": "docs\n├── bin - executable scripts or binaries that are used for various tasks, such as setup scripts, utility scripts, or custom commands.\n├── crowdin - for crowdin translations, a tool or service that helps manage translations for the project.\n├── docker - Dockerfiles and related configuration files used to build Docker images for the project. These images can be used for development, testing, or production environments.\n├── docs - documentation for the project, including user guides, API documentation, and other helpful resources.\n├── env.d/development - environment-specific configuration files for the development environment. These files might include environment variables, configuration settings, or other setup files needed for development.\n├── gitlint - configuration files for `gitlint`, a tool that enforces commit message guidelines to ensure consistency and quality in commit messages.\n├── playground - experimental or temporary code, where developers can test new features or ideas without affecting the main codebase.\n└── src - main source code directory, containing the core application code, libraries, and modules of the project." + }, + { + "type": "heading", + "props": { + "level": 2 + }, + "content": "Credits ❤️" + }, + { + "type": "heading", + "props": { + "level": 3 + }, + "content": "Stack" + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "Docs is built on top of " + }, + { + "type": "link", + "href": "https://www.django-rest-framework.org/", + "content": [ + { + "type": "text", + "text": "Django Rest Framework" + } + ] + }, + { + "type": "text", + "text": ", " + }, + { + "type": "link", + "href": "https://nextjs.org/", + "content": [ + { + "type": "text", + "text": "Next.js" + } + ] + }, + { + "type": "text", + "text": ", " + }, + { + "type": "link", + "href": "https://www.blocknotejs.org/", + "content": [ + { + "type": "text", + "text": "BlockNote.js" + } + ] + }, + { + "type": "text", + "text": ", " + }, + { + "type": "link", + "href": "https://tiptap.dev/docs/hocuspocus/introduction", + "content": [ + { + "type": "text", + "text": "HocusPocus" + } + ] + }, + { + "type": "text", + "text": " and " + }, + { + "type": "link", + "href": "https://yjs.dev/", + "content": [ + { + "type": "text", + "text": "Yjs" + } + ] + }, + { + "type": "text", + "text": "." + } + ] + }, + { + "type": "heading", + "props": { + "level": 3 + }, + "content": "Gov ❤️ open source" + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "Docs is the result of a joint effort led by the French 🇫🇷🥖 (" + }, + { + "type": "link", + "href": "https://www.numerique.gouv.fr/dinum/", + "content": [ + { + "type": "text", + "text": "DINUM" + } + ] + }, + { + "type": "text", + "text": ") and German 🇩🇪🥨 governments (" + }, + { + "type": "link", + "href": "https://zendis.de/", + "content": [ + { + "type": "text", + "text": "ZenDiS" + } + ] + }, + { + "type": "text", + "text": ")." + } + ] + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "We are proud sponsors of " + }, + { + "type": "link", + "href": "https://www.blocknotejs.org/", + "content": [ + { + "type": "text", + "text": "BlockNotejs" + } + ] + }, + { + "type": "text", + "text": " and " + }, + { + "type": "link", + "href": "https://yjs.dev/", + "content": [ + { + "type": "text", + "text": "Yjs" + } + ] + }, + { + "type": "text", + "text": "." + } + ] + }, + { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "We are always looking for new public partners (we are currently onboarding the Netherlands 🇳🇱🧀), feel free to " + }, + { + "type": "link", + "href": "mailto:docs@numerique.gouv.fr", + "content": [ + { + "type": "text", + "text": "reach out" + } + ] + }, + { + "type": "text", + "text": " if you are interested in using or contributing to Docs." + } + ] + }, + { + "type": "image", + "props": { + "name": "", + "url": "/docs/assets/europe_opensource.png" + } + } + ], + "transitions": [ + { + "name": "Reposition AGPL Warning", + "operations": [ + { + "type": "insert", + "index": 5, + "block": { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "⚠️ " + }, + { + "type": "text", + "text": "Note that Docs provides docs/pdf exporters by loading ", + "styles": { + "bold": true + } + }, + { + "type": "link", + "href": "https://github.com/suitenumerique/docs/blob/main/src/frontend/apps/impress/package.json#L22C7-L23C53", + "content": [ + { + "type": "text", + "text": "two BlockNote packages", + "styles": { + "bold": true + } + } + ] + }, + { + "type": "text", + "text": ", which we use under the AGPL-3.0 licence. Until we comply with the terms of this license, we recommend that you don't run Docs as a commercial product, unless you are willing to sponsor ", + "styles": { + "bold": true + } + }, + { + "type": "link", + "href": "https://github.com/TypeCellOS/BlockNote", + "content": [ + { + "type": "text", + "text": "BlockNote", + "styles": { + "bold": true + } + } + ] + }, + { + "type": "text", + "text": ".", + "styles": { + "bold": true + } + } + ] + } + }, + { + "type": "update", + "index": 22, + "block": { + "content": [ + { + "type": "text", + "text": "Test Docs on your browser by visiting this " + }, + { + "type": "link", + "href": "https://impress-preprod.beta.numerique.gouv.fr/docs/6ee5aac4-4fb9-457d-95bf-bb56c2467713/", + "content": [ + { + "type": "text", + "text": "demo document" + } + ] + } + ] + } + }, + { + "type": "delete", + "index": 23 + } + ] + }, + { + "name": "Header Redesign with Banner", + "operations": [ + { + "type": "update", + "index": 0, + "block": { + "props": { + "name": "Docs", + "url": "/docs/assets/banner-docs.png" + } + } + }, + { + "type": "delete", + "index": 1 + }, + { + "type": "insert", + "index": 3, + "block": { + "type": "heading", + "props": { + "level": 1 + }, + "content": "La Suite Docs : Collaborative Text Editing" + } + }, + { + "type": "insert", + "index": 4, + "block": { + "type": "paragraph", + "content": "Docs, where your notes can become knowledge through live collaboration." + } + }, + { + "type": "delete", + "index": 6 + }, + { + "type": "insert", + "index": 7, + "block": { + "type": "paragraph", + "content": "It offers a scalable and secure alternative to tools such as Google Docs, Notion (without the dbs), Outline, or Confluence." + } + }, + { + "type": "update", + "index": 9, + "block": { + "content": "😌 Get simple, accessible online editing for your team." + } + }, + { + "type": "update", + "index": 10, + "block": { + "content": "💅 Create clean documents with beautiful formatting options." + } + }, + { + "type": "update", + "index": 11, + "block": { + "content": [ + { + "type": "text", + "text": "🖌️ Focus on your content using either the in-line editor, or " + }, + { + "type": "link", + "href": "https://www.markdownguide.org/basic-syntax/", + "content": [ + { + "type": "text", + "text": "the Markdown syntax" + } + ] + }, + { + "type": "text", + "text": "." + } + ] + } + }, + { + "type": "update", + "index": 12, + "block": { + "content": [ + { + "type": "text", + "text": "🧱 Quickly design your page thanks to the many block types, accessible from the " + }, + { + "type": "text", + "text": "/", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": " slash commands, as well as keyboard shortcuts." + } + ] + } + }, + { + "type": "update", + "index": 13, + "block": { + "content": "🔌 Write offline! Your edits will be synced once you're back online." + } + }, + { + "type": "update", + "index": 14, + "block": { + "type": "bulletListItem", + "content": "✨ Save time thanks to our AI actions, such as rephrasing, summarizing, fixing typos, translating, etc. You can even turn your selected text into a prompt!" + } + }, + { + "type": "update", + "index": 15, + "block": { + "type": "heading", + "props": { + "level": 3 + }, + "content": "Work together" + } + }, + { + "type": "update", + "index": 16, + "block": { + "content": "🤝 Enjoy live editing! See your team collaborate in real time." + } + }, + { + "type": "update", + "index": 17, + "block": { + "content": "🔒 Keep your information secure thanks to granular access control. Only share with the right people." + } + }, + { + "type": "update", + "index": 18, + "block": { + "content": [ + { + "type": "text", + "text": "📑 Export your content in multiple formats (" + }, + { + "type": "text", + "text": ".odt", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": ", " + }, + { + "type": "text", + "text": ".docx", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": ", " + }, + { + "type": "text", + "text": ".pdf", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": ") with customizable templates." + } + ] + } + }, + { + "type": "insert", + "index": 19, + "block": { + "type": "bulletListItem", + "content": "📚 Turn your team's collaborative work into organized knowledge with Subpages." + } + }, + { + "type": "update", + "index": 21, + "block": { + "type": "paragraph", + "content": "🚀 Docs is easy to install on your own servers" + } + }, + { + "type": "insert", + "index": 22, + "block": { + "type": "paragraph", + "content": "Available methods: Helm chart, Nix package" + } + }, + { + "type": "insert", + "index": 23, + "block": { + "type": "paragraph", + "content": "In the works: Docker Compose, YunoHost" + } + }, + { + "type": "insert", + "index": 24, + "block": { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "⚠️ For the PDF and Docx export Docs relies on XL packages from BlockNote licenced in AGPL-3.0. Please make sure you fulfill your " + }, + { + "type": "link", + "href": "https://github.com/TypeCellOS/BlockNote/blob/main/packages/xl-pdf-exporter/LICENSE", + "content": [ + { + "type": "text", + "text": "BlockNote licensing" + } + ] + }, + { + "type": "text", + "text": " or " + }, + { + "type": "link", + "href": "https://www.blocknotejs.org/about#partner-with-us", + "content": [ + { + "type": "text", + "text": "sponsorship" + } + ] + }, + { + "type": "text", + "text": " obligations." + } + ] + } + }, + { + "type": "update", + "index": 27, + "block": { + "content": [ + { + "type": "text", + "text": "You can test Docs on your browser by visiting this " + }, + { + "type": "link", + "href": "https://impress-preprod.beta.numerique.gouv.fr/docs/6ee5aac4-4fb9-457d-95bf-bb56c2467713/", + "content": [ + { + "type": "text", + "text": "demo document" + } + ] + } + ] + } + }, + { + "type": "update", + "index": 28, + "block": { + "content": "Run Docs locally" + } + }, + { + "type": "update", + "index": 29, + "block": { + "content": [ + { + "type": "text", + "text": "⚠️ The methods described below for running Docs locally is " + }, + { + "type": "text", + "text": "for testing purposes only", + "styles": { + "bold": true + } + }, + { + "type": "text", + "text": ". It is based on building Docs using " + }, + { + "type": "link", + "href": "https://min.io/", + "content": [ + { + "type": "text", + "text": "Minio" + } + ] + }, + { + "type": "text", + "text": " as an S3-compatible storage solution. Of course you can choose any S3-compatible storage solution." + } + ] + } + }, + { + "type": "update", + "index": 31, + "block": { + "content": [ + { + "type": "text", + "text": "Make sure you have a recent version of Docker and " + }, + { + "type": "link", + "href": "https://docs.docker.com/compose/install", + "content": [ + { + "type": "text", + "text": "Docker Compose" + } + ] + }, + { + "type": "text", + "text": " installed on your laptop, then type:" + } + ] + } + }, + { + "type": "update", + "index": 33, + "block": { + "content": [ + { + "type": "text", + "text": "⚠️ You may need to run the following commands with " + }, + { + "type": "text", + "text": "sudo", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": ", but this can be avoided by adding your user to the local " + }, + { + "type": "text", + "text": "docker", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": " group." + } + ] + } + }, + { + "type": "update", + "index": 37, + "block": { + "content": [ + { + "type": "text", + "text": "This command builds the " + }, + { + "type": "text", + "text": "app", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": " container, installs dependencies, performs database migrations and compiles translations. It's a good idea to use this command each time you are pulling code from the project repository to avoid dependency-related or migration-related issues." + } + ] + } + }, + { + "type": "update", + "index": 40, + "block": { + "content": "You will be prompted to log in. The default credentials are:" + } + }, + { + "type": "update", + "index": 51, + "block": { + "content": [ + { + "type": "text", + "text": "Adding content", + "styles": { + "bold": true + } + } + ] + } + }, + { + "type": "insert", + "index": 52, + "block": { + "type": "paragraph", + "content": "You can create a basic demo site by running this command:" + } + }, + { + "type": "update", + "index": 54, + "block": { + "content": "Finally, you can check all available Make rules using this command:" + } + }, + { + "type": "update", + "index": 57, + "block": { + "content": "You can access the Django admin site at:" + } + }, + { + "type": "update", + "index": 62, + "block": { + "content": [ + { + "type": "text", + "text": "We'd love to hear your thoughts, and hear about your experiments, so come and say hi on " + }, + { + "type": "link", + "href": "https://matrix.to/#/#docs-official:matrix.org", + "content": [ + { + "type": "text", + "text": "Matrix" + } + ] + }, + { + "type": "text", + "text": "." + } + ] + } + }, + { + "type": "update", + "index": 67, + "block": { + "content": "While Docs is a public-driven initiative, our licence choice is an invitation for private sector actors to use, sell and contribute to the project." + } + }, + { + "type": "update", + "index": 71, + "block": { + "content": [ + { + "type": "text", + "text": "If you intend to make pull requests, see " + }, + { + "type": "link", + "href": "https://github.com/suitenumerique/docs/blob/main/CONTRIBUTING.md", + "content": [ + { + "type": "text", + "text": "CONTRIBUTING" + } + ] + }, + { + "type": "text", + "text": " for guidelines." + } + ] + } + }, + { + "type": "update", + "index": 72, + "block": { + "type": "heading", + "props": { + "level": 2 + } + } + }, + { + "type": "update", + "index": 76, + "block": { + "content": [ + { + "type": "text", + "text": "Docs is built on top of " + }, + { + "type": "link", + "href": "https://www.django-rest-framework.org/", + "content": [ + { + "type": "text", + "text": "Django Rest Framework" + } + ] + }, + { + "type": "text", + "text": ", " + }, + { + "type": "link", + "href": "https://nextjs.org/", + "content": [ + { + "type": "text", + "text": "Next.js" + } + ] + }, + { + "type": "text", + "text": ", " + }, + { + "type": "link", + "href": "https://www.blocknotejs.org/", + "content": [ + { + "type": "text", + "text": "BlockNote.js" + } + ] + }, + { + "type": "text", + "text": ", " + }, + { + "type": "link", + "href": "https://tiptap.dev/docs/hocuspocus/introduction", + "content": [ + { + "type": "text", + "text": "HocusPocus" + } + ] + }, + { + "type": "text", + "text": " and " + }, + { + "type": "link", + "href": "https://yjs.dev/", + "content": [ + { + "type": "text", + "text": "Yjs" + } + ] + }, + { + "type": "text", + "text": ". We thank the contributors of all these projects for their awesome work!" + } + ] + } + }, + { + "type": "insert", + "index": 77, + "block": { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "We are proud sponsors of " + }, + { + "type": "link", + "href": "https://www.blocknotejs.org/", + "content": [ + { + "type": "text", + "text": "BlockNotejs" + } + ] + }, + { + "type": "text", + "text": " and " + }, + { + "type": "link", + "href": "https://yjs.dev/", + "content": [ + { + "type": "text", + "text": "Yjs" + } + ] + }, + { + "type": "text", + "text": "." + } + ] + } + }, + { + "type": "delete", + "index": 80 + } + ] + }, + { + "name": "Add Badges & Fix Links", + "operations": [ + { + "type": "insert", + "index": 1, + "block": { + "type": "image", + "props": { + "name": "", + "url": "https://img.shields.io/github/stars/suitenumerique/docs" + } + } + }, + { + "type": "insert", + "index": 2, + "block": { + "type": "image", + "props": { + "name": "PRs Welcome", + "url": "https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=shields" + } + } + }, + { + "type": "insert", + "index": 3, + "block": { + "type": "image", + "props": { + "name": "GitHub commit activity", + "url": "https://img.shields.io/github/commit-activity/m/suitenumerique/docs" + } + } + }, + { + "type": "insert", + "index": 4, + "block": { + "type": "image", + "props": { + "name": "GitHub closed issues", + "url": "https://img.shields.io/github/issues-closed/suitenumerique/docs" + } + } + }, + { + "type": "insert", + "index": 5, + "block": { + "type": "image", + "props": { + "name": "GitHub closed issues", + "url": "https://img.shields.io/github/license/suitenumerique/docs" + } + } + }, + { + "type": "delete", + "index": 7 + }, + { + "type": "insert", + "index": 9, + "block": { + "type": "image", + "props": { + "name": "", + "url": "/docs/assets/docs_live_collaboration_light.gif" + } + } + }, + { + "type": "update", + "index": 29, + "block": { + "content": [ + { + "type": "text", + "text": "⚠️ For some advanced features (ex: Export as PDF) Docs relies on XL packages from BlockNote. These are licenced under AGPL-3.0 and are not MIT compatible. You can perfectly use Docs without these packages by setting the environment variable " + }, + { + "type": "text", + "text": "PUBLISH_AS_MIT", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": " to true. That way you'll build an image of the application without the features that are not MIT compatible. Read the " + }, + { + "type": "link", + "href": "/docs/docs/env.md", + "content": [ + { + "type": "text", + "text": "environment variables documentation" + } + ] + }, + { + "type": "text", + "text": " for more information." + } + ] + } + } + ] + }, + { + "name": "Update Bootstrap & Descriptions", + "operations": [ + { + "type": "update", + "index": 29, + "block": { + "content": [ + { + "type": "text", + "text": "⚠️ For some advanced features (ex: Export as PDF) Docs relies on XL packages from BlockNote. These are licenced under AGPL-3.0 and are not MIT compatible. You can perfectly use Docs without these packages by setting the environment variable " + }, + { + "type": "text", + "text": "PUBLISH_AS_MIT", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": " to true. That way you'll build an image of the application without the features that are not MIT compatible. Read the " + }, + { + "type": "link", + "href": "/docs/env.md", + "content": [ + { + "type": "text", + "text": "environment variables documentation" + } + ] + }, + { + "type": "text", + "text": " for more information." + } + ] + } + }, + { + "type": "update", + "index": 44, + "block": { + "content": "You can access the project by going to ." + } + }, + { + "type": "update", + "index": 47, + "block": { + "content": "📝 Note that if you need to run them afterwards, you can use the eponymous Make rule:" + } + } + ] + }, + { + "name": "License & Spelling Fixes", + "operations": [ + { + "type": "update", + "index": 5, + "block": { + "props": { + "name": "MIT License", + "url": "https://img.shields.io/github/license/suitenumerique/docs" + } + } + }, + { + "type": "update", + "index": 42, + "block": { + "content": [ + { + "type": "text", + "text": "This command builds the " + }, + { + "type": "text", + "text": "app-dev", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": " and " + }, + { + "type": "text", + "text": "frontend-dev", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": " containers, installs dependencies, performs database migrations and compiles translations. It's a good idea to use this command each time you are pulling code from the project repository to avoid dependency-related or migration-related issues." + } + ] + } + }, + { + "type": "update", + "index": 68, + "block": { + "content": "Roadmap 💡" + } + }, + { + "type": "update", + "index": 70, + "block": { + "content": "License 📝" + } + }, + { + "type": "update", + "index": 72, + "block": { + "content": "While Docs is a public-driven initiative, our license choice is an invitation for private sector actors to use, sell and contribute to the project." + } + } + ] + }, + { + "name": "Known Instances & Self-Host", + "operations": [ + { + "type": "delete", + "index": 12 + }, + { + "type": "update", + "index": 25, + "block": { + "type": "heading", + "props": { + "level": 4 + } + } + }, + { + "type": "update", + "index": 26, + "block": { + "content": [ + { + "type": "text", + "text": "We use Kubernetes for our " + }, + { + "type": "link", + "href": "https://docs.numerique.gouv.fr/", + "content": [ + { + "type": "text", + "text": "production instance" + } + ] + }, + { + "type": "text", + "text": " but also support Docker Compose. The community contributed a couple other methods (Nix, YunoHost etc.) check out the " + }, + { + "type": "link", + "href": "/docs/installation/README.md", + "content": [ + { + "type": "text", + "text": "docs" + } + ] + }, + { + "type": "text", + "text": " to get detailed instructions and examples." + } + ] + } + }, + { + "type": "update", + "index": 27, + "block": { + "type": "heading", + "props": { + "level": 4 + }, + "content": "🌍 Known instances" + } + }, + { + "type": "update", + "index": 28, + "block": { + "content": "We hope to see many more, here is an incomplete list of public Docs instances (urls listed in alphabetical order). Feel free to make a PR to add ones that are not listed below🙏" + } + }, + { + "type": "insert", + "index": 29, + "block": { + "type": "table", + "content": { + "type": "tableContent", + "columnWidths": [null, null, null], + "rows": [ + { + "cells": [ + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "Url", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "Org", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "Public", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + } + ] + }, + { + "cells": [ + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "docs.numerique.gouv.fr", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "DINUM", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "French public agents working for the central administration and the extended public sphere. ProConnect is required to login in or sign up", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + } + ] + }, + { + "cells": [ + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "docs.suite.anct.gouv.fr", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "ANCT", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "French public agents working for the territorial administration and the extended public sphere. ProConnect is required to login in or sign up", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + } + ] + }, + { + "cells": [ + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "notes.demo.opendesk.eu", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "ZenDiS", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "Demo instance of OpenDesk. Request access to get credentials", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + } + ] + }, + { + "cells": [ + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "notes.liiib.re", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "lasuite.coop", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "Free and open demo to all. Content and accounts are reset after one month", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + } + ] + } + ] + } + } + }, + { + "type": "insert", + "index": 30, + "block": { + "type": "heading", + "props": { + "level": 4 + }, + "content": "⚠️ Advanced features" + } + }, + { + "type": "insert", + "index": 31, + "block": { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "For some advanced features (ex: Export as PDF) Docs relies on XL packages from BlockNote. These are licenced under GPL and are not MIT compatible. You can perfectly use Docs without these packages by setting the environment variable " + }, + { + "type": "text", + "text": "PUBLISH_AS_MIT", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": " to true. That way you'll build an image of the application without the features that are not MIT compatible. Read the " + }, + { + "type": "link", + "href": "/docs/env.md", + "content": [ + { + "type": "text", + "text": "environment variables documentation" + } + ] + }, + { + "type": "text", + "text": " for more information." + } + ] + } + } + ] + }, + { + "name": "Add Instances & Frontend Tests", + "operations": [ + { + "type": "update", + "index": 29, + "block": { + "content": { + "type": "tableContent", + "columnWidths": [null, null, null], + "rows": [ + { + "cells": [ + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "Url", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "Org", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "Public", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + } + ] + }, + { + "cells": [ + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "docs.numerique.gouv.fr", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "DINUM", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "French public agents working for the central administration and the extended public sphere. ProConnect is required to login in or sign up", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + } + ] + }, + { + "cells": [ + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "docs.suite.anct.gouv.fr", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "ANCT", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "French public agents working for the territorial administration and the extended public sphere. ProConnect is required to login in or sign up", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + } + ] + }, + { + "cells": [ + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "notes.demo.opendesk.eu", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "ZenDiS", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "Demo instance of OpenDesk. Request access to get credentials", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + } + ] + }, + { + "cells": [ + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "notes.liiib.re", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "lasuite.coop", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "Free and open demo to all. Content and accounts are reset after one month", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + } + ] + }, + { + "cells": [ + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "docs.federated.nexus", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "federated.nexus", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "Public instance, but you have to ", + "styles": {} + }, + { + "type": "link", + "href": "https://federated.nexus/register/", + "content": [ + { + "type": "text", + "text": "sign up for a Federated Nexus account", + "styles": {} + } + ] + }, + { + "type": "text", + "text": ".", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + } + ] + } + ] + } + } + }, + { + "type": "insert", + "index": 58, + "block": { + "type": "paragraph", + "content": "To execute frontend tests & linting only" + } + }, + { + "type": "insert", + "index": 59, + "block": { + "type": "codeBlock", + "props": { + "language": "shellscript" + }, + "content": "$ make frontend-test\n$ make frontend-lint" + } + } + ] + }, + { + "name": "Production URL & Demo Update", + "operations": [ + { + "type": "update", + "index": 28, + "block": { + "content": "We hope to see many more, here is an incomplete list of public Docs instances. Feel free to make a PR to add ones that are not listed below🙏" + } + }, + { + "type": "update", + "index": 29, + "block": { + "content": { + "type": "tableContent", + "columnWidths": [null, null, null], + "headerRows": 1, + "rows": [ + { + "cells": [ + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "Url", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "Org", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "Public", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + } + ] + }, + { + "cells": [ + { + "type": "tableCell", + "content": [ + { + "type": "link", + "href": "https://docs.numerique.gouv.fr/", + "content": [ + { + "type": "text", + "text": "docs.numerique.gouv.fr", + "styles": {} + } + ] + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "DINUM", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "French public agents working for the central administration and the extended public sphere. ProConnect is required to login in or sign up", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + } + ] + }, + { + "cells": [ + { + "type": "tableCell", + "content": [ + { + "type": "link", + "href": "https://docs.suite.anct.gouv.fr/", + "content": [ + { + "type": "text", + "text": "docs.suite.anct.gouv.fr", + "styles": {} + } + ] + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "ANCT", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "French public agents working for the territorial administration and the extended public sphere. ProConnect is required to login in or sign up", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + } + ] + }, + { + "cells": [ + { + "type": "tableCell", + "content": [ + { + "type": "link", + "href": "https://notes.demo.opendesk.eu", + "content": [ + { + "type": "text", + "text": "notes.demo.opendesk.eu", + "styles": {} + } + ] + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "ZenDiS", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "Demo instance of OpenDesk. Request access to get credentials", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + } + ] + }, + { + "cells": [ + { + "type": "tableCell", + "content": [ + { + "type": "link", + "href": "https://notes.liiib.re/", + "content": [ + { + "type": "text", + "text": "notes.liiib.re", + "styles": {} + } + ] + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "lasuite.coop", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "Free and open demo to all. Content and accounts are reset after one month", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + } + ] + }, + { + "cells": [ + { + "type": "tableCell", + "content": [ + { + "type": "link", + "href": "https://docs.federated.nexus/", + "content": [ + { + "type": "text", + "text": "docs.federated.nexus", + "styles": {} + } + ] + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "federated.nexus", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "Public instance, but you have to ", + "styles": {} + }, + { + "type": "link", + "href": "https://federated.nexus/register/", + "content": [ + { + "type": "text", + "text": "sign up for a Federated Nexus account", + "styles": {} + } + ] + }, + { + "type": "text", + "text": ".", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + } + ] + }, + { + "cells": [ + { + "type": "tableCell", + "content": [ + { + "type": "link", + "href": "https://docs.demo.mosacloud.eu/", + "content": [ + { + "type": "text", + "text": "docs.demo.mosacloud.eu", + "styles": {} + } + ] + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "mosa.cloud", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + }, + { + "type": "tableCell", + "content": [ + { + "type": "text", + "text": "Demo instance of mosa.cloud, a dutch company providing services around La Suite apps.", + "styles": {} + } + ], + "props": { + "colspan": 1, + "rowspan": 1, + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + } + } + ] + } + ] + } + } + }, + { + "type": "update", + "index": 34, + "block": { + "content": [ + { + "type": "text", + "text": "You can test Docs on your browser by visiting this " + }, + { + "type": "link", + "href": "https://docs.la-suite.eu/docs/9137bbb5-3e8a-4ff7-8a36-fcc4e8bd57f4/", + "content": [ + { + "type": "text", + "text": "demo document" + } + ] + } + ] + } + } + ] + }, + { + "name": "Complete Rewrite & Typo Fixes", + "operations": [ + { + "type": "update", + "index": 2, + "block": { + "props": { + "name": "PRs Welcome", + "url": "https://img.shields.io/badge/PRs-welcome-brightgreen.svg" + } + } + }, + { + "type": "delete", + "index": 3 + }, + { + "type": "delete", + "index": 3 + }, + { + "type": "update", + "index": 4, + "block": { + "content": [ + { + "type": "text", + "text": " " + }, + { + "type": "link", + "href": "https://matrix.to/#/#docs-official:matrix.org", + "content": [ + { + "type": "text", + "text": "Chat on Matrix" + } + ] + }, + { + "type": "text", + "text": " • " + }, + { + "type": "link", + "href": "/docs/", + "content": [ + { + "type": "text", + "text": "Documentation" + } + ] + }, + { + "type": "text", + "text": " • " + }, + { + "type": "link", + "href": "#try-docs", + "content": [ + { + "type": "text", + "text": "Try Docs" + } + ] + }, + { + "type": "text", + "text": " • " + }, + { + "type": "link", + "href": "mailto:docs@numerique.gouv.fr", + "content": [ + { + "type": "text", + "text": "Contact us" + } + ] + }, + { + "type": "text", + "text": " " + } + ] + } + }, + { + "type": "update", + "index": 5, + "block": { + "content": "La Suite Docs: Collaborative Text Editing" + } + }, + { + "type": "update", + "index": 6, + "block": { + "content": [ + { + "type": "text", + "text": "Docs, where your notes can become knowledge through live collaboration.", + "styles": { + "bold": true + } + } + ] + } + }, + { + "type": "update", + "index": 7, + "block": { + "type": "paragraph", + "content": "Docs is an open-source collaborative editor that helps teams write, organize, and share knowledge together - in real time." + } + }, + { + "type": "update", + "index": 8, + "block": { + "type": "image", + "props": { + "name": "Live collaboration demo", + "url": "/docs/assets/docs_live_collaboration_light.gif" + } + } + }, + { + "type": "update", + "index": 9, + "block": { + "type": "heading", + "props": { + "level": 2 + }, + "content": "What is Docs?" + } + }, + { + "type": "update", + "index": 10, + "block": { + "type": "paragraph", + "content": "Docs is an open-source alternative to tools like Notion or Google Docs, focused on:" + } + }, + { + "type": "update", + "index": 11, + "block": { + "content": "Real-time collaboration" + } + }, + { + "type": "update", + "index": 12, + "block": { + "content": "Clean, structured documents" + } + }, + { + "type": "update", + "index": 13, + "block": { + "content": "Knowledge organization" + } + }, + { + "type": "update", + "index": 14, + "block": { + "content": "Data ownership & self-hosting" + } + }, + { + "type": "update", + "index": 15, + "block": { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "Built for public organizations, companies, and open communities.", + "styles": { + "bold": true, + "italic": true + } + } + ] + } + }, + { + "type": "update", + "index": 16, + "block": { + "type": "heading", + "props": { + "level": 2 + }, + "content": "Why use Docs?" + } + }, + { + "type": "update", + "index": 17, + "block": { + "content": "Writing" + } + }, + { + "type": "update", + "index": 18, + "block": { + "content": "Rich-text & Markdown editing" + } + }, + { + "type": "update", + "index": 19, + "block": { + "content": "Slash commands & block system" + } + }, + { + "type": "update", + "index": 20, + "block": { + "content": "Beautiful formatting" + } + }, + { + "type": "update", + "index": 21, + "block": { + "content": "Offline editing" + } + }, + { + "type": "update", + "index": 22, + "block": { + "type": "bulletListItem", + "content": "Optional AI writing helpers (rewrite, summarize, translate, fix typos)" + } + }, + { + "type": "update", + "index": 23, + "block": { + "props": { + "level": 3 + }, + "content": "Collaboration" + } + }, + { + "type": "update", + "index": 24, + "block": { + "type": "bulletListItem", + "content": "Live cursors & presence" + } + }, + { + "type": "update", + "index": 25, + "block": { + "type": "bulletListItem", + "content": "Comments & sharing" + } + }, + { + "type": "update", + "index": 26, + "block": { + "type": "bulletListItem", + "content": "Granular access control" + } + }, + { + "type": "update", + "index": 27, + "block": { + "type": "heading", + "props": { + "level": 3 + }, + "content": "Knowledge management" + } + }, + { + "type": "update", + "index": 28, + "block": { + "type": "bulletListItem", + "content": "Subpages & hierarchy" + } + }, + { + "type": "update", + "index": 29, + "block": { + "type": "bulletListItem", + "content": "Searchable content" + } + }, + { + "type": "update", + "index": 30, + "block": { + "props": { + "level": 3 + }, + "content": "Export/Import & interoperability" + } + }, + { + "type": "update", + "index": 31, + "block": { + "type": "bulletListItem", + "content": [ + { + "type": "text", + "text": "Import to " + }, + { + "type": "text", + "text": ".docx", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": " and " + }, + { + "type": "text", + "text": ".md", + "styles": { + "code": true + } + } + ] + } + }, + { + "type": "update", + "index": 32, + "block": { + "type": "bulletListItem", + "content": [ + { + "type": "text", + "text": "Export to " + }, + { + "type": "text", + "text": ".docx", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": ", " + }, + { + "type": "text", + "text": ".odt", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": ", " + }, + { + "type": "text", + "text": ".pdf", + "styles": { + "code": true + } + } + ] + } + }, + { + "type": "update", + "index": 33, + "block": { + "props": { + "level": 2 + }, + "content": "Try Docs" + } + }, + { + "type": "update", + "index": 34, + "block": { + "type": "paragraph", + "content": "Experience Docs instantly - no installation required." + } + }, + { + "type": "update", + "index": 35, + "block": { + "type": "bulletListItem", + "content": "🔗 [Open a live demo document][demo]" + } + }, + { + "type": "update", + "index": 36, + "block": { + "type": "bulletListItem", + "content": "🌍 [Browse public instances][instances]" + } + }, + { + "type": "update", + "index": 37, + "block": { + "type": "paragraph", + "content": "[demo]: https://docs.la-suite.eu/docs/9137bbb5-3e8a-4ff7-8a36-fcc4e8bd57f4/\n [instances]: /docs/instances.md" + } + }, + { + "type": "update", + "index": 38, + "block": { + "type": "heading", + "props": { + "level": 2 + }, + "content": "Self-hosting" + } + }, + { + "type": "update", + "index": 39, + "block": { + "content": "Docs supports Kubernetes, Docker Compose, and community-provided methods such as Nix and YunoHost." + } + }, + { + "type": "update", + "index": 40, + "block": { + "content": [ + { + "type": "text", + "text": "Get started with self-hosting: " + }, + { + "type": "link", + "href": "/docs/installation/README.md", + "content": [ + { + "type": "text", + "text": "Installation guide" + } + ] + } + ] + } + }, + { + "type": "update", + "index": 41, + "block": { + "type": "quote", + "content": [ + { + "type": "text", + "text": "[!WARNING]\n Some advanced features (for example: " + }, + { + "type": "text", + "text": "Export as PDF", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": ") rely on XL packages from Blocknote.\n These packages are licensed under GPL and are " + }, + { + "type": "text", + "text": "not MIT-compatible\n", + "styles": { + "bold": true + } + }, + { + "type": "text", + "text": "You can run Docs " + }, + { + "type": "text", + "text": "without these packages", + "styles": { + "bold": true + } + }, + { + "type": "text", + "text": " by building with:\nThis builds an image of Docs without non-MIT features.\nMore details can be found in " + }, + { + "type": "link", + "href": "/docs/env.md", + "content": [ + { + "type": "text", + "text": "environment variables" + } + ] + }, + { + "type": "text", + "text": "PUBLISH_AS_MIT=true" + } + ] + } + }, + { + "type": "update", + "index": 42, + "block": { + "type": "heading", + "props": { + "level": 2 + }, + "content": "Local Development (for contributors)" + } + }, + { + "type": "update", + "index": 43, + "block": { + "content": "Run Docs locally for development and testing." + } + }, + { + "type": "update", + "index": 44, + "block": { + "type": "quote", + "content": [ + { + "type": "text", + "text": "[!WARNING]\n This setup is intended " + }, + { + "type": "text", + "text": "for development and testing only", + "styles": { + "bold": true + } + }, + { + "type": "text", + "text": ".\n It uses Minio as an S3-compatible storage backend, but any S3-compatible service can be used." + } + ] + } + }, + { + "type": "update", + "index": 45, + "block": { + "type": "heading", + "props": { + "level": 3 + }, + "content": "Prerequisites" + } + }, + { + "type": "update", + "index": 46, + "block": { + "type": "bulletListItem", + "content": "Docker" + } + }, + { + "type": "update", + "index": 47, + "block": { + "type": "bulletListItem", + "content": "Docker Compose" + } + }, + { + "type": "update", + "index": 48, + "block": { + "type": "bulletListItem", + "content": "GNU Make" + } + }, + { + "type": "update", + "index": 49, + "block": { + "content": "Verify installation:" + } + }, + { + "type": "update", + "index": 50, + "block": { + "type": "codeBlock", + "props": { + "language": "bash" + }, + "content": "docker -v\ndocker compose version" + } + }, + { + "type": "update", + "index": 51, + "block": { + "type": "quote", + "content": [ + { + "type": "text", + "text": "If you encounter permission errors, you may need to use " + }, + { + "type": "text", + "text": "sudo", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": ", or add your user to the " + }, + { + "type": "text", + "text": "docker", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": " group." + } + ] + } + }, + { + "type": "update", + "index": 52, + "block": { + "type": "heading", + "props": { + "level": 3 + }, + "content": "Bootstrap the project" + } + }, + { + "type": "update", + "index": 53, + "block": { + "type": "paragraph", + "content": "The easiest way to start is using GNU Make:" + } + }, + { + "type": "update", + "index": 54, + "block": { + "type": "codeBlock", + "props": { + "language": "bash" + }, + "content": "make bootstrap FLUSH_ARGS='--no-input'" + } + }, + { + "type": "update", + "index": 55, + "block": { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "This builds the " + }, + { + "type": "text", + "text": "app-dev", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": " and " + }, + { + "type": "text", + "text": "frontend-dev", + "styles": { + "code": true + } + }, + { + "type": "text", + "text": " containers, installs dependencies, runs database migrations, and compiles translations." + } + ] + } + }, + { + "type": "update", + "index": 56, + "block": { + "content": "It is recommended to run this command after pulling new code." + } + }, + { + "type": "update", + "index": 57, + "block": { + "type": "paragraph", + "content": "Start services:" + } + }, + { + "type": "update", + "index": 58, + "block": { + "type": "codeBlock", + "props": { + "language": "bash" + }, + "content": "make run" + } + }, + { + "type": "update", + "index": 59, + "block": { + "content": "Open " + } + }, + { + "type": "update", + "index": 60, + "block": { + "type": "paragraph", + "content": "Default credentials (development only):" + } + }, + { + "type": "update", + "index": 61, + "block": { + "type": "codeBlock", + "props": { + "language": "md" + }, + "content": "username: impress\npassword: impress" + } + }, + { + "type": "update", + "index": 62, + "block": { + "type": "heading", + "props": { + "level": 3 + }, + "content": "Frontend development mode" + } + }, + { + "type": "update", + "index": 63, + "block": { + "content": "For frontend work, running outside Docker is often more convenient:" + } + }, + { + "type": "update", + "index": 64, + "block": { + "type": "codeBlock", + "props": { + "language": "bash" + }, + "content": "make frontend-development-install\nmake run-frontend-development" + } + }, + { + "type": "update", + "index": 65, + "block": { + "type": "heading", + "props": { + "level": 3 + }, + "content": "Backend only" + } + }, + { + "type": "update", + "index": 66, + "block": { + "content": "Starting all services except the frontend container:" + } + }, + { + "type": "update", + "index": 67, + "block": { + "props": { + "language": "bash" + }, + "content": "make run-backend" + } + }, + { + "type": "update", + "index": 68, + "block": { + "props": { + "level": 3 + }, + "content": "Tests & Linting" + } + }, + { + "type": "update", + "index": 69, + "block": { + "type": "codeBlock", + "props": { + "language": "bash" + }, + "content": "make frontend-test\nmake frontend-lint" + } + }, + { + "type": "update", + "index": 70, + "block": { + "props": { + "level": 3 + }, + "content": "Demo content" + } + }, + { + "type": "update", + "index": 71, + "block": { + "content": "Create a basic demo site:" + } + }, + { + "type": "insert", + "index": 72, + "block": { + "type": "codeBlock", + "props": { + "language": "bash" + }, + "content": "make demo" + } + }, + { + "type": "insert", + "index": 73, + "block": { + "type": "heading", + "props": { + "level": 3 + }, + "content": "More Make targets" + } + }, + { + "type": "insert", + "index": 74, + "block": { + "type": "paragraph", + "content": "To check all available Make rules:" + } + }, + { + "type": "insert", + "index": 75, + "block": { + "type": "codeBlock", + "props": { + "language": "bash" + }, + "content": "make help" + } + }, + { + "type": "insert", + "index": 76, + "block": { + "type": "heading", + "props": { + "level": 3 + }, + "content": "Django admin" + } + }, + { + "type": "insert", + "index": 77, + "block": { + "type": "paragraph", + "content": "Create a superuser:" + } + }, + { + "type": "insert", + "index": 78, + "block": { + "type": "codeBlock", + "props": { + "language": "bash" + }, + "content": "make superuser" + } + }, + { + "type": "insert", + "index": 79, + "block": { + "type": "paragraph", + "content": "Admin UI: " + } + }, + { + "type": "insert", + "index": 80, + "block": { + "type": "heading", + "props": { + "level": 2 + }, + "content": "Contributing" + } + }, + { + "type": "insert", + "index": 81, + "block": { + "type": "paragraph", + "content": "This project is community-driven and PRs are welcome." + } + }, + { + "type": "insert", + "index": 82, + "block": { + "type": "bulletListItem", + "content": [ + { + "type": "link", + "href": "CONTRIBUTING.md", + "content": [ + { + "type": "text", + "text": "Contribution guide" + } + ] + } + ] + } + }, + { + "type": "insert", + "index": 83, + "block": { + "type": "bulletListItem", + "content": [ + { + "type": "link", + "href": "https://crowdin.com/project/lasuite-docs", + "content": [ + { + "type": "text", + "text": "Translations" + } + ] + } + ] + } + }, + { + "type": "insert", + "index": 84, + "block": { + "type": "bulletListItem", + "content": [ + { + "type": "link", + "href": "https://matrix.to/#/#docs-official:matrix.org", + "content": [ + { + "type": "text", + "text": "Chat with us!" + } + ] + } + ] + } + }, + { + "type": "insert", + "index": 85, + "block": { + "type": "heading", + "props": { + "level": 2 + }, + "content": "Roadmap" + } + }, + { + "type": "insert", + "index": 86, + "block": { + "type": "paragraph", + "content": "Curious where Docs is headed?" + } + }, + { + "type": "insert", + "index": 87, + "block": { + "type": "paragraph", + "content": [ + { + "type": "text", + "text": "Explore upcoming features, priorities and long-term direction on our " + }, + { + "type": "link", + "href": "https://docs.numerique.gouv.fr/docs/d1d3788e-c619-41ff-abe8-2d079da2f084/", + "content": [ + { + "type": "text", + "text": "public roadmap" + } + ] + }, + { + "type": "text", + "text": "." + } + ] + } + }, + { + "type": "delete", + "index": 91 + }, + { + "type": "delete", + "index": 91 + }, + { + "type": "delete", + "index": 91 + }, + { + "type": "delete", + "index": 91 + }, + { + "type": "delete", + "index": 91 + }, + { + "type": "delete", + "index": 91 + }, + { + "type": "update", + "index": 93, + "block": { + "content": [ + { + "type": "text", + "text": "Docs is built on top of " + }, + { + "type": "link", + "href": "https://www.django-rest-framework.org/", + "content": [ + { + "type": "text", + "text": "Django Rest Framework" + } + ] + }, + { + "type": "text", + "text": ", " + }, + { + "type": "link", + "href": "https://nextjs.org/", + "content": [ + { + "type": "text", + "text": "Next.js" + } + ] + }, + { + "type": "text", + "text": ", " + }, + { + "type": "link", + "href": "https://prosemirror.net/", + "content": [ + { + "type": "text", + "text": "ProseMirror" + } + ] + }, + { + "type": "text", + "text": ", " + }, + { + "type": "link", + "href": "https://www.blocknotejs.org/", + "content": [ + { + "type": "text", + "text": "BlockNote.js" + } + ] + }, + { + "type": "text", + "text": ", " + }, + { + "type": "link", + "href": "https://tiptap.dev/docs/hocuspocus/introduction", + "content": [ + { + "type": "text", + "text": "HocusPocus" + } + ] + }, + { + "type": "text", + "text": ", and " + }, + { + "type": "link", + "href": "https://yjs.dev/", + "content": [ + { + "type": "text", + "text": "Yjs" + } + ] + }, + { + "type": "text", + "text": ". We thank the contributors of all these projects for their awesome work!" + } + ] + } + }, + { + "type": "insert", + "index": 95, + "block": { + "type": "divider" + } + }, + { + "type": "update", + "index": 97, + "block": { + "content": [ + { + "type": "text", + "text": "Docs is the result of a joint initiative led by the French 🇫🇷 (" + }, + { + "type": "link", + "href": "https://www.numerique.gouv.fr/dinum/", + "content": [ + { + "type": "text", + "text": "DINUM" + } + ] + }, + { + "type": "text", + "text": ") Government and German 🇩🇪 government (" + }, + { + "type": "link", + "href": "https://zendis.de/", + "content": [ + { + "type": "text", + "text": "ZenDiS" + } + ] + }, + { + "type": "text", + "text": ")." + } + ] + } + }, + { + "type": "update", + "index": 98, + "block": { + "content": [ + { + "type": "text", + "text": "We are always looking for new public partners (we are currently onboarding the Netherlands 🇳🇱), feel free to " + }, + { + "type": "link", + "href": "mailto:docs@numerique.gouv.fr", + "content": [ + { + "type": "text", + "text": "contact us" + } + ] + }, + { + "type": "text", + "text": " if you are interested in using or contributing to Docs." + } + ] + } + }, + { + "type": "update", + "index": 99, + "block": { + "props": { + "name": "Europe Opensource", + "url": "/docs/assets/europe_opensource.png" + } + } + } + ] + } + ] +} diff --git a/examples/07-collaboration/14-multi-doc-versioning/tsconfig.json b/examples/07-collaboration/14-multi-doc-versioning/tsconfig.json new file mode 100644 index 0000000000..93fa81bee8 --- /dev/null +++ b/examples/07-collaboration/14-multi-doc-versioning/tsconfig.json @@ -0,0 +1,29 @@ +{ + "__comment": "AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY", + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "allowJs": false, + "skipLibCheck": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "composite": true + }, + "include": ["."], + "__ADD_FOR_LOCAL_DEV_references": [ + { + "path": "../../../packages/core/" + }, + { + "path": "../../../packages/react/" + } + ] +} diff --git a/examples/07-collaboration/14-multi-doc-versioning/vite.config.ts b/examples/07-collaboration/14-multi-doc-versioning/vite.config.ts new file mode 100644 index 0000000000..0133a6da9e --- /dev/null +++ b/examples/07-collaboration/14-multi-doc-versioning/vite.config.ts @@ -0,0 +1,31 @@ +// AUTO-GENERATED FILE, DO NOT EDIT DIRECTLY +import react from "@vitejs/plugin-react"; +import * as fs from "fs"; +import * as path from "path"; +import { defineConfig } from "vite-plus"; +// https://vitejs.dev/config/ +export default defineConfig(((conf: { command: string }) => ({ + plugins: [react()], + optimizeDeps: {}, + build: { + sourcemap: true, + }, + resolve: { + alias: + conf.command === "build" || + !fs.existsSync(path.resolve(__dirname, "../../packages/core/src")) + ? {} + : ({ + // Comment out the lines below to load a built version of blocknote + // or, keep as is to load live from sources with live reload working + "@blocknote/core": path.resolve( + __dirname, + "../../packages/core/src/", + ), + "@blocknote/react": path.resolve( + __dirname, + "../../packages/react/src/", + ), + } as any), + }, +})) as Parameters[0]); diff --git a/packages/core/package.json b/packages/core/package.json index 88309cdeef..fbe4f404b9 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -109,7 +109,7 @@ "@tiptap/pm": "^3.13.0", "emoji-mart": "^5.6.0", "fast-deep-equal": "^3.1.3", - "lib0": "1.0.0-rc.13", + "lib0": "1.0.0-rc.14", "prosemirror-highlight": "^0.15.1", "prosemirror-model": "^1.25.4", "prosemirror-state": "^1.4.4", @@ -131,7 +131,7 @@ "y-prosemirror": "^1.3.7", "y-protocols": "^1.0.6", "yjs": "^13.6.27", - "@y/y": "^14.0.0-rc.16", + "@y/y": "^14.0.0-rc.17", "@y/prosemirror": "^2.0.0-2", "@y/protocols": "^1.0.6-rc.1" }, diff --git a/packages/core/src/extensions/tiptap-extensions/Suggestions/SuggestionMarks.ts b/packages/core/src/extensions/tiptap-extensions/Suggestions/SuggestionMarks.ts index 38a62baf07..994871bc0d 100644 --- a/packages/core/src/extensions/tiptap-extensions/Suggestions/SuggestionMarks.ts +++ b/packages/core/src/extensions/tiptap-extensions/Suggestions/SuggestionMarks.ts @@ -6,13 +6,30 @@ import { MarkSpec } from "prosemirror-model"; // The ideal solution would be to not depend on tiptap nodes / marks, but be able to use prosemirror nodes / marks directly // this way we could directly use the exported marks from @handlewithcare/prosemirror-suggest-changes + +const formatAttributionTitle = ( + action: string, + userIds: readonly string[] | null, + timestamp: number | null, +): string => { + const who = userIds && userIds.length > 0 ? userIds.join(", ") : "unknown"; + const when = + timestamp != null + ? new Date(timestamp).toLocaleString([], { + dateStyle: "medium", + timeStyle: "short", + }) + : "unknown time"; + return `${action} by ${who} on ${when}`; +}; export const SuggestionAddMark = Mark.create({ name: "y-attributed-insert", inclusive: false, - excludes: "", + // excludes: "", TODO: what's desired? addAttributes() { return { - id: { default: null, validate: "number" }, // note: validate is supported in prosemirror but not in tiptap, so this doesn't actually work (considered not critical) + userIds: { default: null }, + timestamp: { default: null }, "user-color": { default: null, validate: "string" }, }; }, @@ -28,7 +45,13 @@ export const SuggestionAddMark = Mark.create({ return [ "ins", { - "data-id": String(mark.attrs["id"]), + "data-description": formatAttributionTitle( + "Inserted", + mark.attrs["userIds"], + mark.attrs["timestamp"], + ), + "data-user-ids": JSON.stringify(mark.attrs["userIds"]), + "data-timestamp": String(mark.attrs["timestamp"]), "data-user-color": String(mark.attrs["user-color"]), "data-inline": String(inline), style: @@ -44,12 +67,15 @@ export const SuggestionAddMark = Mark.create({ { tag: "ins", getAttrs(node) { - if (!node.dataset["id"]) { + if (!node.dataset["userIds"]) { return false; } return { - id: parseInt(node.dataset["id"], 10), - userColor: node.dataset["userColor"], + userIds: JSON.parse(node.dataset["userIds"]), + timestamp: node.dataset["timestamp"] + ? parseInt(node.dataset["timestamp"], 10) + : null, + "user-color": node.dataset["userColor"], }; }, }, @@ -61,10 +87,11 @@ export const SuggestionAddMark = Mark.create({ export const SuggestionDeleteMark = Mark.create({ name: "y-attributed-delete", inclusive: false, - excludes: "", + // excludes: "", TODO: what's desired? addAttributes() { return { - id: { default: null, validate: "number" }, // note: validate is supported in prosemirror but not in tiptap + userIds: { default: null }, + timestamp: { default: null }, "user-color": { default: null, validate: "string" }, }; }, @@ -76,14 +103,17 @@ export const SuggestionDeleteMark = Mark.create({ blocknoteIgnore: true, inclusive: false, - // attrs: { - // id: { validate: "number" }, - // }, toDOM(mark, inline) { return [ "del", { - "data-id": String(mark.attrs["id"]), + "data-description": formatAttributionTitle( + "Deleted", + mark.attrs["userIds"], + mark.attrs["timestamp"], + ), + "data-user-ids": JSON.stringify(mark.attrs["userIds"]), + "data-timestamp": String(mark.attrs["timestamp"]), "data-user-color": String(mark.attrs["user-color"]), "data-inline": String(inline), style: @@ -99,12 +129,15 @@ export const SuggestionDeleteMark = Mark.create({ { tag: "del", getAttrs(node) { - if (!node.dataset["id"]) { + if (!node.dataset["userIds"]) { return false; } return { - id: parseInt(node.dataset["id"], 10), - userColor: node.dataset["userColor"], + userIds: JSON.parse(node.dataset["userIds"]), + timestamp: node.dataset["timestamp"] + ? parseInt(node.dataset["timestamp"], 10) + : null, + "user-color": node.dataset["userColor"], }; }, }, @@ -116,10 +149,12 @@ export const SuggestionDeleteMark = Mark.create({ export const SuggestionModificationMark = Mark.create({ name: "y-attributed-format", inclusive: false, - excludes: "", + // excludes: "", TODO: what's desired? addAttributes() { return { - id: { default: null, validate: "number" }, // note: validate is supported in prosemirror but not in tiptap + userIds: { default: null }, + format: { default: null }, + timestamp: { default: null }, "user-color": { default: null, validate: "string" }, }; }, @@ -134,8 +169,15 @@ export const SuggestionModificationMark = Mark.create({ return [ inline ? "span" : "div", { + "data-description": formatAttributionTitle( + "Modified", + mark.attrs["userIds"], + mark.attrs["timestamp"], + ), "data-type": "modification", - "data-id": String(mark.attrs["id"]), + "data-user-ids": JSON.stringify(mark.attrs["userIds"]), + "data-format": JSON.stringify(mark.attrs["format"]), + "data-timestamp": String(mark.attrs["timestamp"]), "data-user-color": String(mark.attrs["user-color"]), style: (inline ? "" : "display: contents") + @@ -150,11 +192,17 @@ export const SuggestionModificationMark = Mark.create({ { tag: "span[data-type='modification']", getAttrs(node) { - if (!node.dataset["id"]) { + if (!node.dataset["userIds"]) { return false; } return { - id: parseInt(node.dataset["id"], 10), + userIds: JSON.parse(node.dataset["userIds"]), + format: node.dataset["format"] + ? JSON.parse(node.dataset["format"]) + : null, + timestamp: node.dataset["timestamp"] + ? parseInt(node.dataset["timestamp"], 10) + : null, "user-color": node.dataset["userColor"], }; }, @@ -162,11 +210,17 @@ export const SuggestionModificationMark = Mark.create({ { tag: "div[data-type='modification']", getAttrs(node) { - if (!node.dataset["id"]) { + if (!node.dataset["userIds"]) { return false; } return { - id: parseInt(node.dataset["id"], 10), + userIds: JSON.parse(node.dataset["userIds"]), + format: node.dataset["format"] + ? JSON.parse(node.dataset["format"]) + : null, + timestamp: node.dataset["timestamp"] + ? parseInt(node.dataset["timestamp"], 10) + : null, "user-color": node.dataset["userColor"], }; }, diff --git a/packages/core/src/extensions/tiptap-extensions/UniqueID/UniqueID.ts b/packages/core/src/extensions/tiptap-extensions/UniqueID/UniqueID.ts index 57a904ce3e..7ab30b78aa 100644 --- a/packages/core/src/extensions/tiptap-extensions/UniqueID/UniqueID.ts +++ b/packages/core/src/extensions/tiptap-extensions/UniqueID/UniqueID.ts @@ -4,9 +4,9 @@ import { findChildrenInRange, getChangedRanges, } from "@tiptap/core"; -import { Fragment, Slice } from "prosemirror-model"; -import { Plugin, PluginKey } from "prosemirror-state"; import { uuidv4 } from "lib0/random"; +import { Fragment, Node, Slice } from "prosemirror-model"; +import { Plugin, PluginKey } from "prosemirror-state"; import { isSuggestedDeletionNode } from "../../../api/getBlockInfoFromPos.js"; /** @@ -42,6 +42,20 @@ function findDuplicates(items: any) { return duplicates; } +/** + * Whether a node is marked as deleted by a suggestion (carries the + * `y-attributed-delete` node mark). + * + * Under the suggestion/matchNodes binding, changing a block's content type + * renders the block as a deleted copy (this mark) next to its inserted + * replacement - and both copies share the same `id`. The deleted copy must be + * ignored by the uniqueness logic, otherwise its `id` looks like a duplicate + * and we'd regenerate the `id` on the surviving block. + */ +function isMarkedDeleted(node: Node) { + return node.marks.some((mark) => mark.type.name === "y-attributed-delete"); +} + const UniqueID = Extension.create({ name: "uniqueID", // we’ll set a very high priority to make sure this runs first @@ -163,6 +177,10 @@ const UniqueID = Extension.create({ const duplicatedNewIds = findDuplicates(newIds); newNodes.forEach(({ node, pos }) => { + // ignore ids on blocks marked as deleted (see above). + if (isMarkedDeleted(node)) { + return; + } // instead of checking `node.attrs[attributeName]` directly // we look at the current state of the node within `tr.doc`. // this helps to prevent adding new ids to the same node diff --git a/packages/core/src/y/extensions/YSync.ts b/packages/core/src/y/extensions/YSync.ts index f4c9f73574..8902661e13 100644 --- a/packages/core/src/y/extensions/YSync.ts +++ b/packages/core/src/y/extensions/YSync.ts @@ -3,6 +3,7 @@ import { type ExtensionOptions, createExtension, } from "../../editor/BlockNoteExtension.js"; +import { blockMatchNodes } from "./blockMatchNodes.js"; import { CollaborationOptions } from "./index.js"; /** @@ -70,14 +71,16 @@ const mapAttributionToMark = ( if (attribution.insert) { out["y-attributed-insert"] = { - id: attribution.insert[0] ?? null, + userIds: attribution.insert, + timestamp: attribution.insertAt ?? null, "user-color": colorForUserIds(attribution.insert), }; } if (attribution.delete) { out["y-attributed-delete"] = { - id: attribution.delete[0] ?? null, + userIds: attribution.delete, + timestamp: attribution.deleteAt ?? null, "user-color": colorForUserIds(attribution.delete), }; } @@ -85,7 +88,9 @@ const mapAttributionToMark = ( if (attribution.format) { const userIds = [...new Set(Object.values(attribution.format).flat())]; out["y-attributed-format"] = { - id: userIds[0] ?? null, + userIds, + format: attribution.format, + timestamp: attribution.formatAt ?? null, "user-color": colorForUserIds(userIds), }; } @@ -118,6 +123,14 @@ export const YSyncExtension = createExtension( syncPlugin({ suggestionDoc: options.suggestionDoc, mapAttributionToMark, + // Node-pairing policy for the PM->Y diff: a `blockContainer` whose + // block-content type changes is treated as a *different* node, so the + // diff replaces the whole container (deleted + inserted siblings in + // the blockGroup) instead of producing two block-contents in one + // container => schema-invalid. No schema change / storage transform + // needed; `blockContainer` already whitelists the `y-attributed-*` + // marks. See blockMatchNodes.ts. + matchNodes: blockMatchNodes, }), ], runsBefore: ["default"], diff --git a/packages/core/src/y/extensions/blockMatchNodes.ts b/packages/core/src/y/extensions/blockMatchNodes.ts new file mode 100644 index 0000000000..9114bea8ff --- /dev/null +++ b/packages/core/src/y/extensions/blockMatchNodes.ts @@ -0,0 +1,50 @@ +import * as delta from "lib0/delta"; + +/** + * Canonical name of a content delta's first block child (the child carried by an + * insert op), or `null`. For a BlockNote `blockContainer` (content + * `blockContent blockGroup?`) this is its block-content type (paragraph, + * heading, image, ...). + */ +const firstChildName = (d: delta.DeltaAny): string | null => { + for (const op of (d as any).children) { + if (delta.$insertOp.check(op)) { + for (const it of op.insert) { + if (delta.$deltaAny.check(it)) { + return it.name; + } + } + } + } + return null; +}; + +/** + * BlockNote's node-pairing policy for y-prosemirror's `matchNodes` option + * (forwarded to `lib0/delta.diff`). This is the schema-specific bit that lives + * in userland - the binding itself stays schema-agnostic. + * + * A `blockContainer` holds exactly one block content (`blockContent + * blockGroup?`). Diffing a *type change* of that content as an in-place child + * delete+insert would, under a suggestion, tombstone the old content next to the + * new one => two block-contents in one container => schema-invalid. So we + * declare a container's identity to be its first block-content child's type: + * when that changes, the two containers are reported as *different*, the PM->Y + * diff replaces the whole container, and the deleted + inserted containers sit + * as siblings in the blockGroup (`blockGroupChild+` allows that). Each carries + * the `y-attributed-*` node mark - which `blockContainer` already whitelists - + * so no schema change and no storage transform are needed. A plain text edit + * keeps the same first-child type => same identity => the diff descends and + * merges as usual. + * + * @param a removed (old) node + * @param b inserted (new) node + * @returns whether `a` and `b` are the same node (diff in place) vs different (replace) + */ +export const blockMatchNodes = ( + a: delta.DeltaAny, + b: delta.DeltaAny, +): boolean => + (a as any).name === (b as any).name && + ((a as any).name !== "blockContainer" || + firstChildName(a) === firstChildName(b)); diff --git a/packages/core/src/y/index.ts b/packages/core/src/y/index.ts index 75f99c8e15..4a0e02964e 100644 --- a/packages/core/src/y/index.ts +++ b/packages/core/src/y/index.ts @@ -1,3 +1,4 @@ export * from "./extensions/index.js"; export * from "./utils.js"; export * from "./comments/index.js"; +export * from "./versioning/index.js"; diff --git a/packages/core/src/y/versioning/index.ts b/packages/core/src/y/versioning/index.ts new file mode 100644 index 0000000000..739cdf36c7 --- /dev/null +++ b/packages/core/src/y/versioning/index.ts @@ -0,0 +1 @@ +export * from "./yhub.js"; diff --git a/packages/core/src/y/versioning/yhub.ts b/packages/core/src/y/versioning/yhub.ts new file mode 100644 index 0000000000..6cd518365d --- /dev/null +++ b/packages/core/src/y/versioning/yhub.ts @@ -0,0 +1,298 @@ +import * as Y from "@y/y"; +import { decodeAny, encodeAny } from "lib0/buffer"; + +import { + sortSnapshotsNewestFirst, + type CreateSnapshotOptions, + type VersioningEndpoints, + type VersionSnapshot, +} from "../../extensions/Versioning/index.js"; + +// --------------------------------------------------------------------------- +// Types +// --------------------------------------------------------------------------- + +/** + * Options for creating a YHub versioning endpoints instance. + */ +export interface YHubVersioningOptions { + /** + * Base URL of the YHub API (e.g. `"https://yhub.example.com"`). + * Must **not** include a trailing slash. + */ + baseUrl: string; + + /** YHub organisation identifier. */ + org: string; + + /** Document identifier within the organisation. */ + docId: string; + + /** + * Optional headers to include in every request (e.g. authentication tokens). + */ + headers?: Record; + + /** + * Maximum number of activity entries to fetch when listing versions. + * @default 50 + */ + activityLimit?: number; +} + +/** + * Shape of a single activity entry returned by the YHub + * `GET /activity/{org}/{docId}` endpoint (after `decodeAny`). + */ +interface YHubActivityEntry { + /** Start of the change window (unix-ms timestamp). */ + from: number; + /** End of the change window (unix-ms timestamp). */ + to: number; + /** User who authored the change (when `customAttributions` is enabled). */ + by?: string; +} + +/** + * Shape returned by the YHub `GET /changeset/{org}/{docId}` endpoint (after + * `decodeAny`). + */ +interface YHubChangeset { + /** Full Y.Doc state **before** the changeset window. */ + prevDoc?: Uint8Array; + /** Full Y.Doc state **after** the changeset window. */ + nextDoc?: Uint8Array; +} + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +/** Snapshot-metadata store (names & options that aren't tracked by YHub). */ +interface SnapshotMeta { + name?: string; + restoredFromSnapshotId?: string; +} + +/** + * Convert a YHub activity entry into a {@link VersionSnapshot}. + */ +function activityToSnapshot( + entry: YHubActivityEntry, + meta?: SnapshotMeta, +): VersionSnapshot { + return { + id: String(entry.to), + name: meta?.name, + createdAt: entry.from, + updatedAt: entry.to, + secondaryLabel: entry.by, + restoredFromSnapshotId: meta?.restoredFromSnapshotId, + }; +} + +async function yhubFetch( + url: string, + headers: Record, + init?: RequestInit, +): Promise { + const res = await fetch(url, { + ...init, + headers: { ...headers, ...init?.headers }, + }); + if (!res.ok) { + throw new Error( + `YHub request failed: ${res.status} ${res.statusText} (${url})`, + ); + } + return res.arrayBuffer(); +} + +// --------------------------------------------------------------------------- +// Factory +// --------------------------------------------------------------------------- + +/** + * Create a {@link VersioningEndpoints} implementation backed by the + * [YHub](https://github.com/yjs/yhub) HTTP API. + * + * YHub stores continuous edit history rather than discrete snapshots. This + * adapter maps YHub's *activity* entries to {@link VersionSnapshot}s so they + * can be listed, previewed, and restored through BlockNote's versioning UI. + * + * @example + * ```ts + * import { withCollaboration } from "@blocknote/core/y"; + * import { createYHubVersioningEndpoints } from "@blocknote/core/y"; + * + * const editor = BlockNoteEditor.create( + * withCollaboration({ + * collaboration: { + * fragment, + * user: { name: "Alice", color: "#ff0" }, + * provider, + * versioningEndpoints: createYHubVersioningEndpoints({ + * baseUrl: "https://yhub.example.com", + * org: "my-org", + * docId: "my-doc", + * }), + * }, + * }), + * ); + * ``` + */ +export function createYHubVersioningEndpoints( + options: YHubVersioningOptions, +): VersioningEndpoints { + const { baseUrl, org, docId, headers = {}, activityLimit = 50 } = options; + + const activityUrl = `${baseUrl}/activity/${org}/${docId}`; + const changesetUrl = `${baseUrl}/changeset/${org}/${docId}`; + const rollbackUrl = `${baseUrl}/rollback/${org}/${docId}`; + + // Client-side metadata (names, restored-from links) keyed by snapshot id. + const metaMap = new Map(); + + // ------------------------------------------------------------------ + // list + // ------------------------------------------------------------------ + const list: VersioningEndpoints["list"] = async () => { + const params = new URLSearchParams({ + order: "desc", + limit: String(activityLimit), + group: "true", + customAttributions: "true", + }); + + const buf = await yhubFetch(`${activityUrl}?${params}`, headers); + const entries = decodeAny(new Uint8Array(buf)) as YHubActivityEntry[]; + + return sortSnapshotsNewestFirst( + entries.map((e) => activityToSnapshot(e, metaMap.get(String(e.to)))), + ); + }; + + // ------------------------------------------------------------------ + // create + // ------------------------------------------------------------------ + const create: VersioningEndpoints["create"] = async ( + fragment: Y.Type, + opts?: CreateSnapshotOptions, + ) => { + const doc = fragment.doc; + if (!doc) { + throw new Error( + "Cannot create snapshot: the Y.Type is not attached to a Y.Doc.", + ); + } + + // Encode the current document state. + const update = Y.encodeStateAsUpdateV2(doc); + + // Persist via PATCH /ydoc to make sure the current state is stored. + await yhubFetch(`${baseUrl}/ydoc/${org}/${docId}`, headers, { + method: "PATCH", + body: encodeAny({ update }) as Blob | BufferSource, + }); + + const now = Date.now(); + const id = String(now); + + const meta: SnapshotMeta = { + name: opts?.name, + restoredFromSnapshotId: opts?.restoredFromSnapshotId, + }; + metaMap.set(id, meta); + + return { + id, + name: opts?.name, + createdAt: now, + updatedAt: now, + restoredFromSnapshotId: opts?.restoredFromSnapshotId, + }; + }; + + // ------------------------------------------------------------------ + // getContent + // ------------------------------------------------------------------ + const getContent: VersioningEndpoints< + Y.Type, + Uint8Array + >["getContent"] = async (id: string) => { + const to = Number(id); + const params = new URLSearchParams({ + from: "0", + to: String(to), + ydoc: "true", + }); + + const buf = await yhubFetch(`${changesetUrl}?${params}`, headers); + const changeset = decodeAny(new Uint8Array(buf)) as YHubChangeset; + + if (!changeset.nextDoc) { + throw new Error(`YHub returned no document state for snapshot ${id}.`); + } + + return changeset.nextDoc; + }; + + // ------------------------------------------------------------------ + // restore + // ------------------------------------------------------------------ + const restore: VersioningEndpoints["restore"] = async ( + fragment: Y.Type, + id: string, + ) => { + // 1. Create a backup snapshot of the current state. + await create(fragment, { name: "Backup" }); + + // 2. Get the content of the target snapshot. + const snapshotContent = await getContent(id); + + // 3. Issue a rollback via YHub. Rolling back everything after the target + // timestamp effectively restores the document to that point. + const to = Number(id); + await yhubFetch(`${rollbackUrl}?from=${to}`, headers, { + method: "POST", + body: encodeAny({ from: to, customAttributions: true }) as + | Blob + | BufferSource, + }); + + // 4. Record metadata for the restored snapshot. + const restoredSnapshot = await create(fragment, { + name: "Restored Snapshot", + restoredFromSnapshotId: id, + }); + + metaMap.set(restoredSnapshot.id, { + name: "Restored Snapshot", + restoredFromSnapshotId: id, + }); + + return snapshotContent; + }; + + // ------------------------------------------------------------------ + // updateSnapshotName + // ------------------------------------------------------------------ + const updateSnapshotName: VersioningEndpoints< + Y.Type, + Uint8Array + >["updateSnapshotName"] = async (id: string, name?: string) => { + const existing = metaMap.get(id) ?? {}; + metaMap.set(id, { ...existing, name }); + }; + + // ------------------------------------------------------------------ + // Return + // ------------------------------------------------------------------ + return { + list, + create, + getContent, + restore, + updateSnapshotName, + }; +} diff --git a/patches/@y__prosemirror@2.0.0-2.patch b/patches/@y__prosemirror@2.0.0-2.patch index dab913697b..7d7c8f1216 100644 --- a/patches/@y__prosemirror@2.0.0-2.patch +++ b/patches/@y__prosemirror@2.0.0-2.patch @@ -100,7 +100,7 @@ index 0000000000000000000000000000000000000000..f09b4e94cfb42585d13b700cef3f4fb0 +{"version":3,"file":"cursor-plugin.d.ts","sourceRoot":"","sources":["../../src/cursor-plugin.js"],"names":[],"mappings":"AAgCO,2CAHI,IAAI,GACH,WAAW,CAmBtB;AAQM,8CAHI,IAAI,GACH,OAAO,kBAAkB,EAAE,eAAe,CAOrD;AAYM,yCATI,OAAO,mBAAmB,EAAE,WAAW,aACvC,OAAO,wBAAwB,EAAE,SAAS,mBAC1C,eAAe,gBACf,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,mBACzC,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,kBAAkB,EAAE,eAAe,oBAC5E,MAAM,UACN;IAAC,KAAK,EAAE,CAAC,CAAC,IAAI,GAAG,IAAI,CAAC;IAAC,kBAAkB,EAAE,CAAC,CAAC,0BAA0B,GAAG,IAAI,CAAA;CAAC,GAAG,SAAS,GAC1F,aAAa,CAkExB;AA2BM,yCATI,OAAO,wBAAwB,EAAE,SAAS,yGAElD;IAA+B,oBAAoB;IACU,aAAa,WAA3D,IAAI,YAAY,MAAM,KAAK,WAAW;IACuC,gBAAgB,WAA7F,IAAI,YAAY,MAAM,KAAK,OAAO,kBAAkB,EAAE,eAAe;IACrC,uBAAuB;IAChD,gBAAgB;CACtC,GAAS,MAAM,CAAC,aAAa,CAAC,CAmL7B;;;;;;;;;;;gDAlUO,MAAM,gBACN,MAAM,kBACN,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,KACjB,OAAO;oDAwHjB;IAAmD,IAAI,EAA/C,OAAO,kBAAkB,EAAE,UAAU;IAC8B,SAAS,EAA5E;QAAC,MAAM,EAAE,CAAC,CAAC,gBAAgB,CAAC;QAAC,IAAI,EAAE,CAAC,CAAC,gBAAgB,CAAA;KAAC,GAAG,IAAI;IACM,SAAS,EAA5E;QAAC,MAAM,EAAE,CAAC,CAAC,gBAAgB,CAAC;QAAC,IAAI,EAAE,CAAC,CAAC,gBAAgB,CAAA;KAAC,GAAG,IAAI;IAChD,UAAU,EAAvB,OAAO;IAC0B,MAAM,EAAvC,QAAQ,GAAG,OAAO,GAAG,MAAM;CACnC,KAAU;IAAC,MAAM,EAAE,CAAC,CAAC,gBAAgB,CAAC;IAAC,IAAI,EAAE,CAAC,CAAC,gBAAgB,CAAA;CAAC,GAAG,IAAI;mBApJvD,MAAM;8BACiB,kBAAkB;uBACrC,mBAAmB"} \ No newline at end of file diff --git a/dist/src/index.d.ts b/dist/src/index.d.ts -index fec5f1c23d3f28e250fecd7045fcebe7fc60993f..ebf62e224dcb8a4becb6dcc0e59799e732a4ce1c 100644 +index fec5f1c23d3f28e250fecd7045fcebe7fc60993f..c870a6d1eaa70daf2a6c718b179cb7873ae19e94 100644 --- a/dist/src/index.d.ts +++ b/dist/src/index.d.ts @@ -1,84 +1,8 @@ @@ -194,7 +194,7 @@ index fec5f1c23d3f28e250fecd7045fcebe7fc60993f..ebf62e224dcb8a4becb6dcc0e59799e7 +export * from "./commands.js"; +export * from "./undo-plugin.js"; +export * from "./cursor-plugin.js"; -+export { docToDelta, $prosemirrorDelta, defaultMapAttributionToMark } from "./sync-utils.js"; ++export { docToDelta, $prosemirrorDelta, defaultMapAttributionToMark, yattr2markname, pmToFragment, fragmentToPm } from "./sync-utils.js"; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/dist/src/index.d.ts.map b/dist/src/index.d.ts.map @@ -286,10 +286,10 @@ index 0000000000000000000000000000000000000000..e4f768c579f11b08055a31cc166e8c34 \ No newline at end of file diff --git a/dist/src/sync-plugin.d.ts b/dist/src/sync-plugin.d.ts new file mode 100644 -index 0000000000000000000000000000000000000000..c1da2aa33b86511936e9b1ba4d2d3c848e0c70da +index 0000000000000000000000000000000000000000..56fcf104d0d08a0a21e3bf8941063abb0ec7e783 --- /dev/null +++ b/dist/src/sync-plugin.d.ts -@@ -0,0 +1,41 @@ +@@ -0,0 +1,44 @@ +/** + * This Prosemirror {@link Plugin} is responsible for synchronizing the prosemirror {@link EditorState} with a {@link Y.XmlFragment} + * @@ -303,12 +303,14 @@ index 0000000000000000000000000000000000000000..c1da2aa33b86511936e9b1ba4d2d3c84 + * @param {Y.Doc} [opts.suggestionDoc] A {@link Y.Doc} to use for suggestion tracking + * @param {AttributionMapper} [opts.mapAttributionToMark] A function to map the {@link Y.Attribution} to a {@link import('prosemirror-model').Mark} - the mark names *must* be one of: `y-attributed-insert`, `y-attributed-delete`, `y-attributed-format`. No other mark names are permitted + * @param {AttributedNodesPredicate} [opts.attributedNodes] Optional predicate `(nodeName, kinds) => boolean`. When it returns `true` for an attributed node *and* a `{nodeName}--attributed` type exists in the schema, that node is rendered under the variant type (the `y-attributed-*` marks are still applied). `kinds` is `{ insert?, delete?, format? }`. The variant is a pure rendering concern - the canonical name is what is stored in the Y document. The predicate must be deterministic in `(nodeName, kinds)`. ++ * @param {YpmMatchNodes} [opts.matchNodes] Node-pairing predicate for the PM->Y diff (forwarded to `lib0/delta.diff`). Given a removed node `a` and an inserted node `b` (content deltas with canonical names), return whether they are the *same* node - i.e. diffed in place (descend/modify) vs. replaced (delete + insert). Defaults to name-equality. Override to raise the diff boundary at a strict node: report two same-named nodes as *different* when the child that identifies them changed, so a suggestion's old/new content lands as sibling blocks in the permissive grandparent instead of as schema-invalid siblings inside the strict node (e.g. BlockNote's `blockContainer`, content `blockContent blockGroup?`). What identifies a node is schema-specific, hence the integrator's to define. A plain text edit (same identity) still descends and merges normally. + * @returns {Plugin} + */ +export function syncPlugin(opts?: { + suggestionDoc?: Y.Doc | undefined; + mapAttributionToMark?: AttributionMapper | undefined; + attributedNodes?: AttributedNodesPredicate | undefined; ++ matchNodes?: YpmMatchNodes | undefined; +}): Plugin; +/** + * The y-prosemirror binding is a bi-directional synchronization with the provided Y.Type and the EditorView @@ -319,6 +321,7 @@ index 0000000000000000000000000000000000000000..c1da2aa33b86511936e9b1ba4d2d3c84 + attributionManager: Y.AbstractAttributionManager | null; + attributionMapper: AttributionMapper; + attributedNodes: AttributedNodesPredicate; ++ matchNodes: YpmMatchNodes; +}>; +export const $syncPluginStateUpdate: s.Schema<{ + ytype?: Y.Type | null | undefined; @@ -334,18 +337,18 @@ index 0000000000000000000000000000000000000000..c1da2aa33b86511936e9b1ba4d2d3c84 \ No newline at end of file diff --git a/dist/src/sync-plugin.d.ts.map b/dist/src/sync-plugin.d.ts.map new file mode 100644 -index 0000000000000000000000000000000000000000..df8c9df944fe1c64c46c648d913a0f8b52694bd7 +index 0000000000000000000000000000000000000000..3575d0e44bf8c37230381401f8e5a39d09092bfc --- /dev/null +++ b/dist/src/sync-plugin.d.ts.map @@ -0,0 +1 @@ -+{"version":3,"file":"sync-plugin.d.ts","sourceRoot":"","sources":["../../src/sync-plugin.js"],"names":[],"mappings":"AAgGA;;;;;;;;;;;;;;GAcG;AACH,kCALG;IAAqB,aAAa;IACD,oBAAoB;IACb,eAAe;CACvD,GAAU,MAAM,CA+LlB;AA7RD;;;GAGG;AACH;;;;;GAYE;AAEF;;;;;;GAME;mBAvCiB,MAAM;uBACF,mBAAmB;mBAWvB,aAAa"} ++{"version":3,"file":"sync-plugin.d.ts","sourceRoot":"","sources":["../../src/sync-plugin.js"],"names":[],"mappings":"AAsGA;;;;;;;;;;;;;;;GAeG;AACH,kCANG;IAAqB,aAAa;IACD,oBAAoB;IACb,eAAe;IAC1B,UAAU;CACvC,GAAU,MAAM,CAuMlB;AA3SD;;;GAGG;AACH;;;;;;GAiBE;AAEF;;;;;;GAME;mBA7CiB,MAAM;uBACF,mBAAmB;mBAYvB,aAAa"} \ No newline at end of file diff --git a/dist/src/sync-utils.d.ts b/dist/src/sync-utils.d.ts new file mode 100644 -index 0000000000000000000000000000000000000000..dfb00a847adcc5a1db01d557a8b0b056eefd1c9a +index 0000000000000000000000000000000000000000..7243ce51f02ae62155eb28a60ddd926d60b5a788 --- /dev/null +++ b/dist/src/sync-utils.d.ts -@@ -0,0 +1,146 @@ +@@ -0,0 +1,165 @@ +/** + * Transforms a {@link Node} into a {@link Y.XmlFragment} + * @param {Node} node @@ -433,6 +436,7 @@ index 0000000000000000000000000000000000000000..dfb00a847adcc5a1db01d557a8b0b056 +export function attributedVariant(canonicalName: string, format: Record | null | undefined, attributedNodes: AttributedNodesPredicate, schema: import("prosemirror-model").Schema): string; +export function defaultMapAttributionToMark(format: Record | null, attribution: T): Record | null; +export function deltaAttributionToFormat(d: delta.DeltaAny, attributionsToFormat: Function): ProsemirrorDelta; ++export function yattr2markname(attrName: string): string; +export function formattingAttributesToMarks(formatting: { + [key: string]: any; +} | null, schema: import("prosemirror-model").Schema): import("prosemirror-model").Mark[]; @@ -449,6 +453,24 @@ index 0000000000000000000000000000000000000000..dfb00a847adcc5a1db01d557a8b0b056 +export function deltaToPSteps(tr: import("prosemirror-state").Transaction, d: ProsemirrorDelta, pnode?: Node, currPos?: { + i: number; +}, attributedNodes?: AttributedNodesPredicate): import("prosemirror-state").Transaction; ++/** ++ * Default node-pairing predicate for the PM->Y diff, forwarded to ++ * `lib0/delta.diff`'s `matchNodes`: two nodes are the *same* node (diffed in ++ * place) iff they share a name - the standard `delta.diff` behavior. ++ * ++ * Override it via `syncPlugin`'s `matchNodes` option to make the diff treat ++ * certain same-named nodes as *different* (a whole-node delete + insert / a ++ * replace). The motivating case is raising the diff boundary for a strict ++ * container whose identifying child changed type (so a suggestion's old/new ++ * content lands as sibling blocks in the permissive grandparent instead of as ++ * schema-invalid siblings inside the strict node). Crucially, *what identifies ++ * a node* is schema-specific - e.g. "a `blockContainer` is identified by its ++ * first block-content child" is BlockNote's model, not the binding's - so that ++ * policy belongs in the integrator's predicate, not here. ++ * ++ * @type {YpmMatchNodes} ++ */ ++export const defaultMatchNodes: YpmMatchNodes; +export function deltaToPNode(d: ProsemirrorDelta, schema: import("prosemirror-model").Schema, dformat: delta.FormattingAttributes | null, attributedNodes?: AttributedNodesPredicate): Node; +export function docDiffToDelta(beforeDoc: Node, afterDoc: Node): delta.Delta<{ + name: string; @@ -495,11 +517,11 @@ index 0000000000000000000000000000000000000000..dfb00a847adcc5a1db01d557a8b0b056 \ No newline at end of file diff --git a/dist/src/sync-utils.d.ts.map b/dist/src/sync-utils.d.ts.map new file mode 100644 -index 0000000000000000000000000000000000000000..8d7883745029eee21f25288286021206007fd3ff +index 0000000000000000000000000000000000000000..97ba0c3b0bcaac4cc9c0fb69a56186697129c239 --- /dev/null +++ b/dist/src/sync-utils.d.ts.map @@ -0,0 +1 @@ -+{"version":3,"file":"sync-utils.d.ts","sourceRoot":"","sources":["../../src/sync-utils.js"],"names":[],"mappings":"AAsNA;;;;;;;GAOG;AACH,mCANW,IAAI,YACJ,CAAC,CAAC,IAAI,2BAEd;IAA4C,kBAAkB;CAC9D,GAAU,CAAC,CAAC,IAAI,CASlB;AAED;;;;;;;;;GASG;AACH,uCARW,CAAC,CAAC,IAAI,MACN,OAAO,mBAAmB,EAAE,WAAW,kEAE/C;IAA2C,kBAAkB;IACZ,oBAAoB,KAxIxB,CAAC,SAApC,OAAQ,YAAY,EAAE,WAAY,UACpC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,eAC9B,CAAC,KACC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAsID,eAAe;CACtD,GAAU,OAAO,mBAAmB,EAAE,WAAW,CAiBnD;AAED;;;;;GAKG;AACH,uCAJW,CAAC,CAAC,IAAI,MACN,OAAO,mBAAmB,EAAE,WAAW,GACtC,IAAI,CAIf;AAoYD;;;;;;;;;;;;;;;;;GAiBG;AACH,oCAJW,IAAI,mBACJ,MAAM,GACL,MAAM,EAAE,CAwBnB;AAED;;;;;GAKG;AACH,yCAJW,MAAM,EAAE,QACR,IAAI,GACH,MAAM,CAgCjB;AAzsBD;;;;;;;IAA4I;AAE5I;;;;;;;GAOG;AACH,gCAAiC,cAAc,CAAA;AAE/C;;;;;GAKG;AACH,qCAFU,wBAAwB,CAEe;AAS1C,wCAHI,MAAM,GACL,MAAM,CAKR;AAcH,iDANI,MAAM,UACN,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,mBAC1C,wBAAwB,UACxB,OAAO,mBAAmB,EAAE,MAAM,GACjC,MAAM,CAajB;AAgCM,4CALyC,CAAC,SAApC,OAAQ,YAAY,EAAE,WAAY,UACpC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,eAC9B,CAAC,GACC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAiC1C;AAOM,4CAHI,KAAK,CAAC,QAAQ,mCA4BL,gBAAgB,CACnC;AA0BM,wDAHI;IAAC,CAAC,GAAG,EAAC,MAAM,GAAE,GAAG,CAAA;CAAC,GAAC,IAAI,UACvB,OAAO,mBAAmB,EAAE,MAAM,sCAGwD;AAM9F,iCAHI,KAAK,CAAC,IAAI,CAAC,GACV,gBAAgB,CAW3B;AAgEM,+BAPI,IAAI,aACJ,MAAM,OAAC,iBACP,OAAO,GAGN,gBAAgB,CAoB3B;AAKM,gCAFI,IAAI;;;;;;;GAEwC;AAmEhD,kCAPI,OAAO,mBAAmB,EAAE,WAAW,KACvC,gBAAgB,UAChB,IAAI,YACJ;IAAE,CAAC,EAAE,MAAM,CAAA;CAAE,oBACb,wBAAwB,GACvB,OAAO,mBAAmB,EAAE,WAAW,CAuJlD;AASM,gCANI,gBAAgB,UAChB,OAAO,mBAAmB,EAAE,MAAM,WAClC,KAAK,CAAC,oBAAoB,GAAC,IAAI,oBAC/B,wBAAwB,GACvB,IAAI,CAkCf;AAMM,0CAHI,IAAI,YACJ,IAAI;;;;;;;GAMd;AAKM,8BAFI,WAAW;;;;;;;GAkBrB;AA+CM,kCAJI,OAAO,uBAAuB,EAAE,IAAI,aACpC,OAAO,mBAAmB,EAAE,IAAI,GAC/B,gBAAgB,CAQ3B;AAoGM,wCALI,IAAI,YACJ,MAAM,OACN,CAAC,CAAC,EAAC,KAAK,CAAC,eAAe,KAAG,GAAG,GAC7B,gBAAgB,CAa3B;;;;;iCArZY,KAAK,CAAC,aAAa;;;;;;;;;aAQlB,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAC,KAAK,CAAC,MAAM,CAAC;;;;aACvC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC;;qBA5VG,mBAAmB;mBAPtC,MAAM;uBAEF,YAAY;mBAIhB,aAAa"} ++{"version":3,"file":"sync-utils.d.ts","sourceRoot":"","sources":["../../src/sync-utils.js"],"names":[],"mappings":"AAwPA;;;;;;;GAOG;AACH,mCANW,IAAI,YACJ,CAAC,CAAC,IAAI,2BAEd;IAA4C,kBAAkB;CAC9D,GAAU,CAAC,CAAC,IAAI,CASlB;AAED;;;;;;;;;GASG;AACH,uCARW,CAAC,CAAC,IAAI,MACN,OAAO,mBAAmB,EAAE,WAAW,kEAE/C;IAA2C,kBAAkB;IACZ,oBAAoB,KAzKxB,CAAC,SAApC,OAAQ,YAAY,EAAE,WAAY,UACpC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,eAC9B,CAAC,KACC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAuKD,eAAe;CACtD,GAAU,OAAO,mBAAmB,EAAE,WAAW,CAiBnD;AAED;;;;;GAKG;AACH,uCAJW,CAAC,CAAC,IAAI,MACN,OAAO,mBAAmB,EAAE,WAAW,GACtC,IAAI,CAIf;AAmaD;;;;;;;;;;;;;;;;;GAiBG;AACH,oCAJW,IAAI,mBACJ,MAAM,GACL,MAAM,EAAE,CAwBnB;AAED;;;;;GAKG;AACH,yCAJW,MAAM,EAAE,QACR,IAAI,GACH,MAAM,CAgCjB;AAzwBD;;;;;;;IAA4I;AAE5I;;;;;;;GAOG;AACH,gCAAiC,cAAc,CAAA;AAE/C;;;;;GAKG;AACH,qCAFU,wBAAwB,CAEe;AAS1C,wCAHI,MAAM,GACL,MAAM,CAKR;AAcH,iDANI,MAAM,UACN,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,mBAC1C,wBAAwB,UACxB,OAAO,mBAAmB,EAAE,MAAM,GACjC,MAAM,CAajB;AAgCM,4CALyC,CAAC,SAApC,OAAQ,YAAY,EAAE,WAAY,UACpC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,eAC9B,CAAC,GACC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAiC1C;AAOM,4CAHI,KAAK,CAAC,QAAQ,mCA4BL,gBAAgB,CACnC;AAqBM,yCAHI,MAAM,GACL,MAAM,CAE2E;AAsCtF,wDAHI;IAAC,CAAC,GAAG,EAAC,MAAM,GAAE,GAAG,CAAA;CAAC,GAAC,IAAI,UACvB,OAAO,mBAAmB,EAAE,MAAM,sCAGwE;AAM9G,iCAHI,KAAK,CAAC,IAAI,CAAC,GACV,gBAAgB,CAW3B;AAgEM,+BAPI,IAAI,aACJ,MAAM,OAAC,iBACP,OAAO,GAGN,gBAAgB,CAoB3B;AAKM,gCAFI,IAAI;;;;;;;GAEwC;AAyEhD,kCAPI,OAAO,mBAAmB,EAAE,WAAW,KACvC,gBAAgB,UAChB,IAAI,YACJ;IAAE,CAAC,EAAE,MAAM,CAAA;CAAE,oBACb,wBAAwB,GACvB,OAAO,mBAAmB,EAAE,WAAW,CA6JlD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,gCAFU,aAAa,CAEqC;AASrD,gCANI,gBAAgB,UAChB,OAAO,mBAAmB,EAAE,MAAM,WAClC,KAAK,CAAC,oBAAoB,GAAC,IAAI,oBAC/B,wBAAwB,GACvB,IAAI,CAkCf;AAMM,0CAHI,IAAI,YACJ,IAAI;;;;;;;GAMd;AAKM,8BAFI,WAAW;;;;;;;GAkBrB;AA+CM,kCAJI,OAAO,uBAAuB,EAAE,IAAI,aACpC,OAAO,mBAAmB,EAAE,IAAI,GAC/B,gBAAgB,CAQ3B;AAoGM,wCALI,IAAI,YACJ,MAAM,OACN,CAAC,CAAC,EAAC,KAAK,CAAC,eAAe,KAAG,GAAG,GAC7B,gBAAgB,CAa3B;;;;;iCA9aY,KAAK,CAAC,aAAa;;;;;;;;;aAQlB,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAC,KAAK,CAAC,MAAM,CAAC;;;;aACvC,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC;;qBApYG,mBAAmB;mBAPtC,MAAM;uBAEF,YAAY;mBAIhB,aAAa"} \ No newline at end of file diff --git a/dist/src/undo-plugin.d.ts b/dist/src/undo-plugin.d.ts new file mode 100644 @@ -531,8 +553,21 @@ index 0000000000000000000000000000000000000000..665bb84203a88b35e2961e7221a31896 +{"version":3,"file":"undo-plugin.d.ts","sourceRoot":"","sources":["../../src/undo-plugin.js"],"names":[],"mappings":"AA8JO,yCAFI,OAAO,MAAM,EAAE,WAAW,2BAmFpC;;iBAzOa,OAAO,MAAM,EAAE,WAAW;aAC1B;QAAE,QAAQ,EAAE,OAAO,mBAAmB,EAAE,iBAAiB,CAAC;QAAC,cAAc,EAAE,UAAU,CAAC,OAAO,4BAA4B,CAAC,CAAC,gBAAgB,CAAC,CAAA;KAAE,GAAG,IAAI;gBACrJ,OAAO;gBACP,OAAO;kBACP,OAAO;;uBAVE,mBAAmB;6CACG,gBAAgB"} \ No newline at end of file diff --git a/dist/src/utils.d.ts b/dist/src/utils.d.ts -deleted file mode 100644 -index 9006a87dd42992dfe0aa0f7ab5298983deb3357a..0000000000000000000000000000000000000000 +index 9006a87dd42992dfe0aa0f7ab5298983deb3357a..ff01b0ef7739349d9e4fd67f5197020b9db4210b 100644 +--- a/dist/src/utils.d.ts ++++ b/dist/src/utils.d.ts +@@ -1 +1,2 @@ + export function hashOfJSON(json: any): string; ++//# sourceMappingURL=utils.d.ts.map +\ No newline at end of file +diff --git a/dist/src/utils.d.ts.map b/dist/src/utils.d.ts.map +new file mode 100644 +index 0000000000000000000000000000000000000000..0fd58606be14f84b708e556ed09017a0520da035 +--- /dev/null ++++ b/dist/src/utils.d.ts.map +@@ -0,0 +1 @@ ++{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.js"],"names":[],"mappings":"AAmBO,iCAHI,GAAG,GACF,MAAM,CAEmG"} +\ No newline at end of file diff --git a/dist/src/y-prosemirror.d.ts b/dist/src/y-prosemirror.d.ts deleted file mode 100644 index c1f9468c4c77434a1ad9f49227fb1274f5ae1915..0000000000000000000000000000000000000000 @@ -544,10 +579,10 @@ deleted file mode 100644 index 61b864629455150ac073bf6a9e5b7f6f7e9e5037..0000000000000000000000000000000000000000 diff --git a/global.d.ts b/global.d.ts new file mode 100644 -index 0000000000000000000000000000000000000000..f94ae8cdc4fe7400e1e7f5ad7f5cb7a1170519f5 +index 0000000000000000000000000000000000000000..8f3fa2a7d1c5288bb54e9d558d00c3b412139dfc --- /dev/null +++ b/global.d.ts -@@ -0,0 +1,21 @@ +@@ -0,0 +1,31 @@ + +declare type YType = import('@y/y').Type +declare type AttributionManager = import('@y/y').AbstractAttributionManager @@ -566,11 +601,21 @@ index 0000000000000000000000000000000000000000..f94ae8cdc4fe7400e1e7f5ad7f5cb7a1 + * node. Must be deterministic in `(nodeName, kinds)`. + */ +declare type AttributedNodesPredicate = (nodeName: string, kinds: { insert?: boolean, delete?: boolean, format?: boolean }) => boolean ++/** ++ * Node-pairing predicate for the PM<->Y diff (forwarded to `lib0/delta.diff`'s ++ * `matchNodes`). Given a removed node `a` and an inserted node `b` (content ++ * deltas with canonical names), returns whether they are the *same* node - i.e. ++ * diffed in place (descend/modify) vs. replaced (delete + insert). The default ++ * is name-equality; an integrator overrides it to raise the diff boundary for ++ * schema-specific reasons. The "what identifies a node" policy is the ++ * integrator's, not the binding's. ++ */ ++declare type YpmMatchNodes = (a: import('lib0/delta').DeltaAny, b: import('lib0/delta').DeltaAny) => boolean +declare type SyncPluginState = import('lib0/schema').Unwrap +declare type SyncPluginStateUpdate = import('lib0/schema').Unwrap +declare type ProsemirrorDelta = import('lib0/schema').Unwrap diff --git a/package.json b/package.json -index 8eaef6bf2b216933047f528e3c3b0aa469df45e7..258a3b18cc50c11181b70a716953fdb1708bf840 100644 +index 8eaef6bf2b216933047f528e3c3b0aa469df45e7..264aa040efa65d9934939b5df912fea6dd7708a2 100644 --- a/package.json +++ b/package.json @@ -2,10 +2,7 @@ @@ -611,7 +656,7 @@ index 8eaef6bf2b216933047f528e3c3b0aa469df45e7..258a3b18cc50c11181b70a716953fdb1 "homepage": "https://github.com/yjs/y-prosemirror#readme", "dependencies": { - "lib0": "^0.2.115-6" -+ "lib0": "^1.0.0-rc.13" ++ "lib0": "^1.0.0-rc.14" }, "peerDependencies": { - "@y/protocols": "^1.0.6-3", @@ -1144,7 +1189,7 @@ index 0000000000000000000000000000000000000000..79fa8f273361c11282e2c2df76c38895 + } + }) diff --git a/src/index.js b/src/index.js -index ac407e0c363309c970f3dbcbd66db00f9cd1656a..0c20333ce9f66f1a1e3e8e44da1ac4017bbba4cc 100644 +index ac407e0c363309c970f3dbcbd66db00f9cd1656a..3ac49220951d180ea85f5a7a3437d70fbae189b2 100644 --- a/src/index.js +++ b/src/index.js @@ -1,627 +1,7 @@ @@ -1778,7 +1823,7 @@ index ac407e0c363309c970f3dbcbd66db00f9cd1656a..0c20333ce9f66f1a1e3e8e44da1ac401 +export * from './sync-plugin.js' +export * from './keys.js' +export * from './positions.js' -+export { docToDelta, $prosemirrorDelta, defaultMapAttributionToMark } from './sync-utils.js' ++export { docToDelta, $prosemirrorDelta, defaultMapAttributionToMark, yattr2markname, pmToFragment, fragmentToPm } from './sync-utils.js' +export * from './commands.js' +export * from './undo-plugin.js' +export * from './cursor-plugin.js' @@ -2048,16 +2093,17 @@ index 0000000000000000000000000000000000000000..963ea708dbe0e92b2d43fc031243c2e7 +} diff --git a/src/sync-plugin.js b/src/sync-plugin.js new file mode 100644 -index 0000000000000000000000000000000000000000..079bc7e465f98612907d36adc9854054814dda91 +index 0000000000000000000000000000000000000000..5fd9fdd677c998301654e344d007af95506735c6 --- /dev/null +++ b/src/sync-plugin.js -@@ -0,0 +1,301 @@ +@@ -0,0 +1,316 @@ +import * as Y from '@y/y' +import { Plugin } from 'prosemirror-state' +import { + $prosemirrorDelta, + defaultAttributedNodes, + defaultMapAttributionToMark, ++ defaultMatchNodes, + deltaAttributionToFormat, + deltaToPSteps, + nodeToDelta @@ -2082,7 +2128,12 @@ index 0000000000000000000000000000000000000000..079bc7e465f98612907d36adc9854054 + * Predicate deciding which attributed nodes render under their + * `{nodeName}--attributed` variant. See {@link syncPlugin}. + */ -+ attributedNodes: /** @type {s.Schema} */ (s.$function) ++ attributedNodes: /** @type {s.Schema} */ (s.$function), ++ /** ++ * Node-pairing predicate for the PM->Y diff (`opts.matchNodes`). See ++ * {@link syncPlugin}. ++ */ ++ matchNodes: /** @type {s.Schema} */ (s.$function) +}) + +export const $syncPluginStateUpdate = s.$object({ @@ -2161,6 +2212,7 @@ index 0000000000000000000000000000000000000000..079bc7e465f98612907d36adc9854054 + * @param {Y.Doc} [opts.suggestionDoc] A {@link Y.Doc} to use for suggestion tracking + * @param {AttributionMapper} [opts.mapAttributionToMark] A function to map the {@link Y.Attribution} to a {@link import('prosemirror-model').Mark} - the mark names *must* be one of: `y-attributed-insert`, `y-attributed-delete`, `y-attributed-format`. No other mark names are permitted + * @param {AttributedNodesPredicate} [opts.attributedNodes] Optional predicate `(nodeName, kinds) => boolean`. When it returns `true` for an attributed node *and* a `{nodeName}--attributed` type exists in the schema, that node is rendered under the variant type (the `y-attributed-*` marks are still applied). `kinds` is `{ insert?, delete?, format? }`. The variant is a pure rendering concern - the canonical name is what is stored in the Y document. The predicate must be deterministic in `(nodeName, kinds)`. ++ * @param {YpmMatchNodes} [opts.matchNodes] Node-pairing predicate for the PM->Y diff (forwarded to `lib0/delta.diff`). Given a removed node `a` and an inserted node `b` (content deltas with canonical names), return whether they are the *same* node - i.e. diffed in place (descend/modify) vs. replaced (delete + insert). Defaults to name-equality. Override to raise the diff boundary at a strict node: report two same-named nodes as *different* when the child that identifies them changed, so a suggestion's old/new content lands as sibling blocks in the permissive grandparent instead of as schema-invalid siblings inside the strict node (e.g. BlockNote's `blockContainer`, content `blockContent blockGroup?`). What identifies a node is schema-specific, hence the integrator's to define. A plain text edit (same identity) still descends and merges normally. + * @returns {Plugin} + */ +export function syncPlugin (opts = {}) { @@ -2172,7 +2224,8 @@ index 0000000000000000000000000000000000000000..079bc7e465f98612907d36adc9854054 + ytype: null, + attributionManager: null, + attributionMapper: opts.mapAttributionToMark || defaultMapAttributionToMark, -+ attributedNodes: opts.attributedNodes || defaultAttributedNodes ++ attributedNodes: opts.attributedNodes || defaultAttributedNodes, ++ matchNodes: opts.matchNodes || defaultMatchNodes + }) + }, + apply: (tr, prevPluginState) => { @@ -2317,12 +2370,19 @@ index 0000000000000000000000000000000000000000..079bc7e465f98612907d36adc9854054 + const am = attributionManager || Y.noAttributionsManager + const mapper = pluginState.attributionMapper + const attributedNodes = pluginState.attributedNodes ++ const matchNodes = pluginState.matchNodes + const ycontent = deltaAttributionToFormat( + ytype.toDeltaDeep(am), + mapper + ).done() + const pcontent = nodeToDelta(view.state.doc, undefined, true).done() -+ const pmToYDiff = stripAttributionFormattingFromDelta(d.diff(ycontent, pcontent)) ++ // `matchNodes` raises the diff boundary at declared suggestion-boundary ++ // node types: a child-type change inside such a (strict) node becomes a ++ // whole-node replace, so its old/new content lands as sibling blocks in ++ // the permissive grandparent instead of as schema-invalid siblings ++ // inside the strict node. A no-op (name-equality) when no boundary nodes ++ // are configured. ++ const pmToYDiff = stripAttributionFormattingFromDelta(d.diff(ycontent, pcontent, matchNodes)) + if (!pmToYDiff.isEmpty()) { + /** @type {Y.Doc} */ (ytype.doc).transact(() => { + ytype.applyDelta(pmToYDiff, am) @@ -2333,7 +2393,7 @@ index 0000000000000000000000000000000000000000..079bc7e465f98612907d36adc9854054 + mapper + ).done() + const pcontentAfter = nodeToDelta(view.state.doc, undefined, true).done() -+ const pmReconcileDiff = d.diff(pcontentAfter, desiredPM) ++ const pmReconcileDiff = d.diff(pcontentAfter, desiredPM); + if (pmReconcileDiff.isEmpty()) return + const tr = view.state.tr + deltaToPSteps(tr, pmReconcileDiff, undefined, undefined, attributedNodes) @@ -2355,10 +2415,10 @@ index 0000000000000000000000000000000000000000..079bc7e465f98612907d36adc9854054 +} diff --git a/src/sync-utils.js b/src/sync-utils.js new file mode 100644 -index 0000000000000000000000000000000000000000..2234e5506a5341f39c80f389288823d887b38d28 +index 0000000000000000000000000000000000000000..cbea2444b0a7c4ddf2825af47fd95afaa6e4f7a4 --- /dev/null +++ b/src/sync-utils.js -@@ -0,0 +1,752 @@ +@@ -0,0 +1,817 @@ +import * as Y from '@y/y' +import * as array from 'lib0/array' +import * as delta from 'lib0/delta' @@ -2377,6 +2437,7 @@ index 0000000000000000000000000000000000000000..2234e5506a5341f39c80f389288823d8 + ReplaceAroundStep, + ReplaceStep +} from 'prosemirror-transform' ++import { hashOfJSON } from './utils.js' + +export const $prosemirrorDelta = delta.$delta({ name: s.$string, attrs: s.$record(s.$string, s.$any), text: true, recursiveChildren: true }) + @@ -2532,6 +2593,38 @@ index 0000000000000000000000000000000000000000..2234e5506a5341f39c80f389288823d8 +} + +/** ++ * Marks are stored as a flat `format` object keyed by mark name. Marks whose ++ * type does *not* exclude itself (declared with `excludes: ''`, e.g. a comment ++ * mark) may overlap on the same text span - several distinct instances coexist. ++ * Keying them all by the bare mark name would collide, so each overlapping mark ++ * gets a stable content-hash suffix (`name--`), keeping every instance on ++ * its own key. Self-excluding marks (strong/em/code/attribution marks) keep the ++ * bare name. `--<8 base64 chars>` is therefore a reserved suffix, symmetric to ++ * {@link ATTRIBUTED_SUFFIX} above. ++ */ ++const hashedMarkNameRegex = /(.*)(--[a-zA-Z0-9+/=]{8})$/ ++ ++/** ++ * Strip a hashed overlapping-mark suffix to recover the PM mark name. Identity ++ * for bare (non-hashed) names. ++ * ++ * @param {string} attrName ++ * @return {string} ++ */ ++export const yattr2markname = attrName => hashedMarkNameRegex.exec(attrName)?.[1] ?? attrName ++ ++/** ++ * Inverse of {@link yattr2markname}: the delta format key for a PM mark. ++ * ++ * @param {import('prosemirror-model').Mark} mark ++ * @return {string} ++ */ ++const markToYattrName = mark => ++ mark.type.excludes(mark.type) ++ ? mark.type.name ++ : `${mark.type.name}--${hashOfJSON(mark.toJSON())}` ++ ++/** + * @param {readonly import('prosemirror-model').Mark[]} marks + */ +const marksToFormattingAttributes = marks => { @@ -2541,7 +2634,7 @@ index 0000000000000000000000000000000000000000..2234e5506a5341f39c80f389288823d8 + */ + const formatting = {} + marks.forEach(mark => { -+ formatting[mark.type.name] = mark.attrs ++ formatting[markToYattrName(mark)] = mark.attrs + }) + return formatting +} @@ -2550,13 +2643,14 @@ index 0000000000000000000000000000000000000000..2234e5506a5341f39c80f389288823d8 + * Convert a delta `format` object to PM marks. `null` entries (which mean + * "this mark is absent / cleared") are filtered out - a custom attribution + * mapper may emit `null` for absent attribution kinds, and a fresh insert -+ * should not materialize a mark for them. ++ * should not materialize a mark for them. Hashed overlapping-mark keys are ++ * mapped back to their mark name via {@link yattr2markname}. + * + * @param {{[key:string]:any}|null} formatting + * @param {import('prosemirror-model').Schema} schema + */ +export const formattingAttributesToMarks = (formatting, schema) => -+ object.map(formatting ?? {}, (v, k) => v != null ? schema.mark(k, v) : null).filter(m => m != null) ++ object.map(formatting ?? {}, (v, k) => v != null ? schema.mark(yattr2markname(k), v) : null).filter(m => m != null) + +/** + * @param {Array} ns @@ -2679,11 +2773,15 @@ index 0000000000000000000000000000000000000000..2234e5506a5341f39c80f389288823d8 + if (node == null) return + let resultingMarks = node.marks + object.forEach(format ?? {}, (v, k) => { -+ const markType = schema.marks[k] ++ const markName = yattr2markname(k) ++ const markType = schema.marks[markName] + if (markType == null) return ++ // For overlapping marks, remove the specific instance carried by this ++ // (hashed) key rather than every mark of the type. ++ const mark = node.marks.find(m => markToYattrName(m) === k) + resultingMarks = v == null -+ ? markType.removeFromSet(resultingMarks) -+ : schema.mark(k, v).addToSet(resultingMarks) ++ ? (mark ?? markType).removeFromSet(resultingMarks) ++ : schema.mark(markName, v).addToSet(resultingMarks) + }) + const targetType = schema.nodes[ + attributedVariant(canonicalNodeName(node.type.name), marksToFormattingAttributes(resultingMarks), attributedNodes, schema) @@ -2692,10 +2790,12 @@ index 0000000000000000000000000000000000000000..2234e5506a5341f39c80f389288823d8 + tr.setNodeMarkup(pos, targetType, object.assign({ 'y-attributed': true }, node.attrs), resultingMarks) + } else { + object.forEach(format ?? {}, (v, k) => { ++ const markName = yattr2markname(k) + if (v == null) { -+ tr.removeNodeMark(pos, schema.marks[k]) ++ const mark = node.marks.find(m => markToYattrName(m) === k) ++ tr.removeNodeMark(pos, mark ?? schema.marks[markName]) + } else { -+ tr.addNodeMark(pos, schema.mark(k, v)) ++ tr.addNodeMark(pos, schema.mark(markName, v)) + } + }) + } @@ -2786,10 +2886,16 @@ index 0000000000000000000000000000000000000000..2234e5506a5341f39c80f389288823d8 + const from = currPos.i + const to = currPos.i + math.min(pc.nodeSize - nOffset, i) + object.forEach(op.format, (v, k) => { ++ const markName = yattr2markname(k) + if (v == null) { -+ tr.removeMark(from, to, schema.marks[k]) ++ // A format-remove carries no attrs, so match the specific ++ // instance on the current text node - sibling overlaps of the ++ // same type (e.g. another comment) must not be removed with it. ++ // Their relative array order is not significant (see CAVEATS). ++ const mark = pc.marks.find(m => markToYattrName(m) === k) ++ tr.removeMark(from, to, mark ?? schema.marks[markName]) + } else { -+ tr.addMark(from, to, schema.mark(k, v)) ++ tr.addMark(from, to, schema.mark(markName, v)) + } + }) + } @@ -2877,6 +2983,25 @@ index 0000000000000000000000000000000000000000..2234e5506a5341f39c80f389288823d8 +} + +/** ++ * Default node-pairing predicate for the PM->Y diff, forwarded to ++ * `lib0/delta.diff`'s `matchNodes`: two nodes are the *same* node (diffed in ++ * place) iff they share a name - the standard `delta.diff` behavior. ++ * ++ * Override it via `syncPlugin`'s `matchNodes` option to make the diff treat ++ * certain same-named nodes as *different* (a whole-node delete + insert / a ++ * replace). The motivating case is raising the diff boundary for a strict ++ * container whose identifying child changed type (so a suggestion's old/new ++ * content lands as sibling blocks in the permissive grandparent instead of as ++ * schema-invalid siblings inside the strict node). Crucially, *what identifies ++ * a node* is schema-specific - e.g. "a `blockContainer` is identified by its ++ * first block-content child" is BlockNote's model, not the binding's - so that ++ * policy belongs in the integrator's predicate, not here. ++ * ++ * @type {YpmMatchNodes} ++ */ ++export const defaultMatchNodes = (a, b) => a.name === b.name ++ ++/** + * @param {ProsemirrorDelta} d + * @param {import('prosemirror-model').Schema} schema + * @param {delta.FormattingAttributes|null} dformat @@ -2971,10 +3096,10 @@ index 0000000000000000000000000000000000000000..2234e5506a5341f39c80f389288823d8 + deltaModifyNodeAt(beforeDoc, step.pos, d => { d.retain(1, marksToFormattingAttributes([step.mark])) }) + ) + .if(RemoveMarkStep, (step, { beforeDoc }) => -+ deltaModifyNodeAt(beforeDoc, step.from, d => { d.retain(step.to - step.from, { [step.mark.type.name]: null }) }) ++ deltaModifyNodeAt(beforeDoc, step.from, d => { d.retain(step.to - step.from, { [markToYattrName(step.mark)]: null }) }) + ) + .if(RemoveNodeMarkStep, (step, { beforeDoc }) => -+ deltaModifyNodeAt(beforeDoc, step.pos, d => { d.retain(1, { [step.mark.type.name]: null }) }) ++ deltaModifyNodeAt(beforeDoc, step.pos, d => { d.retain(1, { [markToYattrName(step.mark)]: null }) }) + ) + .if(AttrStep, (step, { beforeDoc }) => + deltaModifyNodeAt(beforeDoc, step.pos, d => { d.modify(delta.create().setAttr(step.attr, step.value)) }) @@ -3358,8 +3483,44 @@ index 0000000000000000000000000000000000000000..70a7ae423be9bfd7a061984ce4ca74f4 + }) +} diff --git a/src/utils.js b/src/utils.js -deleted file mode 100644 -index f62b6a1abc732b9c13eb83fd667534173706273d..0000000000000000000000000000000000000000 +index f62b6a1abc732b9c13eb83fd667534173706273d..aa4e28a8060e11871f1548c840444de1e8a08ce9 100644 +--- a/src/utils.js ++++ b/src/utils.js +@@ -1,20 +1,20 @@ +-import * as sha256 from 'lib0/hash/sha256' ++import * as rabin from 'lib0/hash/rabin' + import * as buf from 'lib0/buffer' + + /** +- * Custom function to transform sha256 hash to N byte ++ * Compact, stable base64 tag of an arbitrary json-serializable value. It only ++ * needs to disambiguate overlapping marks of the same type (see `markToYattrName` ++ * in sync-utils.js), not resist attacks, so a cheap Rabin fingerprint is plenty. ++ * ++ * We use the *full* 4-byte (degree-32) fingerprint rather than truncating a ++ * wider one: a Rabin fingerprint propagates small input changes into its ++ * low-order bytes, so slicing the leading bytes off a degree-64 fingerprint ++ * collides for near-identical inputs (e.g. `{id:4}` vs `{id:5}`). The 4 bytes ++ * encode to 8 base64 chars - the length `hashedMarkNameRegex` expects - so ++ * documents written by older (sha256-based) versions still parse: the suffix is ++ * only ever stripped on read (by pattern), never recomputed. + * +- * @param {Uint8Array} digest +- */ +-const _convolute = digest => { +- const N = 6 +- for (let i = N; i < digest.length; i++) { +- digest[i % N] = digest[i % N] ^ digest[i] +- } +- return digest.slice(0, N) +-} +- +-/** + * @param {any} json ++ * @return {string} + */ +-export const hashOfJSON = (json) => buf.toBase64(_convolute(sha256.digest(buf.encodeAny(json)))) ++export const hashOfJSON = (json) => buf.toBase64(rabin.fingerprint(rabin.StandardIrreducible32, buf.encodeAny(json))) diff --git a/src/y-prosemirror.js b/src/y-prosemirror.js deleted file mode 100644 index bb072b6e31a0184a56d7873dcae647f0d5711559..0000000000000000000000000000000000000000 diff --git a/patches/@y__y@14.0.0-rc.16.patch b/patches/@y__y@14.0.0-rc.16.patch deleted file mode 100644 index 42e00d2080..0000000000 --- a/patches/@y__y@14.0.0-rc.16.patch +++ /dev/null @@ -1,193 +0,0 @@ -diff --git a/dist/src/utils/UndoManager.d.ts b/dist/src/utils/UndoManager.d.ts -index 2670b9688224b31267f9e16a21be73ae6b39af84..2f614bb70c302ee0b277f083ee6f1e15a0c73476 100644 ---- a/dist/src/utils/UndoManager.d.ts -+++ b/dist/src/utils/UndoManager.d.ts -@@ -20,7 +20,7 @@ export class StackItem { - * filter returns false, the type/item won't be deleted even it is in the - * undo/redo scope. - * @property {Set} [UndoManagerOptions.trackedOrigins=new Set([null])] -- * @property {boolean} [ignoreRemoteMapChanges] Experimental. By default, the UndoManager will never overwrite remote changes. Enable this property to enable overwriting remote changes on key-value changes (Y.Map, properties on Y.Xml, etc..). -+ * @property {boolean} [ignoreRemoteAttributeChanges] By default, the UndoManager will never overwrite remote changes. In some cases this might be the expected behavior. This property enables overwriting remote changes on attribute changes. (previously named `ignoreRemoteMapChanges`) - * @property {Doc} [doc] The document that this UndoManager operates on. Only needed if typeScope is empty. - */ - /** -@@ -52,7 +52,7 @@ export class UndoManager extends ObservableV2<{ - * @param {Doc|YType|Array} typeScope Limits the scope of the UndoManager. If this is set to a ydoc instance, all changes on that ydoc will be undone. If set to a specific type, only changes on that type or its children will be undone. Also accepts an array of types. - * @param {UndoManagerOptions} options - */ -- constructor(typeScope: Doc | YType | Array, { captureTimeout, captureTransaction, deleteFilter, trackedOrigins, ignoreRemoteMapChanges, doc }?: UndoManagerOptions); -+ constructor(typeScope: Doc | YType | Array, { captureTimeout, captureTransaction, deleteFilter, trackedOrigins, ignoreRemoteAttributeChanges, doc }?: UndoManagerOptions); - /** - * @type {Array} - */ -@@ -83,7 +83,7 @@ export class UndoManager extends ObservableV2<{ - */ - currStackItem: StackItem | null; - lastChange: number; -- ignoreRemoteMapChanges: boolean; -+ ignoreRemoteAttributeChanges: boolean; - captureTimeout: number; - /** - * @param {Transaction} transaction -@@ -151,7 +151,7 @@ export class UndoManager extends ObservableV2<{ - canRedo(): boolean; - } - export function undoContentIds(ydoc: Doc, contentIds: ContentIds, opts?: UndoManagerOptions): void; --export function redoItem(transaction: Transaction, item: Item, redoitems: Set, itemsToDelete: IdSet, ignoreRemoteMapChanges: boolean, um: import("../utils/UndoManager.js").UndoManager): Item | null; -+export function redoItem(transaction: Transaction, item: Item, redoitems: Set, itemsToDelete: IdSet, ignoreRemoteAttributeChanges: boolean, um: import("../utils/UndoManager.js").UndoManager): Item | null; - export function keepItem(item: Item | null, keep: boolean): void; - export type UndoManagerOptions = { - captureTimeout?: number | undefined; -@@ -168,9 +168,9 @@ export type UndoManagerOptions = { - deleteFilter?: ((arg0: Item) => boolean) | undefined; - trackedOrigins?: Set | undefined; - /** -- * Experimental. By default, the UndoManager will never overwrite remote changes. Enable this property to enable overwriting remote changes on key-value changes (Y.Map, properties on Y.Xml, etc..). -+ * By default, the UndoManager will never overwrite remote changes. In some cases this might be the expected behavior. This property enables overwriting remote changes on attribute changes. (previously named `ignoreRemoteMapChanges`) - */ -- ignoreRemoteMapChanges?: boolean | undefined; -+ ignoreRemoteAttributeChanges?: boolean | undefined; - /** - * The document that this UndoManager operates on. Only needed if typeScope is empty. - */ -diff --git a/dist/src/utils/UndoManager.d.ts.map b/dist/src/utils/UndoManager.d.ts.map -index 597c791905316e578275c84f1a9265ffa78e092a..7937771c7c931d9ffd2b2761cc2b33b51cb4bc8c 100644 ---- a/dist/src/utils/UndoManager.d.ts.map -+++ b/dist/src/utils/UndoManager.d.ts.map -@@ -1 +1 @@ --{"version":3,"file":"UndoManager.d.ts","sourceRoot":"","sources":["../../../src/utils/UndoManager.js"],"names":[],"mappings":"AAeA;IACE;;;OAGG;IACH,wBAHW,KAAK,aACL,KAAK,EASf;IANC,kCAAyB;IACzB,kCAAwB;IACxB;;OAEG;IACH,oBAAqB;CAExB;AAgGD;;;;;;;;;;;GAWG;AAEH;;;;;;GAMG;AAEH;;;;;;;;GAQG;AACH;wBAF8C,CAAS,IAAc,EAAd,cAAc,EAAE,IAAW,EAAX,WAAW,KAAE,IAAI;yBAAuB,CAAS,IAAc,EAAd,cAAc,EAAE,IAAW,EAAX,WAAW,KAAE,IAAI;qBAAmB,CAAS,IAAwD,EAAxD;QAAE,gBAAgB,EAAE,OAAO,CAAC;QAAC,gBAAgB,EAAE,OAAO,CAAA;KAAE,KAAE,IAAI;0BAAwB,CAAS,IAAc,EAAd,cAAc,EAAE,IAAW,EAAX,WAAW,KAAE,IAAI;;IAGnT;;;OAGG;IACH,uBAHW,GAAG,GAAC,KAAK,GAAC,KAAK,CAAC,KAAK,CAAC,sGACtB,kBAAkB,EAsG5B;IA3FC;;OAEG;IACH,OAFU,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,CAEb;IACf,SAAc;IAEd,qBA9CmB,IAAI,KAAE,OAAO,CA8CA;IAEhC,yBAAoC;IACpC,2BAlDmB,WAAW,KAAE,OAAO,CAkDK;IAC5C;;OAEG;IACH,WAFU,KAAK,CAAC,SAAS,CAAC,CAEP;IACnB;;OAEG;IACH,WAFU,KAAK,CAAC,SAAS,CAAC,CAEP;IACnB;;;;OAIG;IACH,SAFU,OAAO,CAEG;IACpB,iBAAoB;IACpB;;;;OAIG;IACH,eAFU,SAAS,GAAC,IAAI,CAEC;IACzB,mBAAmB;IACnB,gCAAoD;IACpD,uBAAoC;IACpC;;OAEG;IACH,uCAFW,WAAW,UAmDrB;IAOH;;;;OAIG;IACH,mBAFW,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,KAAK,GAAG,GAAG,QAY1C;IAED;;OAEG;IACH,yBAFW,GAAG,QAIb;IAED;;OAEG;IACH,4BAFW,GAAG,QAIb;IAED,gEAcC;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,sBAEC;IAED;;;;OAIG;IACH,QAFY,SAAS,OAAC,CAWrB;IAED;;;;OAIG;IACH,QAFY,SAAS,OAAC,CAWrB;IAED;;;;OAIG;IACH,WAFY,OAAO,CAIlB;IAED;;;;OAIG;IACH,WAFY,OAAO,CAIlB;CAOF;AAWM,qCAJI,GAAG,cACH,UAAU,SACV,kBAAkB,QAM5B;AAsBM,sCAXI,WAAW,QACX,IAAI,aACJ,GAAG,CAAC,IAAI,CAAC,iBACT,KAAK,0BACL,OAAO,MACP,OAAO,yBAAyB,EAAE,WAAW,GAE5C,IAAI,GAAC,IAAI,CAyGpB;AAWM,+BAHI,IAAI,GAAC,IAAI,QACT,OAAO,QAOjB;;;;;;iCA9ZsB,WAAW,KAAE,OAAO;;;;;;;2BACpB,IAAI,KAAE,OAAO;;;;;;;;;;;;eAWtB,SAAS;YACT,GAAG;UACH,MAAM,GAAC,MAAM;wBACb,GAAG,CAAC,KAAK,EAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;;6BA3Id,iBAAiB;sBAUxB,aAAa;oBADf,UAAU;qBANK,oBAAoB"} -\ No newline at end of file -+{"version":3,"file":"UndoManager.d.ts","sourceRoot":"","sources":["../../../src/utils/UndoManager.js"],"names":[],"mappings":"AAeA;IACE;;;OAGG;IACH,wBAHW,KAAK,aACL,KAAK,EASf;IANC,kCAAyB;IACzB,kCAAwB;IACxB;;OAEG;IACH,oBAAqB;CAExB;AAgGD;;;;;;;;;;;GAWG;AAEH;;;;;;GAMG;AAEH;;;;;;;;GAQG;AACH;wBAF8C,CAAS,IAAc,EAAd,cAAc,EAAE,IAAW,EAAX,WAAW,KAAE,IAAI;yBAAuB,CAAS,IAAc,EAAd,cAAc,EAAE,IAAW,EAAX,WAAW,KAAE,IAAI;qBAAmB,CAAS,IAAwD,EAAxD;QAAE,gBAAgB,EAAE,OAAO,CAAC;QAAC,gBAAgB,EAAE,OAAO,CAAA;KAAE,KAAE,IAAI;0BAAwB,CAAS,IAAc,EAAd,cAAc,EAAE,IAAW,EAAX,WAAW,KAAE,IAAI;;IAGnT;;;OAGG;IACH,uBAHW,GAAG,GAAC,KAAK,GAAC,KAAK,CAAC,KAAK,CAAC,4GACtB,kBAAkB,EAsG5B;IA3FC;;OAEG;IACH,OAFU,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,CAEb;IACf,SAAc;IAEd,qBA9CmB,IAAI,KAAE,OAAO,CA8CA;IAEhC,yBAAoC;IACpC,2BAlDmB,WAAW,KAAE,OAAO,CAkDK;IAC5C;;OAEG;IACH,WAFU,KAAK,CAAC,SAAS,CAAC,CAEP;IACnB;;OAEG;IACH,WAFU,KAAK,CAAC,SAAS,CAAC,CAEP;IACnB;;;;OAIG;IACH,SAFU,OAAO,CAEG;IACpB,iBAAoB;IACpB;;;;OAIG;IACH,eAFU,SAAS,GAAC,IAAI,CAEC;IACzB,mBAAmB;IACnB,sCAAgE;IAChE,uBAAoC;IACpC;;OAEG;IACH,uCAFW,WAAW,UAmDrB;IAOH;;;;OAIG;IACH,mBAFW,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,KAAK,GAAG,GAAG,QAY1C;IAED;;OAEG;IACH,yBAFW,GAAG,QAIb;IAED;;OAEG;IACH,4BAFW,GAAG,QAIb;IAED,gEAcC;IAED;;;;;;;;;;;;;;;;;;;OAmBG;IACH,sBAEC;IAED;;;;OAIG;IACH,QAFY,SAAS,OAAC,CAWrB;IAED;;;;OAIG;IACH,QAFY,SAAS,OAAC,CAWrB;IAED;;;;OAIG;IACH,WAFY,OAAO,CAIlB;IAED;;;;OAIG;IACH,WAFY,OAAO,CAIlB;CAOF;AAWM,qCAJI,GAAG,cACH,UAAU,SACV,kBAAkB,QAM5B;AAsBM,sCAXI,WAAW,QACX,IAAI,aACJ,GAAG,CAAC,IAAI,CAAC,iBACT,KAAK,gCACL,OAAO,MACP,OAAO,yBAAyB,EAAE,WAAW,GAE5C,IAAI,GAAC,IAAI,CA4GpB;AAWM,+BAHI,IAAI,GAAC,IAAI,QACT,OAAO,QAOjB;;;;;;iCAjasB,WAAW,KAAE,OAAO;;;;;;;2BACpB,IAAI,KAAE,OAAO;;;;;;;;;;;;eAWtB,SAAS;YACT,GAAG;UACH,MAAM,GAAC,MAAM;wBACb,GAAG,CAAC,KAAK,EAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;;6BA3Id,iBAAiB;sBAUxB,aAAa;oBADf,UAAU;qBANK,oBAAoB"} -\ No newline at end of file -diff --git a/dist/src/ytype.d.ts.map b/dist/src/ytype.d.ts.map -index 61397c8530690c01be91a97afa4007338ca8060e..608ab7ab770d86eba126fc306594eee2bce5cc72 100644 ---- a/dist/src/ytype.d.ts.map -+++ b/dist/src/ytype.d.ts.map -@@ -1 +1 @@ --{"version":3,"file":"ytype.d.ts","sourceRoot":"","sources":["../../src/ytype.js"],"names":[],"mappings":"AA4CO,4CAAiH;AAUjH,6DAJI,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,OAAC,WAC7B,OAAO,GACN,WAAW,OAAC,CAgCvB;AAWD;IACE;;;;;;OAMG;IACH,kBANW,IAAI,GAAC,IAAI,SACT,IAAI,GAAC,IAAI,SACT,MAAM,qBACN,GAAG,CAAC,MAAM,EAAC,GAAG,CAAC,MACf,0BAA0B,EAQpC;IALC,kBAAgB;IAChB,mBAAkB;IAClB,cAAkB;IAClB,oCAA0C;IAC1C,gFAAY;IAGd;;OAEG;IACH,gBAgBC;IAED;;;;;;;OAOG;IACH,wBAPW,WAAW,UACX,KAAK,UACL,MAAM;;aA4EhB;CACF;AAqHM,2CATI,WAAW,UACX,KAAK,WACL,oBAAoB,WACpB,OAAO,mBAAmB,EAAE,eAAe;;SA0BrD;AASM,iDANI,WAAW,UACX,KAAK,WACL,oBAAoB,UACpB,KAAK,CAAC,GAAG,CAAC,GAAC,MAAM;;SA0B3B;AAWM,wCARI,WAAW,WACX,oBAAoB,UACpB,MAAM,GACL,oBAAoB,CAkD/B;AAED;IACE;;;OAGG;IACH,eAHW,IAAI,SACJ,MAAM,EAOhB;IAHC,QAAU;IACV,cAAkB;IAClB,kBAA8C;CAEjD;AAqDM,mCAHI,KAAK,SACL,MAAM,4BAgDhB;AAWM,kDAJI,KAAK,CAAC,iBAAiB,CAAC,SACxB,MAAM,OACN,MAAM,QAiChB;AAQM,mCAHI,KAAK,GACJ,KAAK,CAAC,IAAI,CAAC,CAWtB;AAUM,wCAJI,KAAK,eACL,WAAW,SACV,MAAM,CAAC,GAAG,CAAC,QActB;AAED;;;GAGG;AACH,mBAFgC,KAAK,SAAvB,KAAK,CAAC,SAAU;IA2D5B;;;;OAIG;IACH,YAJ+B,EAAE,SAAnB,KAAK,CAAC,SAAU,KACnB,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GACd,KAAK,CAAC,EAAE,CAAC,CAMpB;IAjED;;OAEG;IACH,mBAFW,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,OAAC,EAqDxC;IAlDC;;OAEG;IACH,MAFU,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAEwB;IAC/D;;OAEG;IACH,OAFU,IAAI,GAAC,IAAI,CAEF;IACjB;;OAEG;IACH,MAFU,GAAG,CAAC,MAAM,EAAC,IAAI,CAAC,CAEL;IACrB;;OAEG;IACH,QAFU,IAAI,GAAC,IAAI,CAED;IAClB;;OAEG;IACH,KAFU,GAAG,GAAC,IAAI,CAEH;IACf,gBAAgB;IAChB;;;OAGG;IACH,KAFU,YAAY,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAC,WAAW,CAAC,CAEhC;IAC/B;;;OAGG;IACH,MAFU,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,EAAC,WAAW,CAAC,CAEjB;IAChC;;OAEG;IACH,eAFU,IAAI,GAAG,KAAK,CAAC,iBAAiB,CAAC,CAEhB;IACzB;;;OAGG;IACH,iBAAqE;IACrE,uBAA8E;IAK9E;;;OAGG;IACH,wBAA2B;IAc7B,qBAGC;IAED;;;OAGG;IACH,cAFU,KAAK,CAAC,YAAY,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAIhD;IAED;;OAEG;IACH,cAFY,KAAK,CAAC,GAAG,CAAC,OAAC,CAItB;IAED;;;;;;;;;OASG;IACH,cAHW,GAAG,QACH,IAAI,GAAC,IAAI,QASnB;IAFG,aAAmB;IAIvB;;OAEG;IACH,SAFY,KAAK,CAAC,KAAK,CAAC,CAMvB;IAED;;;;;;OAMG;IACH,2BAHW,WAAW,cACX,GAAG,CAAC,IAAI,GAAC,MAAM,CAAC,QAY1B;IAED;;;;;;OAMG;IACH,QAJ8E,CAAC,SAAlE,CAAE,MAAM,EAAE,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,WAAW,KAAK,IAAK,KAClE,CAAC,GACA,CAAC,CAKZ;IAED;;;;;;OAMG;IACH,YAJwD,CAAC,SAA5C,CAAU,IAAa,EAAb,MAAM,CAAC,KAAK,CAAC,EAAC,IAAW,EAAX,WAAW,KAAE,IAAK,KAC5C,CAAC,GACA,CAAC,CAKZ;IAED;;;;OAIG;IACH,aAFW,CAAC,IAAI,EAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAC,EAAE,EAAC,WAAW,KAAG,IAAI,QAIjE;IAED;;;;OAIG;IACH,iBAFW,CAAS,IAAa,EAAb,MAAM,CAAC,KAAK,CAAC,EAAC,IAAW,EAAX,WAAW,KAAE,IAAI,QAIlD;IAED;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,eAdwB,IAAI,SAAf,OAAS,eAEX,0BAA0B,SAElC;QAAsB,aAAa;QACZ,aAAa;QACb,aAAa;QACd,YAAY;QACc,QAAQ;QACpC,IAAI;KACxB,GAAS,IAAI,SAAS,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAkO7F;IAED;;;;;;OAMG;IACH,iBAHW,0BAA0B,GACzB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAI7B;IAED;;;;;;;OAOG;IACH,qBALW,KAAK,CAAC,QAAQ,OACd,0BAA0B,QA8CpC;IAED;;;;;;OAMG;IACH,SAFY,KAAK,CAAC,KAAK,CAAC,CAMvB;IAED;;OAEG;IACH,mBAMC;IAED;;;;;;OAMG;IACH,iCAJW,MAAM,QAMhB;IAED;;;;;;;;;;;OAWG;IACH,eAToE,GAAG,SAAzD,OAAO,CAAC,MAAM,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAC,MAAM,CAAE,EAChB,GAAG,SAAxC,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,GAAG,CAAE,iBAEvC,GAAG,kBACH,GAAG,GACF,GAAG,CAOd;IAED;;;;;;;OAOG;IACH,eAL2E,GAAG,SAAhE,OAAO,CAAC,MAAM,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAC,MAAM,GAAC,MAAM,CAAE,iBAC/D,GAAG,GACF,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAC,SAAS,CAKxD;IAED;;;;;;;OAOG;IACH,8BALW,MAAM,GACL,OAAO,CAMlB;IAED;;;;;;;OAOG;IACH,2BALW,QAAQ,GACP,GAAG,GAAG,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAC,CAMjH;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,cAJW,MAAM,WACN,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,GAAC,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,WACtE,KAAK,CAAC,oBAAoB,QAIpC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,cALW,MAAM,UACN,MAAM,WACN,KAAK,CAAC,oBAAoB,QAKpC;IAED;;;;;;OAMG;IACH,cAJW,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,GAAC,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,QAMhF;IAED;;;;OAIG;IACH,iBAFW,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,QAIvC;IAED;;;;;OAKG;IACH,cAHW,MAAM,WACN,MAAM,QAIhB;IAED;;;;;OAKG;IACH,WAHW,MAAM,GACL,KAAK,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAI5C;IAED;;;;;;;OAOG;IACH,cAJW,MAAM,QACN,MAAM,GACL,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAInD;IAED;;;;;;OAMG;IACH,WAFY,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAkBnF;IAED;;;OAGG;IACH,UAFY;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE;YAAE,CAAC,CAAC,EAAC,MAAM,GAAC,MAAM,GAAG,GAAG,CAAA;SAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAA;KAAG,CA0BxF;IAED;;;OAGG;IACH,wBAFG;QAAuB,QAAQ;KACjC,UAqBA;IAED;;;;;;;;OAQG;IACH,IALa,CAAC,KACH,CAAC,KAAK,EAAC,KAAK,CAAC,oBAAoB,CAAC,KAAK,CAAC,GAAC,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAC,KAAK,EAAC,MAAM,KAAG,CAAC,GACtF,KAAK,CAAC,CAAC,CAAC,CAKnB;IAED;;;;OAIG;IACH,WAFW,CAAC,KAAK,EAAC,KAAK,CAAC,oBAAoB,CAAC,KAAK,CAAC,GAAC,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAC,KAAK,EAAC,MAAM,KAAG,GAAG,QAInG;IAED;;;;OAIG;IACH,eAFW,CAAC,GAAG,EAAC,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAC,GAAG,EAAC,OAAO,CAAC,MAAM,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAC,MAAM,CAAC,EAAC,KAAK,EAAC,IAAI,KAAG,GAAG,QAQ5H;IAED;;;;OAIG;IACH,YAFY,gBAAgB,CAAC,OAAO,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,CAIpF;IAED;;;;OAIG;IACH,cAFY,gBAAgB,CAAC,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAIhE;IAED;;;;OAIG;IACH,eAFY,gBAAgB,CAAC,GAAG,CAAC,IAAI,MAAM,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAC,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAE,CAAC,GAAG,CAAC,CAAC,CAIxH;IAED;;;;OAIG;IACH,gBAFY,MAAM,CAIjB;IASD;;;;;;;;;OASG;IACH,gBAFW,eAAe,GAAG,eAAe,QAW3C;IA1BD;;OAEG;IACH,oCAFW,IAAI,WAId;CAsBF;AAOM,uBAJ+C,KAAK,SAA9C,OAAQ,YAAY,EAAE,iBAAkB,UAC1C,KAAK,GACJ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,YAAY,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAElB;AACpD,6CAA6C;AAMtC,gDAHI,WAAW,SACX,KAAK,uCAiBf;AAOM,8BAJI,GAAG,KACH,GAAG,GACF,OAAO,CAEgH;AAyB5H,oCARI,KAAK,CAAC,GAAG,CAAC,SACV,MAAM,OACN,MAAM,GACL,KAAK,CAAC,GAAG,CAAC,CAgCrB;AAYM,kCAPI,KAAK,SACL,MAAM,GACL,GAAG,CAqBd;AAaM,yDARI,WAAW,UACX,KAAK,iBACL,IAAI,OAAC,WACL,KAAK,CAAC,MAAM,CAAC,QA4DvB;AAaM,oDARI,WAAW,UACX,KAAK,SACL,MAAM,WACN,KAAK,CAAC;QAAO,MAAM,GAAC,GAAG;CAAC,GAAC,KAAK,CAAC,GAAG,CAAC,GAAC,MAAM,GAAC,IAAI,GAAC,MAAM,GAAC,UAAU,CAAC,QA4C5E;AAaM,kDAPI,WAAW,UACX,KAAK,WACL,KAAK,CAAC;QAAO,MAAM,GAAC,GAAG;CAAC,GAAC,KAAK,CAAC,GAAG,CAAC,GAAC,MAAM,GAAC,IAAI,GAAC,MAAM,GAAC,UAAU,CAAC,QAe5E;AAWM,4CARI,WAAW,UACX,KAAK,SACL,MAAM,UACN,MAAM,QAyChB;AAYM,2CAPI,WAAW,UACX,KAAK,OACL,MAAM,QAUhB;AAWM,wCARI,WAAW,UACX,KAAK,OACL,MAAM,SACN,MAAM,QAqChB;AAUM,mCAPI,KAAK,CAAC,GAAG,CAAC,OACV,MAAM,GACL;QAAO,MAAM,GAAC,GAAG;CAAC,GAAC,MAAM,GAAC,IAAI,GAAC,KAAK,CAAC,GAAG,CAAC,GAAC,MAAM,GAAC,UAAU,GAAC,KAAK,CAAC,GAAG,CAAC,GAAC,SAAS,CAS3F;AASM,sCANI,KAAK,CAAC,GAAG,CAAC;;;;EAkBpB;AA0BM,gCAf8B,SAAS,SAAhC,KAAK,CAAC,eAAgB,KACzB,SAAS,UACT,KAAK,iBACL,GAAG,CAAC,MAAM,GAAC,IAAI,CAAC,OAAC,MACjB,0BAA0B,QAC1B,OAAO,aACP,GAAG,CAAC,KAAK,CAAC,GAAC,GAAG,CAAC,KAAK,EAAC,GAAG,CAAC,GAAC,IAAI,iBAC9B,KAAK,OAAC,kBACN,KAAK,OAAC,SACN,GAAG,YACH,GAAG,QA8Cb;AAUM,mCAPI,KAAK,CAAC,GAAG,CAAC,OACV,MAAM,GACL,OAAO,CASlB;AASM,gCANI,IAAI,YACJ,QAAQ,GAAC,SAAS,WAO+F;AAWrH,2CARI,KAAK,CAAC,GAAG,CAAC,OACV,MAAM,YACN,QAAQ,GACP;QAAO,MAAM,GAAC,GAAG;CAAC,GAAC,MAAM,GAAC,IAAI,GAAC,KAAK,CAAC,GAAG,CAAC,GAAC,MAAM,GAAC,UAAU,GAAC,KAAK,CAAC,GAAG,CAAC,GAAC,SAAS,CAW3F;AAUM,8CAPI,KAAK,CAAC,GAAG,CAAC,YACV,QAAQ;;;;EAwBlB;AASM,wCANI,KAAK,CAAC,GAAG,CAAC,GAAG;IAAE,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;CAAE,GACvC,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAQvC;AAQM,yCAHI,eAAe,GAAG,eAAe,GAChC,WAAW,CAEsD;AAQtE,2CAHI,eAAe,GAAG,eAAe,GAChC,aAAa,CAE0D;AAQ5E,yCAHI,eAAe,GAAG,eAAe,GAChC,WAAW,CActB;AAMM,2CAHI,eAAe,GAAG,eAAe,GAChC,aAAa,CAE2E;AAQ7F,0CAHI,eAAe,GAAG,eAAe,GAChC,YAAY,CAEuD;AAQxE,wCAHI,eAAe,GAAG,eAAe,GAChC,UAAU,CAE0E;AAMzF,wCAHI,eAAe,GAAG,eAAe,GAChC,UAAU,CASrB;AAMM,2CAHI,eAAe,GAAG,eAAe,GAChC,aAAa,CAEuD;AAQzE,4CAHI,eAAe,GAAG,eAAe,GAChC,cAAc,CAEwD;AAElF;;;;GAIG;AACH,0BAFU,KAAK,CAAC,CAAS,IAAiC,EAAjC,eAAe,GAAG,eAAe,KAAE,eAAe,CAAC,CAc3E;AAMM,yCAHI,eAAe,GAAG,eAAe,QACjC,MAAM,+CAE0E;AASpF,mCANI,eAAe,GAAG,eAAe,GAChC,KAAK,CAUhB;qBAvkEY;QAAO,MAAM,GAAC,GAAG;CAAC,GAAC,KAAK,CAAC,GAAG,CAAC,GAAC,MAAM,GAAC,IAAI,GAAC,MAAM,GAAC,UAAU,YAAQ,KAAK,CAAC,GAAG,CAAC;kCA48C3D,KAAK,SAAtB,KAAK,CAAC,SAAU,IACjB,KAAK,CAAC,kBAAkB,CAAC,KAAK,EAAE;IACtC,KAAK,EAAE,GAAG,CAAC,IAAI,MAAM,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAE,CAAC;IACxG,QAAQ,EAAE,YAAY,CAAC,KAAK,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAA;CAC1D,CAAC;yBAKY,IAAI,oBACV,OAAO,CAAC,IAAI,EAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,KAAK,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,OAAO,SAAS,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC;qBAj+C7J,mBAAmB;uBAOH,mBAAmB;uBAhCnB,YAAY;wBASX,aAAa;mBADlB,aAAa;4BAiBzB,mBAAmB;8BAAnB,mBAAmB;4BAAnB,mBAAmB;8BAAnB,mBAAmB;6BAAnB,mBAAmB;2BAAnB,mBAAmB;2BAAnB,mBAAmB;8BAAnB,mBAAmB;+BAAnB,mBAAmB"} -\ No newline at end of file -+{"version":3,"file":"ytype.d.ts","sourceRoot":"","sources":["../../src/ytype.js"],"names":[],"mappings":"AA4CO,4CAAiH;AAUjH,6DAJI,KAAK,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,OAAC,WAC7B,OAAO,GACN,WAAW,OAAC,CAgCvB;AAWD;IACE;;;;;;OAMG;IACH,kBANW,IAAI,GAAC,IAAI,SACT,IAAI,GAAC,IAAI,SACT,MAAM,qBACN,GAAG,CAAC,MAAM,EAAC,GAAG,CAAC,MACf,0BAA0B,EAQpC;IALC,kBAAgB;IAChB,mBAAkB;IAClB,cAAkB;IAClB,oCAA0C;IAC1C,gFAAY;IAGd;;OAEG;IACH,gBAgBC;IAED;;;;;;;OAOG;IACH,wBAPW,WAAW,UACX,KAAK,UACL,MAAM;;aA4EhB;CACF;AAqHM,2CATI,WAAW,UACX,KAAK,WACL,oBAAoB,WACpB,OAAO,mBAAmB,EAAE,eAAe;;SA0BrD;AASM,iDANI,WAAW,UACX,KAAK,WACL,oBAAoB,UACpB,KAAK,CAAC,GAAG,CAAC,GAAC,MAAM;;SA0B3B;AAWM,wCARI,WAAW,WACX,oBAAoB,UACpB,MAAM,GACL,oBAAoB,CAkD/B;AAED;IACE;;;OAGG;IACH,eAHW,IAAI,SACJ,MAAM,EAOhB;IAHC,QAAU;IACV,cAAkB;IAClB,kBAA8C;CAEjD;AAqDM,mCAHI,KAAK,SACL,MAAM,4BAgDhB;AAWM,kDAJI,KAAK,CAAC,iBAAiB,CAAC,SACxB,MAAM,OACN,MAAM,QAiChB;AAQM,mCAHI,KAAK,GACJ,KAAK,CAAC,IAAI,CAAC,CAWtB;AAUM,wCAJI,KAAK,eACL,WAAW,SACV,MAAM,CAAC,GAAG,CAAC,QActB;AAED;;;GAGG;AACH,mBAFgC,KAAK,SAAvB,KAAK,CAAC,SAAU;IA2D5B;;;;OAIG;IACH,YAJ+B,EAAE,SAAnB,KAAK,CAAC,SAAU,KACnB,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,GACd,KAAK,CAAC,EAAE,CAAC,CAMpB;IAjED;;OAEG;IACH,mBAFW,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,OAAC,EAqDxC;IAlDC;;OAEG;IACH,MAFU,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAEwB;IAC/D;;OAEG;IACH,OAFU,IAAI,GAAC,IAAI,CAEF;IACjB;;OAEG;IACH,MAFU,GAAG,CAAC,MAAM,EAAC,IAAI,CAAC,CAEL;IACrB;;OAEG;IACH,QAFU,IAAI,GAAC,IAAI,CAED;IAClB;;OAEG;IACH,KAFU,GAAG,GAAC,IAAI,CAEH;IACf,gBAAgB;IAChB;;;OAGG;IACH,KAFU,YAAY,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAC,WAAW,CAAC,CAEhC;IAC/B;;;OAGG;IACH,MAFU,YAAY,CAAC,MAAM,CAAC,KAAK,CAAC,EAAC,WAAW,CAAC,CAEjB;IAChC;;OAEG;IACH,eAFU,IAAI,GAAG,KAAK,CAAC,iBAAiB,CAAC,CAEhB;IACzB;;;OAGG;IACH,iBAAqE;IACrE,uBAA8E;IAK9E;;;OAGG;IACH,wBAA2B;IAc7B,qBAGC;IAED;;;OAGG;IACH,cAFU,KAAK,CAAC,YAAY,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAIhD;IAED;;OAEG;IACH,cAFY,KAAK,CAAC,GAAG,CAAC,OAAC,CAItB;IAED;;;;;;;;;OASG;IACH,cAHW,GAAG,QACH,IAAI,GAAC,IAAI,QASnB;IAFG,aAAmB;IAIvB;;OAEG;IACH,SAFY,KAAK,CAAC,KAAK,CAAC,CAMvB;IAED;;;;;;OAMG;IACH,2BAHW,WAAW,cACX,GAAG,CAAC,IAAI,GAAC,MAAM,CAAC,QAY1B;IAED;;;;;;OAMG;IACH,QAJ8E,CAAC,SAAlE,CAAE,MAAM,EAAE,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,EAAE,WAAW,KAAK,IAAK,KAClE,CAAC,GACA,CAAC,CAKZ;IAED;;;;;;OAMG;IACH,YAJwD,CAAC,SAA5C,CAAU,IAAa,EAAb,MAAM,CAAC,KAAK,CAAC,EAAC,IAAW,EAAX,WAAW,KAAE,IAAK,KAC5C,CAAC,GACA,CAAC,CAKZ;IAED;;;;OAIG;IACH,aAFW,CAAC,IAAI,EAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,EAAC,EAAE,EAAC,WAAW,KAAG,IAAI,QAIjE;IAED;;;;OAIG;IACH,iBAFW,CAAS,IAAa,EAAb,MAAM,CAAC,KAAK,CAAC,EAAC,IAAW,EAAX,WAAW,KAAE,IAAI,QAIlD;IAED;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,eAdwB,IAAI,SAAf,OAAS,eAEX,0BAA0B,SAElC;QAAsB,aAAa;QACZ,aAAa;QACb,aAAa;QACd,YAAY;QACc,QAAQ;QACpC,IAAI;KACxB,GAAS,IAAI,SAAS,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAkO7F;IAED;;;;;;OAMG;IACH,iBAHW,0BAA0B,GACzB,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAI7B;IAED;;;;;;;OAOG;IACH,qBALW,KAAK,CAAC,QAAQ,OACd,0BAA0B,QA8CpC;IAED;;;;;;OAMG;IACH,SAFY,KAAK,CAAC,KAAK,CAAC,CAMvB;IAED;;OAEG;IACH,mBAMC;IAED;;;;;;OAMG;IACH,iCAJW,MAAM,QAMhB;IAED;;;;;;;;;;;OAWG;IACH,eAToE,GAAG,SAAzD,OAAO,CAAC,MAAM,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAC,MAAM,CAAE,EAChB,GAAG,SAAxC,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,GAAG,CAAE,iBAEvC,GAAG,kBACH,GAAG,GACF,GAAG,CAOd;IAED;;;;;;;OAOG;IACH,eAL2E,GAAG,SAAhE,OAAO,CAAC,MAAM,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAC,MAAM,GAAC,MAAM,CAAE,iBAC/D,GAAG,GACF,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAC,SAAS,CAKxD;IAED;;;;;;;OAOG;IACH,8BALW,MAAM,GACL,OAAO,CAMlB;IAED;;;;;;;OAOG;IACH,2BALW,QAAQ,GACP,GAAG,GAAG,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,GAAC,CAMjH;IAED;;;;;;;;;;;;;;;;OAgBG;IACH,cAJW,MAAM,WACN,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,GAAC,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,WACtE,KAAK,CAAC,oBAAoB,QAIpC;IAED;;;;;;;;;;;;;;;;;OAiBG;IACH,cALW,MAAM,UACN,MAAM,WACN,KAAK,CAAC,oBAAoB,QAKpC;IAED;;;;;;OAMG;IACH,cAJW,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,GAAC,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,QAMhF;IAED;;;;OAIG;IACH,iBAFW,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,QAIvC;IAED;;;;;OAKG;IACH,cAHW,MAAM,WACN,MAAM,QAIhB;IAED;;;;;OAKG;IACH,WAHW,MAAM,GACL,KAAK,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAI5C;IAED;;;;;;;OAOG;IACH,cAJW,MAAM,QACN,MAAM,GACL,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAInD;IAED;;;;;;OAMG;IACH,WAFY,KAAK,CAAC,KAAK,CAAC,oBAAoB,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAkBnF;IAED;;;OAGG;IACH,UAFY;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE;YAAE,CAAC,CAAC,EAAC,MAAM,GAAC,MAAM,GAAG,GAAG,CAAA;SAAE,CAAC;QAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAA;KAAG,CA0BxF;IAED;;;OAGG;IACH,wBAFG;QAAuB,QAAQ;KACjC,UAqBA;IAED;;;;;;;;OAQG;IACH,IALa,CAAC,KACH,CAAC,KAAK,EAAC,KAAK,CAAC,oBAAoB,CAAC,KAAK,CAAC,GAAC,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAC,KAAK,EAAC,MAAM,KAAG,CAAC,GACtF,KAAK,CAAC,CAAC,CAAC,CAKnB;IAED;;;;OAIG;IACH,WAFW,CAAC,KAAK,EAAC,KAAK,CAAC,oBAAoB,CAAC,KAAK,CAAC,GAAC,KAAK,CAAC,gBAAgB,CAAC,KAAK,CAAC,EAAC,KAAK,EAAC,MAAM,KAAG,GAAG,QAInG;IAED;;;;OAIG;IACH,eAFW,CAAC,GAAG,EAAC,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAC,GAAG,EAAC,OAAO,CAAC,MAAM,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAC,MAAM,CAAC,EAAC,KAAK,EAAC,IAAI,KAAG,GAAG,QAQ5H;IAED;;;;OAIG;IACH,YAFY,gBAAgB,CAAC,OAAO,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,CAIpF;IAED;;;;OAIG;IACH,cAFY,gBAAgB,CAAC,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAIhE;IAED;;;;OAIG;IACH,eAFY,gBAAgB,CAAC,GAAG,CAAC,IAAI,MAAM,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAC,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAE,CAAC,GAAG,CAAC,CAAC,CAIxH;IAED;;;;OAIG;IACH,gBAFY,MAAM,CAIjB;IASD;;;;;;;;;OASG;IACH,gBAFW,eAAe,GAAG,eAAe,QAW3C;IA1BD;;OAEG;IACH,oCAFW,IAAI,WAId;CAsBF;AAOM,uBAJ+C,KAAK,SAA9C,OAAQ,YAAY,EAAE,iBAAkB,UAC1C,KAAK,GACJ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,YAAY,EAAE,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAElB;AACpD,6CAA6C;AAMtC,gDAHI,WAAW,SACX,KAAK,uCAiBf;AAOM,8BAJI,GAAG,KACH,GAAG,GACF,OAAO,CAEgH;AAyB5H,oCARI,KAAK,CAAC,GAAG,CAAC,SACV,MAAM,OACN,MAAM,GACL,KAAK,CAAC,GAAG,CAAC,CAgCrB;AAYM,kCAPI,KAAK,SACL,MAAM,GACL,GAAG,CAqBd;AAaM,yDARI,WAAW,UACX,KAAK,iBACL,IAAI,OAAC,WACL,KAAK,CAAC,MAAM,CAAC,QA4DvB;AAaM,oDARI,WAAW,UACX,KAAK,SACL,MAAM,WACN,KAAK,CAAC;QAAO,MAAM,GAAC,GAAG;CAAC,GAAC,KAAK,CAAC,GAAG,CAAC,GAAC,MAAM,GAAC,IAAI,GAAC,MAAM,GAAC,UAAU,CAAC,QA4C5E;AAaM,kDAPI,WAAW,UACX,KAAK,WACL,KAAK,CAAC;QAAO,MAAM,GAAC,GAAG;CAAC,GAAC,KAAK,CAAC,GAAG,CAAC,GAAC,MAAM,GAAC,IAAI,GAAC,MAAM,GAAC,UAAU,CAAC,QAe5E;AAWM,4CARI,WAAW,UACX,KAAK,SACL,MAAM,UACN,MAAM,QAyChB;AAYM,2CAPI,WAAW,UACX,KAAK,OACL,MAAM,QAUhB;AAWM,wCARI,WAAW,UACX,KAAK,OACL,MAAM,SACN,MAAM,QAqChB;AAUM,mCAPI,KAAK,CAAC,GAAG,CAAC,OACV,MAAM,GACL;QAAO,MAAM,GAAC,GAAG;CAAC,GAAC,MAAM,GAAC,IAAI,GAAC,KAAK,CAAC,GAAG,CAAC,GAAC,MAAM,GAAC,UAAU,GAAC,KAAK,CAAC,GAAG,CAAC,GAAC,SAAS,CAS3F;AASM,sCANI,KAAK,CAAC,GAAG,CAAC;;;;EAkBpB;AA0BM,gCAf8B,SAAS,SAAhC,KAAK,CAAC,eAAgB,KACzB,SAAS,UACT,KAAK,iBACL,GAAG,CAAC,MAAM,GAAC,IAAI,CAAC,OAAC,MACjB,0BAA0B,QAC1B,OAAO,aACP,GAAG,CAAC,KAAK,CAAC,GAAC,GAAG,CAAC,KAAK,EAAC,GAAG,CAAC,GAAC,IAAI,iBAC9B,KAAK,OAAC,kBACN,KAAK,OAAC,SACN,GAAG,YACH,GAAG,QA0Db;AAUM,mCAPI,KAAK,CAAC,GAAG,CAAC,OACV,MAAM,GACL,OAAO,CASlB;AASM,gCANI,IAAI,YACJ,QAAQ,GAAC,SAAS,WAO+F;AAWrH,2CARI,KAAK,CAAC,GAAG,CAAC,OACV,MAAM,YACN,QAAQ,GACP;QAAO,MAAM,GAAC,GAAG;CAAC,GAAC,MAAM,GAAC,IAAI,GAAC,KAAK,CAAC,GAAG,CAAC,GAAC,MAAM,GAAC,UAAU,GAAC,KAAK,CAAC,GAAG,CAAC,GAAC,SAAS,CAW3F;AAUM,8CAPI,KAAK,CAAC,GAAG,CAAC,YACV,QAAQ;;;;EAwBlB;AASM,wCANI,KAAK,CAAC,GAAG,CAAC,GAAG;IAAE,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;CAAE,GACvC,gBAAgB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAQvC;AAQM,yCAHI,eAAe,GAAG,eAAe,GAChC,WAAW,CAEsD;AAQtE,2CAHI,eAAe,GAAG,eAAe,GAChC,aAAa,CAE0D;AAQ5E,yCAHI,eAAe,GAAG,eAAe,GAChC,WAAW,CActB;AAMM,2CAHI,eAAe,GAAG,eAAe,GAChC,aAAa,CAE2E;AAQ7F,0CAHI,eAAe,GAAG,eAAe,GAChC,YAAY,CAEuD;AAQxE,wCAHI,eAAe,GAAG,eAAe,GAChC,UAAU,CAE0E;AAMzF,wCAHI,eAAe,GAAG,eAAe,GAChC,UAAU,CASrB;AAMM,2CAHI,eAAe,GAAG,eAAe,GAChC,aAAa,CAEuD;AAQzE,4CAHI,eAAe,GAAG,eAAe,GAChC,cAAc,CAEwD;AAElF;;;;GAIG;AACH,0BAFU,KAAK,CAAC,CAAS,IAAiC,EAAjC,eAAe,GAAG,eAAe,KAAE,eAAe,CAAC,CAc3E;AAMM,yCAHI,eAAe,GAAG,eAAe,QACjC,MAAM,+CAE0E;AASpF,mCANI,eAAe,GAAG,eAAe,GAChC,KAAK,CAUhB;qBAnlEY;QAAO,MAAM,GAAC,GAAG;CAAC,GAAC,KAAK,CAAC,GAAG,CAAC,GAAC,MAAM,GAAC,IAAI,GAAC,MAAM,GAAC,UAAU,YAAQ,KAAK,CAAC,GAAG,CAAC;kCA48C3D,KAAK,SAAtB,KAAK,CAAC,SAAU,IACjB,KAAK,CAAC,kBAAkB,CAAC,KAAK,EAAE;IACtC,KAAK,EAAE,GAAG,CAAC,IAAI,MAAM,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,GAAG,YAAY,CAAC,KAAK,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAE,CAAC;IACxG,QAAQ,EAAE,YAAY,CAAC,KAAK,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAAA;CAC1D,CAAC;yBAKY,IAAI,oBACV,OAAO,CAAC,IAAI,EAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAC,KAAK,CAAC,QAAQ,CAAC,SAAS,KAAK,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,GAAG,CAAC,OAAO,SAAS,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,GAAG,KAAK,CAAC;qBAj+C7J,mBAAmB;uBAOH,mBAAmB;uBAhCnB,YAAY;wBASX,aAAa;mBADlB,aAAa;4BAiBzB,mBAAmB;8BAAnB,mBAAmB;4BAAnB,mBAAmB;8BAAnB,mBAAmB;6BAAnB,mBAAmB;2BAAnB,mBAAmB;2BAAnB,mBAAmB;8BAAnB,mBAAmB;+BAAnB,mBAAmB"} -\ No newline at end of file -diff --git a/src/structs/Item.js b/src/structs/Item.js -index d3fb68a6086cab497099f265f95100258224db1b..5c4e621eb5e0341e002688b9e30927a7c2979185 100644 ---- a/src/structs/Item.js -+++ b/src/structs/Item.js -@@ -259,7 +259,7 @@ export class Item extends AbstractStruct { - // set as current parent value if right === null and this is parentSub - /** @type {YType} */ (this.parent)._map.set(this.parentSub, this) - if (this.left !== null) { -- // this is the current attribute value of parent. delete right -+ // this is the current attribute value of parent. delete the previous value - this.left.delete(transaction) - } - } -diff --git a/src/utils/UndoManager.js b/src/utils/UndoManager.js -index 5b94f87efb372d97fb8e943f607c585433dfbabb..27af08ca781bcdebc39206df93055e6a759a6c4f 100644 ---- a/src/utils/UndoManager.js -+++ b/src/utils/UndoManager.js -@@ -92,7 +92,7 @@ const popStackItem = (undoManager, stack, eventType) => { - } - }) - itemsToRedo.forEach(struct => { -- performedChange = redoItem(transaction, struct, itemsToRedo, stackItem.inserts, undoManager.ignoreRemoteMapChanges, undoManager) !== null || performedChange -+ performedChange = redoItem(transaction, struct, itemsToRedo, stackItem.inserts, undoManager.ignoreRemoteAttributeChanges, undoManager) !== null || performedChange - }) - // We want to delete in reverse order so that children are deleted before - // parents, so we have more information available when items are filtered. -@@ -131,7 +131,7 @@ const popStackItem = (undoManager, stack, eventType) => { - * filter returns false, the type/item won't be deleted even it is in the - * undo/redo scope. - * @property {Set} [UndoManagerOptions.trackedOrigins=new Set([null])] -- * @property {boolean} [ignoreRemoteMapChanges] Experimental. By default, the UndoManager will never overwrite remote changes. Enable this property to enable overwriting remote changes on key-value changes (Y.Map, properties on Y.Xml, etc..). -+ * @property {boolean} [ignoreRemoteAttributeChanges] By default, the UndoManager will never overwrite remote changes. In some cases this might be the expected behavior. This property enables overwriting remote changes on attribute changes. (previously named `ignoreRemoteMapChanges`) - * @property {Doc} [doc] The document that this UndoManager operates on. Only needed if typeScope is empty. - */ - -@@ -162,7 +162,7 @@ export class UndoManager extends ObservableV2 { - captureTransaction = _tr => true, - deleteFilter = () => true, - trackedOrigins = new Set([null]), -- ignoreRemoteMapChanges = false, -+ ignoreRemoteAttributeChanges = false, - doc = /** @type {Doc} */ (array.isArray(typeScope) ? typeScope[0].doc : typeScope instanceof Doc ? typeScope : typeScope.doc) - } = {}) { - super() -@@ -198,7 +198,7 @@ export class UndoManager extends ObservableV2 { - */ - this.currStackItem = null - this.lastChange = 0 -- this.ignoreRemoteMapChanges = ignoreRemoteMapChanges -+ this.ignoreRemoteAttributeChanges = ignoreRemoteAttributeChanges - this.captureTimeout = captureTimeout - /** - * @param {Transaction} transaction -@@ -415,14 +415,14 @@ const isDeletedByUndoStack = (stack, id) => array.some(stack, /** @param {StackI - * @param {Item} item - * @param {Set} redoitems - * @param {IdSet} itemsToDelete -- * @param {boolean} ignoreRemoteMapChanges -+ * @param {boolean} ignoreRemoteAttributeChanges - * @param {import('../utils/UndoManager.js').UndoManager} um - * - * @return {Item|null} - * - * @private - */ --export const redoItem = (transaction, item, redoitems, itemsToDelete, ignoreRemoteMapChanges, um) => { -+export const redoItem = (transaction, item, redoitems, itemsToDelete, ignoreRemoteAttributeChanges, um) => { - const doc = transaction.doc - const store = doc.store - const ownClientID = doc.clientID -@@ -442,7 +442,7 @@ export const redoItem = (transaction, item, redoitems, itemsToDelete, ignoreRemo - // make sure that parent is redone - if (parentItem !== null && parentItem.deleted === true) { - // try to undo parent if it will be undone anyway -- if (parentItem.redone === null && (!redoitems.has(parentItem) || redoItem(transaction, parentItem, redoitems, itemsToDelete, ignoreRemoteMapChanges, um) === null)) { -+ if (parentItem.redone === null && (!redoitems.has(parentItem) || redoItem(transaction, parentItem, redoitems, itemsToDelete, ignoreRemoteAttributeChanges, um) === null)) { - return null - } - while (parentItem.redone !== null) { -@@ -491,7 +491,7 @@ export const redoItem = (transaction, item, redoitems, itemsToDelete, ignoreRemo - } - } else { - right = null -- if (item.right && !ignoreRemoteMapChanges) { -+ if (item.right && !ignoreRemoteAttributeChanges) { - left = item - // Iterate right while right is in itemsToDelete - // If it is intended to delete right while item is redone, we can expect that item should replace right. -@@ -508,6 +508,9 @@ export const redoItem = (transaction, item, redoitems, itemsToDelete, ignoreRemo - } else { - left = parentType._map.get(item.parentSub) || null - } -+ if (left !== null && /** @type {YType} */ (left.parent)._item !== parentItem) { -+ left = parentType._map.get(item.parentSub) || null -+ } - } - const nextClock = store.getClock(ownClientID) - const nextId = createID(ownClientID, nextClock) -diff --git a/src/ytype.js b/src/ytype.js -index ab79c2fe90d8b3c74b1c1ce6d7f62f714605f33c..bad51b3c1b80f8849eede060d412aa7d70bd6d3f 100644 ---- a/src/ytype.js -+++ b/src/ytype.js -@@ -1926,7 +1926,19 @@ export const typeMapGetDelta = (d, parent, attrsToRender, am, deep, modified, de - let c = array.last(content.getContent()) - if (deleted) { - if (itemsToRender == null || itemsToRender.hasId(item.lastId)) { -- d.deleteAttr(key, attribution, c) -+ if (attribution != null) { -+ // Item surfaced under attribution (suggestion view / diff AM, -+ // either in snapshot mode or in an event-driven render). The -+ // attribute is still observable in the rendered state, so emit -+ // a positive `SetAttrOp` carrying the attribution metadata - -+ // matching how content children are rendered for the same case -+ // (positive `InsertOp` with attribution, never `DeleteOp`). -+ d.setAttr(key, c, attribution) -+ } else { -+ // Hard-deleted attribute (no AM-surfaced attribution): emit the -+ // change op so event consumers can apply it. -+ d.deleteAttr(key, attribution, c) -+ } - } - } else if (deep && c instanceof YType && modified?.has(c)) { - d.modifyAttr(key, c.toDelta(am, opts)) diff --git a/patches/lib0@1.0.0-rc.13.patch b/patches/lib0@1.0.0-rc.13.patch deleted file mode 100644 index 193dad31ed..0000000000 --- a/patches/lib0@1.0.0-rc.13.patch +++ /dev/null @@ -1,466 +0,0 @@ -diff --git a/dist/delta/delta.d.ts b/dist/delta/delta.d.ts -index 4b3d23babb76883d7a66c10ab9f170436484fcb2..1f97a3da5707f7602a72f8d15c6158c61321d949 100644 ---- a/dist/delta/delta.d.ts -+++ b/dist/delta/delta.d.ts -@@ -42,6 +42,22 @@ export const $attribution: s.Schema; - * @type {s.Schema} - */ - export const $deltaMapChangeJson: s.Schema; -+/** -+ * Invariants shared by all op classes below (TextOp, InsertOp, DeleteOp, -+ * RetainOp, ModifyOp, SetAttrOp, DeleteAttrOp, ModifyAttrOp): -+ * -+ * - **Only code inside `delta.js` may mutate op fields.** External consumers -+ * treat ops as immutable; structural fields are JSDoc-annotated `@readonly` -+ * to reinforce this. Mutation is permitted only while the owning Delta is -+ * not `done` — every builder entry point routes through `modDeltaCheck` -+ * to enforce this at runtime. -+ * - **Any mutation of a fingerprinted field MUST null `_fingerprint`.** The -+ * fingerprint is a lazy cache; if it has already been computed and the -+ * underlying data changes without invalidating it, every subsequent -+ * fingerprint read (and any `diff` / equality check that relies on it) is -+ * wrong. Fields covered: insert, delete, retain, format, attribution, -+ * value, key. -+ */ - export class TextOp extends list.ListNode { - /** - * @param {string} insert -@@ -125,9 +141,9 @@ export class InsertOp extends list.ListNode { - */ - _fingerprint: string | null; - /** -- * @param {ArrayContent} newVal -+ * @param {ArrayContent} _newVal - */ -- _updateInsert(newVal: ArrayContent): void; -+ _updateInsert(_newVal: ArrayContent): void; - /** - * @return {'insert'} - */ -@@ -184,10 +200,10 @@ export class DeleteOp extends list.ListNode { - /** - * Remove a part of the operation (similar to Array.splice) - * -- * @param {number} _offset -+ * @param {number} offset - * @param {number} len - */ -- _splice(_offset: number, len: number): this; -+ _splice(offset: number, len: number): this; - /** - * @return {DeltaListOpJSON} - */ -@@ -666,10 +682,12 @@ export class DeltaBuilder?} other -- * @param {{ final?: boolean }} opts -- experimental -+ * @param {{ final?: boolean }} opts -- (experimental) - * @return {DeltaBuilder} - */ - apply(other: Delta | null, { final }?: { -diff --git a/src/bin/0serve.js b/src/bin/0serve.js -index a69d09ba2effab926c2b0b24a147ad744064fe78..16cb9427c6ef666000b4463aa8734505c39e7563 100755 ---- a/src/bin/0serve.js -+++ b/src/bin/0serve.js -@@ -89,9 +89,17 @@ const server = http.createServer((req, res) => { - server.listen(port, host, () => { - logging.print(logging.BOLD, logging.ORANGE, `Server is running on http://${host}:${port}`) - if (paramOpenFile) { -- const start = debugBrowser || (process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'start' : 'xdg-open') -+ const url = `http://${host}:${port}/${paramOpenFile}` - import('child_process').then(cp => { -- cp.exec(`${start} http://${host}:${port}/${paramOpenFile}`) -+ if (debugBrowser) { -+ cp.execFile(debugBrowser, [url]) -+ } else if (process.platform === 'darwin') { -+ cp.execFile('open', [url]) -+ } else if (process.platform === 'win32') { -+ cp.execFile('cmd', ['/c', 'start', '', url]) -+ } else { -+ cp.execFile('xdg-open', [url]) -+ } - }) - } - }) -diff --git a/src/delta/delta.js b/src/delta/delta.js -index e063729e4515dd76aecd488655b26fec82a22ca9..d4be86c6af7aef2f0c51c32f2023c24152770c22 100644 ---- a/src/delta/delta.js -+++ b/src/delta/delta.js -@@ -101,6 +101,22 @@ const _cloneAttrs = attrs => attrs == null ? attrs : { ...attrs } - */ - const _markMaybeDeltaAsDone = maybeDelta => $deltaAny.check(maybeDelta) ? /** @type {MaybeDelta} */ (maybeDelta.done()) : maybeDelta - -+/** -+ * Invariants shared by all op classes below (TextOp, InsertOp, DeleteOp, -+ * RetainOp, ModifyOp, SetAttrOp, DeleteAttrOp, ModifyAttrOp): -+ * -+ * - **Only code inside `delta.js` may mutate op fields.** External consumers -+ * treat ops as immutable; structural fields are JSDoc-annotated `@readonly` -+ * to reinforce this. Mutation is permitted only while the owning Delta is -+ * not `done` — every builder entry point routes through `modDeltaCheck` -+ * to enforce this at runtime. -+ * - **Any mutation of a fingerprinted field MUST null `_fingerprint`.** The -+ * fingerprint is a lazy cache; if it has already been computed and the -+ * underlying data changes without invalidating it, every subsequent -+ * fingerprint read (and any `diff` / equality check that relies on it) is -+ * wrong. Fields covered: insert, delete, retain, format, attribution, -+ * value, key. -+ */ - export class TextOp extends list.ListNode { - /** - * @param {string} insert -@@ -228,14 +244,17 @@ export class InsertOp extends list.ListNode { - this._fingerprint = null - } - -+ /* c8 ignore start */ - /** -- * @param {ArrayContent} newVal -+ * @param {ArrayContent} _newVal - */ -- _updateInsert (newVal) { -- // @ts-ignore -- this.insert = newVal -- this._fingerprint = null -+ _updateInsert (_newVal) { -+ // Mirror of TextOp._updateInsert; not currently called on InsertOp because -+ // adjacent inserts are merged in-place via `end.insert.push(...)`. Kept for -+ // parity with TextOp's API. -+ error.unexpectedCase() // throw if called - } -+ /* c8 ignore stop */ - - /** - * @return {'insert'} -@@ -357,11 +376,13 @@ export class DeleteOp extends list.ListNode { - /** - * Remove a part of the operation (similar to Array.splice) - * -- * @param {number} _offset -+ * @param {number} offset - * @param {number} len - */ -- _splice (_offset, len) { -- this.prevValue = /** @type {any} */ (this.prevValue ? slice(this.prevValue, _offset, len) : null) -+ _splice (offset, len) { -+ if (this.prevValue) { -+ /** @type {DeltaBuilder} */ (this.prevValue).apply(create().retain(offset).delete(len)) -+ } - this._fingerprint = null - this.delete -= len - return this -@@ -547,6 +568,9 @@ export class ModifyOp extends list.ListNode { - }))) - } - -+ /* c8 ignore start */ -+ // ModifyOp has length 1, so callers never pass offset>0 or len>0 — splitHere -+ // is a no-op for length-1 ops. Kept for the structural _splice contract. - /** - * Remove a part of the operation (similar to Array.splice) - * -@@ -556,6 +580,7 @@ export class ModifyOp extends list.ListNode { - _splice (_offset, _len) { - return this - } -+ /* c8 ignore stop */ - - /** - * @return {DeltaListOpJSON} -@@ -851,7 +876,7 @@ export const $setAttrOpWith = $content => s.$custom(o => $setAttrOp.check(o) && - * @param {s.Schema} $content - * @return {s.Schema>} - */ --export const $insertOpWith = $content => s.$custom(o => $insertOp.check(o) && $content.check(o.insert.every(ins => $content.check(ins)))) -+export const $insertOpWith = $content => s.$custom(o => $insertOp.check(o) && o.insert.every(ins => $content.check(ins))) - - /** - * @template {DeltaAny} Modify -@@ -1231,9 +1256,13 @@ const tryMergeWithPrev = (parent, op) => { - /** @type {DeleteOp} */ (prevOp).delete += op.delete - } else if ($textOp.check(op)) { - /** @type {TextOp} */ (prevOp)._updateInsert(/** @type {TextOp} */ (prevOp).insert + op.insert) -+ /* c8 ignore start */ - } else { -+ // unreachable: the constructor check at the top of the function already -+ // limits `op` to one of the four kinds tested above - error.unexpectedCase() - } -+ /* c8 ignore stop */ - list.remove(parent, op) - } - -@@ -1501,10 +1530,12 @@ export class DeltaBuilder extends Delta { - * - * a.apply(b).apply(c) - * -- * @todo fuzz test the above property -+ * If `final = true`, we consider this delta the final state and drop deleteAttrOps from -+ * attributes. (E.g. if `otherOp` deletes an attribute, this op will simply not have the -+ * attribute). Any kind of `delete` op might be considered a bug. A final delta is not idempotent. - * - * @param {Delta?} other -- * @param {{ final?: boolean }} opts -- experimental -+ * @param {{ final?: boolean }} opts -- (experimental) - * @return {DeltaBuilder} - */ - apply (other, { final = this.isFinal } = {}) { -@@ -1517,7 +1548,7 @@ export class DeltaBuilder extends Delta { - const c = /** @type {SetAttrOp|DeleteAttrOp|ModifyAttrOp} */ (this.attrs[op.key]) - if ($modifyAttrOp.check(op)) { - if ($deltaAny.check(c?.value)) { -- c._modValue.apply(op.value) -+ c._modValue.apply(op.value, { final }) - } else { - // then this is a simple modify - // @ts-ignore -@@ -1588,10 +1619,14 @@ export class DeltaBuilder extends Delta { - this.childCnt += op.length - } - for (const op of other.children) { -+ // defensive: the per-branch logic below resets opsI/offset whenever it -+ // consumes an op exactly. This guard catches any path that forgets to. -+ /* c8 ignore start */ - if (opsI?.length === offset) { - opsI = opNextUndeleted(opsI) - offset = 0 - } -+ /* c8 ignore stop */ - if ($textOp.check(op) || $insertOp.check(op)) { - insertClonedOp(op) - } else if ($retainOp.check(op)) { -@@ -1611,7 +1646,11 @@ export class DeltaBuilder extends Delta { - } - if (opsI != null) { - if (op.format != null && retainLen > 0) { -- offset = retainLen -+ // accumulate onto the existing offset — the else-branch below uses -+ // `offset += retainLen`, and we must agree with it when prior -+ // iterations have advanced offset into opsI without splitting (e.g. -+ // a format-less retain followed by a same-format retain). -+ offset += retainLen - splitHere() - updateOpFormat(/** @type {ChildrenOpAny} */ (opsI.prev), op.format) - scheduleForMerge(opsI.prev) -@@ -1670,9 +1709,12 @@ export class DeltaBuilder extends Delta { - opsI._splice(offset, delLen) - } - remainingLen -= delLen -+ /* c8 ignore start */ - } else { -+ // unreachable: opsI was already typed as retain | non-delete-content | delete above - error.unexpectedCase() - } -+ /* c8 ignore stop */ - } - } else if ($modifyOp.check(op)) { - if (opsI != null && op.format != null && (!$deleteOp.check(opsI) && !$retainOp.check(opsI))) { // retain handles splitting seperately, without copying attrs -@@ -1709,14 +1751,20 @@ export class DeltaBuilder extends Delta { - opsI._splice(0, 1) - scheduleForMerge(opsI) - } -- } else if ($deleteOp.check(opsI)) { -- // nop -+ /* c8 ignore start */ - } else { -+ // remaining branches: opsI is deleteOp or something unknown -+ // both branches are unreachable today: opNextUndeleted skips -+ // delete ops, so opsI is never a delete during iteration; and the four -+ // branches above exhaust the other op kinds. The deleteOp branch is -+ // kept as a defensive no-op (drops a modify that lands in a deleted -+ // region) rather than a throw. - error.unexpectedCase() - } - } else { - error.unexpectedCase() - } -+ /* c8 ignore stop */ - } - // iterate backwards, to ensure that we merge all content - for (let i = maybeMergeable.length - 1; i >= 0; i--) { -@@ -1772,9 +1820,12 @@ export class DeltaBuilder extends Delta { - // @ts-ignore - delete this.attrs[otherOp.key] - } -+ /* c8 ignore start */ - } else { -+ // unreachable: attr ops are exhaustively setAttr | deleteAttr | modifyAttr - error.unexpectedCase() - } -+ /* c8 ignore stop */ - } - /** - * Rebase children. -@@ -1831,7 +1882,10 @@ export class DeltaBuilder extends Delta { - otherOffset = otherChild.length - } else { - if ($modifyOp.check(otherChild)) { -- /** @type {any} */ (currChild.value).rebase(otherChild, priority) -+ // _modValue (not .value) — ModifyOp.clone() marks its inner delta -+ // as `done`, so a cloned ModifyOp can only be rebased after the -+ // _modValue getter lazy-clones it back to mutable. -+ currChild._modValue.rebase(otherChild.value, priority) - } else if ($deleteOp.check(otherChild)) { - list.remove(this.children, currChild) - this.childCnt -= 1 -@@ -1848,21 +1902,70 @@ export class DeltaBuilder extends Delta { - * - insert: split curr op and insert retain - */ - if ($retainOp.check(otherChild) || $modifyOp.check(otherChild)) { -+ // Format reconciliation. priority=true is a no-op (currChild's format -+ // wins). For !priority, currChild concedes any format key that -+ // otherChild also writes — but only over the [currOffset..currOffset+ -+ // maxCommonLen] overlap. Split currChild around the overlap so the -+ // prefix/suffix keep their original format and only the middle piece -+ // carries the stripped format. -+ if ( -+ !priority && -+ $retainOp.check(currChild) && -+ currChild.format != null && -+ otherChild.format != null -+ ) { -+ /** @type {FormattingAttributes} */ -+ const stripped = {} -+ let strippedAny = false -+ for (const k in currChild.format) { -+ if (k in otherChild.format) { -+ strippedAny = true -+ } else { -+ stripped[k] = currChild.format[k] -+ } -+ } -+ if (strippedAny) { -+ // split off the suffix [currOffset+maxCommonLen..length] if any -+ if (currOffset + maxCommonLen < currChild.length) { -+ const suffix = currChild.clone(currOffset + maxCommonLen, currChild.length) -+ list.insertBetween(this.children, currChild, currChild.next, suffix) -+ currChild._splice(currOffset + maxCommonLen, currChild.length - (currOffset + maxCommonLen)) -+ } -+ // split off the prefix [0..currOffset] if any -+ if (currOffset > 0) { -+ const prefix = currChild.clone(0, currOffset) -+ list.insertBetween(this.children, currChild.prev, currChild, prefix) -+ currChild._splice(0, currOffset) -+ currOffset = 0 -+ } -+ // currChild now spans exactly the overlap. Replace its format. -+ /** @type {any} */ (currChild).format = object.isEmpty(stripped) ? null : stripped -+ currChild._fingerprint = null -+ } -+ } - currOffset += maxCommonLen - otherOffset += maxCommonLen - } else if ($deleteOp.check(otherChild)) { - if ($retainOp.check(currChild)) { - // @ts-ignore - currChild.retain -= maxCommonLen -+ currChild._fingerprint = null - } else if ($deleteOp.check(currChild)) { - currChild.delete -= maxCommonLen -+ currChild._fingerprint = null - } - this.childCnt -= maxCommonLen -- } else { // insert/text.check(currOp) -+ // advance other so subsequent currChild ops see what comes AFTER this -+ // delete; without this we'd loop against the same delete forever and -+ // never reach other's later inserts. -+ otherOffset += maxCommonLen -+ } else { // insert/text.check(otherChild) - if (currOffset > 0) { -- const leftPart = currChild.clone(currOffset) -+ const leftPart = currChild.clone(0, currOffset) - list.insertBetween(this.children, currChild.prev, currChild, leftPart) -- currChild._splice(currOffset, currChild.length - currOffset) -+ // leftPart is the prefix; currChild becomes the suffix. Remove the -+ // prefix portion from currChild so it represents [currOffset..length]. -+ currChild._splice(0, currOffset) - currOffset = 0 - } - list.insertBetween(this.children, currChild.prev, currChild, new RetainOp(otherChild.length, null, null)) -@@ -2000,8 +2103,10 @@ export class $Delta extends s.Schema { - check (o, err = undefined) { - const { $name, $attrs, $children, hasText, $formats } = this.shape - if (!$deltaAny.check(o, err)) { -+ /* c8 ignore next */ - err?.extend(null, 'Delta', o?.constructor.name, 'Constructor match failed') - } else if (o.name != null && !$name.check(o.name, err)) { -+ /* c8 ignore next */ - err?.extend('Delta.name', $name.toString(), o.name, 'Unexpected node name') - } else if (list.toArray(o.children).some(c => (!hasText && $textOp.check(c)) || (hasText && $textOp.check(c) && c.format != null && !$formats.check(c.format)) || ($insertOp.check(c) && !c.insert.every(ins => $children.check(ins))))) { - err?.extend('Delta.children', '', '', 'Children don\'t match the schema') -@@ -2097,7 +2202,7 @@ export const mergeDeltas = (a, b) => { - c.apply(b) - return /** @type {any} */ (c) - } -- return a == null ? b : (a || null) -+ return /** @type {D} */ (a || b || null) - } - - /** -@@ -2325,6 +2430,16 @@ class _DiffStringWrapper { - */ - - /** -+ * Compute a delta that, when applied to `d1`, produces `d2`. Only the children and attributes of -+ * `d1` and `d2` are compared; the top-level node names of `d1` and `d2` are *not*. Diffing -+ * `
a
` against `a` is valid and yields an empty diff — they have the same -+ * children and attributes, so as far as `diff` is concerned they are equal at the level it cares -+ * about. The top-level name is treated as a document-type marker, not as diffable content. -+ * -+ * Names *are* compared on children: a child node whose name changes between `d1` and `d2` is -+ * replaced wholesale (delete + insert), not converted into a `modify` op. Same-name child nodes -+ * at aligned positions are paired and recursed into via `modify`. -+ * - * @template {DeltaConf} Conf - * @param {Delta} d1 - * @param {NoInfer>} d2 -@@ -2395,9 +2510,14 @@ export const diff = (d1, d2) => { - cs2.push(left2.insert) - } else if ($insertOp.check(left2)) { - cs2.push(...left2.insert.map(ins => typeof ins === 'string' ? new _DiffStringWrapper(ins) : ins)) -+ /* c8 ignore start */ - } else { -+ // unreachable for valid diff inputs (delete on the rhs would already -+ // have been rejected via the `[lib0/delta] diffing deletes unsupported` -+ // path above) - error.unexpectedCase() - } -+ /* c8 ignore stop */ - formattingNeedsDiff ||= left2.format != null - left2 = left2.next - } -@@ -2459,9 +2579,14 @@ export const diff = (d1, d2) => { - a = a.next - aOffset = 0 - } -+ /* c8 ignore start */ - } else { -+ // unreachable: by this point both a and b are insert/text (deletes -+ // were rejected upstream and `originalUpdated` is the result of an -+ // apply, which keeps inserts only). - error.unexpectedCase() - } -+ /* c8 ignore stop */ - } - // @todo instead of applying, we want to first exec d, then formattingDiff - we need a merge - // function! -@@ -2481,10 +2606,11 @@ export const diff = (d1, d2) => { - } else { - d.setAttr(key, nextVal) - } -+ /* c8 ignore start */ - } else { -- /* c8 ignore next 2 */ - error.unexpectedCase() - } -+ /* c8 ignore stop */ - } - } - for (const { key } of d1.attrs) { diff --git a/patches/lib0@1.0.0-rc.14.patch b/patches/lib0@1.0.0-rc.14.patch new file mode 100644 index 0000000000..becd073304 --- /dev/null +++ b/patches/lib0@1.0.0-rc.14.patch @@ -0,0 +1,79 @@ +diff --git a/dist/delta/delta.d.ts b/dist/delta/delta.d.ts +index 1f97a3d..b6f9db5 100644 +--- a/dist/delta/delta.d.ts ++++ b/dist/delta/delta.d.ts +@@ -905,7 +905,7 @@ export function from> extends Array ? (unknown extends Ac ? never : Ac) : never; + text: Extract extends never ? false : true; + }>; +-export function diff(d1: Delta, d2: NoInfer>): Delta; ++export function diff(d1: Delta, d2: NoInfer>, matchNodes?: (a: any, b: any) => boolean): Delta; + export function diffChangesetWithSeparator(changeset: Array<{ + index: number; + remove: Array; +diff --git a/src/delta/delta.js b/src/delta/delta.js +index d4be86c..89ddc86 100644 +--- a/src/delta/delta.js ++++ b/src/delta/delta.js +@@ -2443,9 +2443,14 @@ class _DiffStringWrapper { + * @template {DeltaConf} Conf + * @param {Delta} d1 + * @param {NoInfer>} d2 ++ * @param {(a: DeltaAny, b: DeltaAny) => boolean} [matchNodes] decides whether a ++ * removed node and an inserted node are the *same* node (→ diffed/modified in ++ * place) or different (→ replaced). Defaults to name-equality. Override to force ++ * a *replace* for nodes that should be treated as atomic - e.g. raising a diff ++ * boundary when a node's identifying child changes type. + * @return {Delta} + */ +-export const diff = (d1, d2) => { ++export const diff = (d1, d2, matchNodes = (a, b) => a.name === b.name) => { + const d = create(d1.name === d2.name ? d1.name : null, $deltaAny) + if (d1.fingerprint !== d2.fingerprint) { + /** +@@ -2533,7 +2538,7 @@ export const diff = (d1, d2) => { + const changeset3 = diffChangesetWithSeparator(changeset2, patience.smartSplitRegex) + // split all + const changeset4 = diffChangesetWithSeparator(changeset3, /./g) +- applyChangesetToDelta(d, changeset4) ++ applyChangesetToDelta(d, changeset4, matchNodes) + if (formattingNeedsDiff) { + const formattingDiff = create() + // update opsIs with content diff. then we can figure out the formatting diff. +@@ -2602,7 +2607,7 @@ export const diff = (d1, d2) => { + const prevVal = attr1?.value + const nextVal = attr2.value + if ($deltaAny.check(prevVal) && $deltaAny.check(nextVal) && prevVal.name === nextVal.name) { +- d.modifyAttr(key, diff(prevVal, nextVal)) ++ d.modifyAttr(key, diff(prevVal, nextVal, matchNodes)) + } else { + d.setAttr(key, nextVal) + } +@@ -2648,8 +2653,9 @@ const applyInserts = (d, cins, len) => { len > 0 && cins.splice(0, len).forEach( + /** + * @param {DeltaBuilderAny} d + * @param {Array<{ index: number, remove: Array, insert: Array }>} changeset ++ * @param {(a: DeltaAny, b: DeltaAny) => boolean} [matchNodes] see {@link diff} + */ +-const applyChangesetToDelta = (d, changeset) => { ++const applyChangesetToDelta = (d, changeset, matchNodes = (a, b) => a.name === b.name) => { + for (let ci = 0, lastIndex = 0; ci < changeset.length; ci++) { + const c = changeset[ci] + d.retain(c.index - lastIndex) +@@ -2660,14 +2666,14 @@ const applyChangesetToDelta = (d, changeset) => { + const cremoveDeltaIndex = c.remove.findIndex(cc => $deltaAny.check(cc)) + if (cremoveDeltaIndex < 0) break + const cremoveDelta = c.remove[cremoveDeltaIndex] +- const cinsertDeltaIndex = c.insert.findIndex(cc => $deltaAny.check(cc) && cc.name === cremoveDelta.name) ++ const cinsertDeltaIndex = c.insert.findIndex(cc => $deltaAny.check(cc) && matchNodes(cremoveDelta, cc)) + if (cinsertDeltaIndex < 0) { + applyRemoves(d, c.remove, cremoveDeltaIndex + 1) + continue + } + applyRemoves(d, c.remove, cremoveDeltaIndex) + applyInserts(d, c.insert, cinsertDeltaIndex) +- d.modify(diff(c.remove[0], c.insert[0])) ++ d.modify(diff(c.remove[0], c.insert[0], matchNodes)) + c.remove.splice(0, 1) + c.insert.splice(0, 1) + } diff --git a/playground/src/examples.gen.tsx b/playground/src/examples.gen.tsx index f84d8461c2..250c4a241c 100644 --- a/playground/src/examples.gen.tsx +++ b/playground/src/examples.gen.tsx @@ -1813,6 +1813,30 @@ export const examples = { readme: 'This example shows how to use the `VersioningExtension` with collaborative editing using `@y/y` (v14). Snapshots are stored in localStorage using Yjs v2 state updates.\n\n**Try it out:** Edit the document, then click the "Version History" button to open the sidebar. From there you can save snapshots, preview older versions, rename them, and restore them.\n\n**Relevant Docs:**\n\n- [Editor Setup](/docs/getting-started/editor-setup)\n- [Real-time collaboration](/docs/features/collaboration)', }, + { + projectSlug: "multi-doc-versioning", + fullSlug: "collaboration/multi-doc-versioning", + pathFromRoot: "examples/07-collaboration/14-multi-doc-versioning", + config: { + playground: true, + docs: false, + author: "nperez0111", + tags: ["Advanced", "Collaboration"], + dependencies: { + "@y/protocols": "^1.0.6-rc.1", + "@y/websocket": "^4.0.0-3", + "@y/y": "^14.0.0-rc.16", + lib0: "1.0.0-rc.13", + } as any, + }, + title: "Multi-Document Collaboration with Version History", + group: { + pathFromRoot: "examples/07-collaboration", + slug: "collaboration", + }, + readme: + "This example shows a multi-document collaborative editor with per-document version history, using BlockNote's `VersioningExtension` and Y.js v14.\n\n**Features:**\n\n- User picker (per-tab identity via `sessionStorage`)\n- Left sidebar with document list (create, rename, delete)\n- Collaborative editing with Y.js (including suggestion mode)\n- Right sidebar with version history powered by `VersioningSidebar`\n- Per-document versioning backed by `localStorage`\n- Open multiple tabs with different users via the `?as=` URL param\n\n**Relevant Docs:**\n\n- [Versioning](https://www.blocknotejs.org/docs/collaboration/versioning)\n- [Y.js Collaboration](https://www.blocknotejs.org/docs/collaboration)", + }, ], }, extensions: { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fc55ba1b82..f141380ce3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,14 +14,15 @@ overrides: '@headlessui/react': ^2.2.4 '@tiptap/core': ^3.0.0 '@tiptap/pm': ^3.0.0 - '@y/prosemirror>lib0': 1.0.0-rc.13 + vitest: 4.1.7 + '@vitest/runner': 4.1.7 '@y/y': 14.0.0-rc.16 '@y/prosemirror': 2.0.0-2 + lib0: 1.0.0-rc.14 patchedDependencies: - '@y/prosemirror@2.0.0-2': 802334aa5d2410b9fc999d5fb5ffef01650a04e58b59fca24e142c55b3379728 - '@y/y@14.0.0-rc.16': 4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9 - lib0@1.0.0-rc.13: 328c50b547222f0e54a7a9f4f70926c0532c006dec4f24d6954635b8c3adb69e + '@y/prosemirror@2.0.0-2': 168146d45476a6e2019bd9b140bf068fd17c12fb6b7d282509552826e74740dc + lib0@1.0.0-rc.14: e55ee919122bfd99c2418ad2ca66b24bdc0770c01033d31bbec567d195600f20 importers: @@ -44,7 +45,7 @@ importers: version: 5.9.3 vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) wait-on: specifier: 9.0.5 version: 9.0.5 @@ -107,7 +108,7 @@ importers: version: 0.27.19(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@fumadocs/base-ui': specifier: 16.5.0 - version: 16.5.0(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tailwindcss@4.2.2) + version: 16.5.0(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tailwindcss@4.2.2) '@liveblocks/client': specifier: ^3.19.5 version: 3.19.5(@types/json-schema@7.0.15) @@ -143,7 +144,7 @@ importers: version: 3.1.18 '@polar-sh/better-auth': specifier: ^1.6.4 - version: 1.8.3(@polar-sh/sdk@0.42.5)(@stripe/react-stripe-js@4.0.2(@stripe/stripe-js@7.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@stripe/stripe-js@7.9.0)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(better-auth@1.4.22(better-sqlite3@12.8.0)(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(pg@8.20.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(vitest@4.1.5))(react-dom@19.2.5(react@19.2.5))(react-is@19.2.4)(react@19.2.5)(redux@5.0.1)(zod@4.3.6) + version: 1.8.3(@polar-sh/sdk@0.42.5)(@stripe/react-stripe-js@4.0.2(@stripe/stripe-js@7.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@stripe/stripe-js@7.9.0)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(better-auth@1.4.22(better-sqlite3@12.8.0)(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(pg@8.20.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(msw@2.11.5(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))))(react-dom@19.2.5(react@19.2.5))(react-is@19.2.4)(react@19.2.5)(redux@5.0.1)(zod@4.3.6) '@polar-sh/sdk': specifier: ^0.42.2 version: 0.42.5 @@ -158,7 +159,7 @@ importers: version: 4.3.2(react@19.2.5) '@sentry/nextjs': specifier: ^10.34.0 - version: 10.47.0(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)(webpack@5.105.4(esbuild@0.27.5)) + version: 10.47.0(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)(webpack@5.105.4(esbuild@0.27.5)(postcss@8.5.14)) '@shikijs/core': specifier: ^4 version: 4.0.2 @@ -212,28 +213,28 @@ importers: version: 3.6.8(@uppy/core@3.13.1) '@vercel/analytics': specifier: ^1.6.1 - version: 1.6.1(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5) + version: 1.6.1(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5) '@y-sweet/react': specifier: ^0.6.3 version: 0.6.4(react@19.2.5)(yjs@13.6.30) '@y/prosemirror': specifier: 2.0.0-2 - version: 2.0.0-2(patch_hash=802334aa5d2410b9fc999d5fb5ffef01650a04e58b59fca24e142c55b3379728)(@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9)))(@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9))(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8) + version: 2.0.0-2(patch_hash=168146d45476a6e2019bd9b140bf068fd17c12fb6b7d282509552826e74740dc)(@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.16))(@y/y@14.0.0-rc.16)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8) '@y/protocols': specifier: ^1.0.6-rc.1 - version: 1.0.6-rc.1(@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9)) + version: 1.0.6-rc.1(@y/y@14.0.0-rc.16) '@y/websocket': specifier: ^4.0.0-3 - version: 4.0.0-rc.2(@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9)) + version: 4.0.0-rc.2(@y/y@14.0.0-rc.16) '@y/y': specifier: 14.0.0-rc.16 - version: 14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9) + version: 14.0.0-rc.16 ai: specifier: ^6.0.5 version: 6.0.5(zod@4.3.6) better-auth: specifier: ~1.4.15 - version: 1.4.22(better-sqlite3@12.8.0)(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(pg@8.20.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(vitest@4.1.5) + version: 1.4.22(better-sqlite3@12.8.0)(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(pg@8.20.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(msw@2.11.5(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))) better-sqlite3: specifier: ^12.6.2 version: 12.8.0 @@ -245,22 +246,22 @@ importers: version: 12.38.0(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) fumadocs-core: specifier: 16.5.0 - version: 16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6) + version: 16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6) fumadocs-mdx: specifier: ^14.2.6 - version: 14.2.11(@types/mdast@4.0.4)(@types/mdx@2.0.13)(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 14.2.11(@types/mdast@4.0.4)(@types/mdx@2.0.13)(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) fumadocs-twoslash: specifier: ^3.1.12 - version: 3.1.15(@fumadocs/base-ui@16.5.0(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tailwindcss@4.2.2))(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3) + version: 3.1.15(@fumadocs/base-ui@16.5.0(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tailwindcss@4.2.2))(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3) fumadocs-typescript: specifier: ^5.1.1 - version: 5.2.1(7b71d35b2307cf0dedaa2cbc5003f54e) + version: 5.2.1(5565cdb15ab48f43051a188bfe184646) fumadocs-ui: specifier: npm:@fumadocs/base-ui@16.5.0 - version: '@fumadocs/base-ui@16.5.0(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tailwindcss@4.2.2)' + version: '@fumadocs/base-ui@16.5.0(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tailwindcss@4.2.2)' lib0: - specifier: 1.0.0-rc.13 - version: 1.0.0-rc.13(patch_hash=328c50b547222f0e54a7a9f4f70926c0532c006dec4f24d6954635b8c3adb69e) + specifier: 1.0.0-rc.14 + version: 1.0.0-rc.14(patch_hash=e55ee919122bfd99c2418ad2ca66b24bdc0770c01033d31bbec567d195600f20) lucide-react: specifier: ^0.562.0 version: 0.562.0(react@19.2.5) @@ -269,7 +270,7 @@ importers: version: 12.38.0(@emotion/is-prop-valid@1.4.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) next: specifier: ^16.2.7 - version: 16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + version: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) next-themes: specifier: ^0.4.6 version: 0.4.6(react-dom@19.2.5(react@19.2.5))(react@19.2.5) @@ -403,10 +404,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/01-basic/02-block-objects: dependencies: @@ -446,10 +447,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/01-basic/03-multi-column: dependencies: @@ -492,10 +493,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/01-basic/04-default-blocks: dependencies: @@ -535,10 +536,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/01-basic/05-removing-default-blocks: dependencies: @@ -578,10 +579,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/01-basic/06-block-manipulation: dependencies: @@ -621,10 +622,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/01-basic/07-selection-blocks: dependencies: @@ -664,10 +665,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/01-basic/08-ariakit: dependencies: @@ -707,10 +708,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/01-basic/09-shadcn: dependencies: @@ -750,7 +751,7 @@ importers: devDependencies: '@tailwindcss/vite': specifier: ^4.1.14 - version: 4.2.2(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 4.2.2(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) '@types/react': specifier: ^19.2.3 version: 19.2.14 @@ -759,10 +760,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/01-basic/10-localization: dependencies: @@ -802,10 +803,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/01-basic/11-custom-placeholder: dependencies: @@ -845,10 +846,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/01-basic/12-multi-editor: dependencies: @@ -888,10 +889,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/01-basic/13-custom-paste-handler: dependencies: @@ -931,10 +932,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/01-basic/14-editor-scrollable: dependencies: @@ -974,10 +975,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/01-basic/15-shadowdom: dependencies: @@ -1017,10 +1018,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/01-basic/16-read-only-editor: dependencies: @@ -1060,10 +1061,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/01-basic/17-no-trailing-block: dependencies: @@ -1103,10 +1104,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/01-basic/testing: dependencies: @@ -1146,10 +1147,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/02-backend/01-file-uploading: dependencies: @@ -1189,10 +1190,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/02-backend/02-saving-loading: dependencies: @@ -1232,10 +1233,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/02-backend/03-s3: dependencies: @@ -1281,10 +1282,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/02-backend/04-rendering-static-documents: dependencies: @@ -1327,10 +1328,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/03-ui-components/01-ui-elements-remove: dependencies: @@ -1370,10 +1371,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/03-ui-components/02-formatting-toolbar-buttons: dependencies: @@ -1413,10 +1414,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/03-ui-components/03-formatting-toolbar-block-type-items: dependencies: @@ -1459,10 +1460,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/03-ui-components/04-side-menu-buttons: dependencies: @@ -1505,10 +1506,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/03-ui-components/05-side-menu-drag-handle-items: dependencies: @@ -1551,10 +1552,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/03-ui-components/06-suggestion-menus-slash-menu-items: dependencies: @@ -1597,10 +1598,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/03-ui-components/07-suggestion-menus-slash-menu-component: dependencies: @@ -1640,10 +1641,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/03-ui-components/08-suggestion-menus-emoji-picker-columns: dependencies: @@ -1683,10 +1684,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/03-ui-components/09-suggestion-menus-emoji-picker-component: dependencies: @@ -1726,10 +1727,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/03-ui-components/10-suggestion-menus-grid-mentions: dependencies: @@ -1769,10 +1770,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/03-ui-components/11-uppy-file-panel: dependencies: @@ -1848,10 +1849,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/03-ui-components/12-static-formatting-toolbar: dependencies: @@ -1891,10 +1892,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/03-ui-components/13-custom-ui: dependencies: @@ -1940,10 +1941,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/03-ui-components/14-experimental-mobile-formatting-toolbar: dependencies: @@ -1983,10 +1984,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/03-ui-components/15-advanced-tables: dependencies: @@ -2026,10 +2027,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/03-ui-components/16-link-toolbar-buttons: dependencies: @@ -2069,10 +2070,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/03-ui-components/17-advanced-tables-2: dependencies: @@ -2112,10 +2113,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/03-ui-components/18-drag-n-drop: dependencies: @@ -2155,10 +2156,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/03-ui-components/19-suggestion-menus-grouping-ordering: dependencies: @@ -2198,10 +2199,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/03-ui-components/20-portal-elements: dependencies: @@ -2241,10 +2242,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/04-theming/01-theming-dom-attributes: dependencies: @@ -2284,10 +2285,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/04-theming/02-changing-font: dependencies: @@ -2327,10 +2328,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/04-theming/03-theming-css: dependencies: @@ -2370,10 +2371,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/04-theming/04-theming-css-variables: dependencies: @@ -2413,10 +2414,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/04-theming/05-theming-css-variables-code: dependencies: @@ -2456,10 +2457,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/04-theming/06-code-block: dependencies: @@ -2502,10 +2503,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/04-theming/07-custom-code-block: dependencies: @@ -2563,10 +2564,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/05-interoperability/01-converting-blocks-to-html: dependencies: @@ -2606,10 +2607,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/05-interoperability/02-converting-blocks-from-html: dependencies: @@ -2649,10 +2650,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/05-interoperability/03-converting-blocks-to-md: dependencies: @@ -2692,10 +2693,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/05-interoperability/04-converting-blocks-from-md: dependencies: @@ -2735,10 +2736,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/05-interoperability/05-converting-blocks-to-pdf: dependencies: @@ -2787,10 +2788,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/05-interoperability/06-converting-blocks-to-docx: dependencies: @@ -2836,10 +2837,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/05-interoperability/07-converting-blocks-to-odt: dependencies: @@ -2885,10 +2886,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/05-interoperability/08-converting-blocks-to-react-email: dependencies: @@ -2934,10 +2935,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/05-interoperability/09-blocks-to-html-static-render: dependencies: @@ -2977,10 +2978,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/05-interoperability/10-static-html-render: dependencies: @@ -3020,10 +3021,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/06-custom-schema/01-alert-block: dependencies: @@ -3066,10 +3067,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/06-custom-schema/02-suggestion-menus-mentions: dependencies: @@ -3109,10 +3110,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/06-custom-schema/03-font-style: dependencies: @@ -3155,10 +3156,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/06-custom-schema/04-pdf-file-block: dependencies: @@ -3201,10 +3202,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/06-custom-schema/05-alert-block-full-ux: dependencies: @@ -3247,10 +3248,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/06-custom-schema/06-toggleable-blocks: dependencies: @@ -3290,10 +3291,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/06-custom-schema/07-configuring-blocks: dependencies: @@ -3333,10 +3334,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/06-custom-schema/08-non-editable-block: dependencies: @@ -3376,10 +3377,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/06-custom-schema/draggable-inline-content: dependencies: @@ -3419,10 +3420,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/06-custom-schema/react-custom-blocks: dependencies: @@ -3462,10 +3463,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/06-custom-schema/react-custom-inline-content: dependencies: @@ -3505,10 +3506,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/06-custom-schema/react-custom-styles: dependencies: @@ -3548,10 +3549,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/07-collaboration/01-partykit: dependencies: @@ -3597,10 +3598,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/07-collaboration/02-liveblocks: dependencies: @@ -3658,10 +3659,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/07-collaboration/03-y-sweet: dependencies: @@ -3704,10 +3705,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/07-collaboration/04-electric-sql: dependencies: @@ -3747,10 +3748,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/07-collaboration/05-comments: dependencies: @@ -3793,10 +3794,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/07-collaboration/06-comments-with-sidebar: dependencies: @@ -3842,10 +3843,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/07-collaboration/07-ghost-writer: dependencies: @@ -3891,10 +3892,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/07-collaboration/08-forking: dependencies: @@ -3940,10 +3941,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/07-collaboration/09-comments-testing: dependencies: @@ -3986,10 +3987,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/07-collaboration/10-versioning: dependencies: @@ -4019,16 +4020,16 @@ importers: version: 9.1.1(react@19.2.5) '@y/protocols': specifier: ^1.0.6-rc.1 - version: 1.0.6-rc.1(@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9)) + version: 1.0.6-rc.1(@y/y@14.0.0-rc.16) '@y/websocket': specifier: ^4.0.0-3 - version: 4.0.0-rc.2(@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9)) + version: 4.0.0-rc.2(@y/y@14.0.0-rc.16) '@y/y': specifier: 14.0.0-rc.16 - version: 14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9) + version: 14.0.0-rc.16 lib0: - specifier: 1.0.0-rc.13 - version: 1.0.0-rc.13(patch_hash=328c50b547222f0e54a7a9f4f70926c0532c006dec4f24d6954635b8c3adb69e) + specifier: 1.0.0-rc.14 + version: 1.0.0-rc.14(patch_hash=e55ee919122bfd99c2418ad2ca66b24bdc0770c01033d31bbec567d195600f20) react: specifier: ^19.2.3 version: 19.2.5 @@ -4047,10 +4048,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/07-collaboration/11-yhub: dependencies: @@ -4077,16 +4078,16 @@ importers: version: 9.1.1(react@19.2.5) '@y/prosemirror': specifier: 2.0.0-2 - version: 2.0.0-2(patch_hash=802334aa5d2410b9fc999d5fb5ffef01650a04e58b59fca24e142c55b3379728)(@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9)))(@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9))(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8) + version: 2.0.0-2(patch_hash=168146d45476a6e2019bd9b140bf068fd17c12fb6b7d282509552826e74740dc)(@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.16))(@y/y@14.0.0-rc.16)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8) '@y/protocols': specifier: ^1.0.6-rc.1 - version: 1.0.6-rc.1(@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9)) + version: 1.0.6-rc.1(@y/y@14.0.0-rc.16) '@y/websocket': specifier: ^4.0.0-rc.2 - version: 4.0.0-rc.2(@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9)) + version: 4.0.0-rc.2(@y/y@14.0.0-rc.16) '@y/y': specifier: 14.0.0-rc.16 - version: 14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9) + version: 14.0.0-rc.16 react: specifier: ^19.2.3 version: 19.2.5 @@ -4102,10 +4103,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/07-collaboration/12-versioning-yjs13: dependencies: @@ -4131,8 +4132,8 @@ importers: specifier: ^9.0.2 version: 9.1.1(react@19.2.5) lib0: - specifier: ^0.2.99 - version: 0.2.117 + specifier: 1.0.0-rc.14 + version: 1.0.0-rc.14(patch_hash=e55ee919122bfd99c2418ad2ca66b24bdc0770c01033d31bbec567d195600f20) react: specifier: ^19.2.3 version: 19.2.5 @@ -4154,10 +4155,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/07-collaboration/13-versioning-yjs14: dependencies: @@ -4184,16 +4185,16 @@ importers: version: 9.1.1(react@19.2.5) '@y/protocols': specifier: ^1.0.6-rc.1 - version: 1.0.6-rc.1(@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9)) + version: 1.0.6-rc.1(@y/y@14.0.0-rc.16) '@y/websocket': specifier: ^4.0.0-3 - version: 4.0.0-rc.2(@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9)) + version: 4.0.0-rc.2(@y/y@14.0.0-rc.16) '@y/y': specifier: 14.0.0-rc.16 - version: 14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9) + version: 14.0.0-rc.16 lib0: - specifier: 1.0.0-rc.13 - version: 1.0.0-rc.13(patch_hash=328c50b547222f0e54a7a9f4f70926c0532c006dec4f24d6954635b8c3adb69e) + specifier: 1.0.0-rc.14 + version: 1.0.0-rc.14(patch_hash=e55ee919122bfd99c2418ad2ca66b24bdc0770c01033d31bbec567d195600f20) react: specifier: ^19.2.3 version: 19.2.5 @@ -4209,10 +4210,65 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) + + examples/07-collaboration/14-multi-doc-versioning: + dependencies: + '@blocknote/ariakit': + specifier: latest + version: link:../../../packages/ariakit + '@blocknote/core': + specifier: latest + version: link:../../../packages/core + '@blocknote/mantine': + specifier: latest + version: link:../../../packages/mantine + '@blocknote/react': + specifier: latest + version: link:../../../packages/react + '@blocknote/shadcn': + specifier: latest + version: link:../../../packages/shadcn + '@mantine/core': + specifier: ^9.0.2 + version: 9.1.1(@mantine/hooks@9.1.1(react@19.2.5))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@mantine/hooks': + specifier: ^9.0.2 + version: 9.1.1(react@19.2.5) + '@y/protocols': + specifier: ^1.0.6-rc.1 + version: 1.0.6-rc.1(@y/y@14.0.0-rc.16) + '@y/websocket': + specifier: ^4.0.0-3 + version: 4.0.0-rc.2(@y/y@14.0.0-rc.16) + '@y/y': + specifier: 14.0.0-rc.16 + version: 14.0.0-rc.16 + lib0: + specifier: 1.0.0-rc.14 + version: 1.0.0-rc.14(patch_hash=e55ee919122bfd99c2418ad2ca66b24bdc0770c01033d31bbec567d195600f20) + react: + specifier: ^19.2.3 + version: 19.2.5 + react-dom: + specifier: ^19.2.3 + version: 19.2.5(react@19.2.5) + devDependencies: + '@types/react': + specifier: ^19.2.3 + version: 19.2.14 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.14) + '@vitejs/plugin-react': + specifier: ^6.0.1 + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) + vite-plus: + specifier: 'catalog:' + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/08-extensions/01-tiptap-arrow-conversion: dependencies: @@ -4255,10 +4311,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/08-extensions/02-versioning: dependencies: @@ -4301,10 +4357,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/09-ai/01-minimal: dependencies: @@ -4350,10 +4406,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/09-ai/02-playground: dependencies: @@ -4399,10 +4455,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/09-ai/03-custom-ai-menu-items: dependencies: @@ -4451,10 +4507,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/09-ai/04-with-collaboration: dependencies: @@ -4506,10 +4562,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/09-ai/05-manual-execution: dependencies: @@ -4561,10 +4617,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/09-ai/06-client-side-transport: dependencies: @@ -4613,10 +4669,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/09-ai/07-server-persistence: dependencies: @@ -4662,10 +4718,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/vanilla-js/react-vanilla-custom-blocks: dependencies: @@ -4705,10 +4761,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/vanilla-js/react-vanilla-custom-inline-content: dependencies: @@ -4748,10 +4804,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) examples/vanilla-js/react-vanilla-custom-styles: dependencies: @@ -4791,10 +4847,10 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) packages/ariakit: dependencies: @@ -4816,7 +4872,7 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) react: specifier: ^19.2.5 version: 19.2.5 @@ -4834,10 +4890,10 @@ importers: version: 5.9.3 vite-plugin-externalize-deps: specifier: ^0.10.0 - version: 0.10.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.10.0(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) packages/code-block: dependencies: @@ -4868,7 +4924,7 @@ importers: version: 5.9.3 vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) optionalDependencies: '@shikijs/types': specifier: ^4 @@ -4917,13 +4973,13 @@ importers: version: 3.22.4 '@y/prosemirror': specifier: 2.0.0-2 - version: 2.0.0-2(patch_hash=802334aa5d2410b9fc999d5fb5ffef01650a04e58b59fca24e142c55b3379728)(@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9)))(@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9))(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8) + version: 2.0.0-2(patch_hash=168146d45476a6e2019bd9b140bf068fd17c12fb6b7d282509552826e74740dc)(@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.16))(@y/y@14.0.0-rc.16)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8) '@y/protocols': specifier: ^1.0.6-rc.1 - version: 1.0.6-rc.1(@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9)) + version: 1.0.6-rc.1(@y/y@14.0.0-rc.16) '@y/y': specifier: 14.0.0-rc.16 - version: 14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9) + version: 14.0.0-rc.16 emoji-mart: specifier: ^5.6.0 version: 5.6.0 @@ -4931,8 +4987,8 @@ importers: specifier: ^3.1.3 version: 3.1.3 lib0: - specifier: 1.0.0-rc.13 - version: 1.0.0-rc.13(patch_hash=328c50b547222f0e54a7a9f4f70926c0532c006dec4f24d6954635b8c3adb69e) + specifier: 1.0.0-rc.14 + version: 1.0.0-rc.14(patch_hash=e55ee919122bfd99c2418ad2ca66b24bdc0770c01033d31bbec567d195600f20) prosemirror-highlight: specifier: ^0.15.1 version: 0.15.1(@shikijs/types@4.0.2)(@types/hast@3.0.4)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-transform@1.12.0)(prosemirror-view@1.41.8) @@ -4966,7 +5022,7 @@ importers: version: 5.9.3 vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) y-prosemirror: specifier: ^1.3.7 version: 1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) @@ -5008,7 +5064,7 @@ importers: version: 5.9.3 vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) packages/mantine: dependencies: @@ -5033,7 +5089,7 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) react: specifier: ^19.2.5 version: 19.2.5 @@ -5054,10 +5110,10 @@ importers: version: 5.9.3 vite-plugin-externalize-deps: specifier: ^0.10.0 - version: 0.10.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.10.0(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) packages/react: dependencies: @@ -5106,7 +5162,7 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) react: specifier: ^19.2.5 version: 19.2.5 @@ -5127,10 +5183,10 @@ importers: version: 5.9.3 vite-plugin-externalize-deps: specifier: ^0.10.0 - version: 0.10.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.10.0(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) optionalDependencies: '@types/use-sync-external-store': specifier: 1.5.0 @@ -5180,7 +5236,7 @@ importers: version: 5.9.3 vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) y-prosemirror: specifier: ^1.3.7 version: 1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30) @@ -5256,7 +5312,7 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) react: specifier: ^19.2.5 version: 19.2.5 @@ -5274,10 +5330,10 @@ importers: version: 5.9.3 vite-plugin-externalize-deps: specifier: ^0.10.0 - version: 0.10.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.10.0(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) packages/xl-ai: dependencies: @@ -5383,7 +5439,7 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) glob: specifier: ^10.5.0 version: 10.5.0 @@ -5392,10 +5448,10 @@ importers: version: 4.0.3 msw: specifier: ^2.11.5 - version: 2.11.5(@types/node@25.6.0)(typescript@5.9.3) + version: 2.11.5(@types/node@25.9.0)(typescript@5.9.3) msw-snapshot: specifier: ^5.3.0 - version: 5.3.0(msw@2.11.5(@types/node@25.6.0)(typescript@5.9.3)) + version: 5.3.0(msw@2.11.5(@types/node@25.9.0)(typescript@5.9.3)) react-icons: specifier: ^5.5.0 version: 5.6.0(react@19.2.5) @@ -5413,10 +5469,10 @@ importers: version: 6.25.0 vite-plugin-externalize-deps: specifier: ^0.10.0 - version: 0.10.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.10.0(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) packages/xl-ai-server: dependencies: @@ -5465,13 +5521,13 @@ importers: version: 6.25.0 vite-node: specifier: ^6.0.0 - version: 6.0.0(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0) + version: 6.0.0(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3) vite-plugin-externalize-deps: specifier: ^0.10.0 - version: 0.10.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.10.0(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) packages/xl-docx-exporter: dependencies: @@ -5520,7 +5576,7 @@ importers: version: 5.9.3 vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) xml-formatter: specifier: ^3.6.7 version: 3.7.0 @@ -5572,7 +5628,7 @@ importers: version: 5.9.3 vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) packages/xl-multi-column: dependencies: @@ -5627,7 +5683,7 @@ importers: version: 5.9.3 vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) packages/xl-odt-exporter: dependencies: @@ -5673,7 +5729,7 @@ importers: version: 5.9.3 vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) xml-formatter: specifier: ^3.6.7 version: 3.7.0 @@ -5734,7 +5790,7 @@ importers: version: 5.9.3 vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) playground: dependencies: @@ -5882,7 +5938,7 @@ importers: devDependencies: '@tailwindcss/vite': specifier: ^4.1.14 - version: 4.2.2(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 4.2.2(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) '@types/react': specifier: ^19.2.3 version: 19.2.14 @@ -5891,7 +5947,7 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitejs/plugin-react': specifier: ^6.0.1 - version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) rimraf: specifier: ^5.0.10 version: 5.0.10 @@ -5906,10 +5962,10 @@ importers: version: 1.4.0 vite-plugin-inspect: specifier: 12.0.0-beta.1 - version: 12.0.0-beta.1(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))(ws@8.20.0) + version: 12.0.0-beta.1(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(ws@8.20.0) vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) shared: dependencies: @@ -5928,7 +5984,7 @@ importers: version: 5.9.3 vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) tests: dependencies: @@ -5956,7 +6012,7 @@ importers: version: 1.60.0 '@tailwindcss/vite': specifier: ^4.1.14 - version: 4.2.2(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 4.2.2(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) '@tiptap/pm': specifier: ^3.0.0 version: 3.22.4 @@ -5971,7 +6027,13 @@ importers: version: 19.2.3(@types/react@19.2.14) '@vitest/ui': specifier: 4.1.5 - version: 4.1.5(vitest@4.1.5) + version: 4.1.5(vitest@4.1.7) + '@y/protocols': + specifier: ^1.0.6-rc.1 + version: 1.0.6-rc.1(@y/y@14.0.0-rc.16) + '@y/y': + specifier: 14.0.0-rc.16 + version: 14.0.0-rc.16 htmlfy: specifier: ^0.6.7 version: 0.6.7 @@ -5989,10 +6051,10 @@ importers: version: 5.0.10 vite-plus: specifier: 'catalog:' - version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + version: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) vitest-browser-react: specifier: ^2.2.0 - version: 2.2.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(vitest@4.1.5) + version: 2.2.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(vitest@4.1.7) packages: @@ -6995,16 +7057,12 @@ packages: peerDependencies: hono: ^4 - '@humanfs/core@0.19.2': - resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} - engines: {node: '>=18.18.0'} - - '@humanfs/node@0.16.8': - resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} - '@humanfs/types@0.15.0': - resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} engines: {node: '>=18.18.0'} '@humanwhocodes/module-importer@1.0.1': @@ -7522,57 +7580,57 @@ packages: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 - '@next/env@16.2.7': - resolution: {integrity: sha512-tMJizPlj6ZYpBMMdK8S0LJufrP4QTdR6pcv9KQ/bVETPAmg0j1mlHE9G2c38UyGHxoBapgwuj7XjbGJ2RcDFOg==} + '@next/env@16.2.9': + resolution: {integrity: sha512-ki5VxxXfzD/9TDe13wyeTKIjQTAwBVpnr8KhRDUr8ltMUq1/NBpWNT5tiPoxiGl+PHM4X2ahSOiPk6iAimIzPg==} - '@next/swc-darwin-arm64@16.2.7': - resolution: {integrity: sha512-vm1EDI/pVaBNNiychmxk3fft+OhQPVD9cIM/tReLZIQ3TfQ4kqI9DwKk00dzuS1ulC7icbrzCFrmRRlk9PfNdw==} + '@next/swc-darwin-arm64@16.2.9': + resolution: {integrity: sha512-HkfxNYUCmcct0Xsqib5KxqMSHV4AHJq857BNRchyBDs4YS19aHzVfn1kDuBYKqLLQBjXgnkIsjV2Kd4d2wzYhw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@16.2.7': - resolution: {integrity: sha512-O3IRSv1ZBL1zs0WrIgefTEcTKFVn+ryxBNe54erJ6KsD+2f/Mmt7g2jOYh8PSBdUwPtKQJuCsTMlZ7tIu2AcsQ==} + '@next/swc-darwin-x64@16.2.9': + resolution: {integrity: sha512-7IAtK4MeybpqRV9GRABWEhJ62mOS+rzWOzOTFie4cSEtm12xsoOMJRcECoZx3FHPzFAqN/IJtHqWAFOLfl152w==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@16.2.7': - resolution: {integrity: sha512-Re6PZtjBDd0aMU+VcZcC/PrIvj4WhrjDYtMhhCVQamWN4L90EVP0pcEOBQD25prSlw7OzNw5QpHLWMilRLsRNw==} + '@next/swc-linux-arm64-gnu@16.2.9': + resolution: {integrity: sha512-hBD75iWpUtkL9SmQmcRhmLomn9jgkPzCEkbOcLgHymPEKzv+6ONy13RRiIEz/iEObjkS2Jlb5gYS2XGoS3X4rw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] - '@next/swc-linux-arm64-musl@16.2.7': - resolution: {integrity: sha512-qyogG9QtBzWxgJfeGBvOEHI3851gTfCF3wLZ5RDLTBJGAmE9p1qDwKCOdrBrvBzRvYDT+gUDp72pzlSEfAXgNA==} + '@next/swc-linux-arm64-musl@16.2.9': + resolution: {integrity: sha512-qZTI3pf9SGc/obr8NkQAekBxmp1QK+kVm+VAf3BALLfFAj+1kUhkTxmrWpVos9R/UYIA8AWX2p6cGI5WdwzVUA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [musl] - '@next/swc-linux-x64-gnu@16.2.7': - resolution: {integrity: sha512-Vhe4ZDuBpmMogrGi5D4R2Kq4JAQlj6+wvgaFYy31zfES0zPmt6TLA+cuYpM/OLrPZjo2MYQTHVqNUSCR6+fDZQ==} + '@next/swc-linux-x64-gnu@16.2.9': + resolution: {integrity: sha512-xm0HfRNX+UkH4R3c18ynswjj5o5uEj/7iI9p9omdtTSIsRCzQqkGMA+10nzJ4EHnYC3as65IMhbbl5fWRUWHYg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] - '@next/swc-linux-x64-musl@16.2.7': - resolution: {integrity: sha512-srvian89JahFLw1YLBEuhvPJ0DO5lpUeJQMXy4xYo7g628ZlNgXdNkqoxSAv9OYrBfByh6vxISMwW/mRbzCY+g==} + '@next/swc-linux-x64-musl@16.2.9': + resolution: {integrity: sha512-QumimHkGEG6vM3PfEDWKyKen03NcqLOkeKB1EfcPe7VxzmEiCa4jNnMyBn/US5zcd/VE1CI+O8Ovb3lfjVHfGw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] - '@next/swc-win32-arm64-msvc@16.2.7': - resolution: {integrity: sha512-GX3wvLpULFuRFJzwHaKfm7QZJ18F4ZSuxlPJ96BoBglCzBmdSjyeBKF+ZhWhvL/ckxNfLnNa7bsObO2ipYpszw==} + '@next/swc-win32-arm64-msvc@16.2.9': + resolution: {integrity: sha512-hzQpKZvw8rAwI6A2uQh6SacCSvNAXaIkPNsWwzqqfRiIMiXMfH936skDhz1OO6KpvdKkJrgHHtqQOq5PIXOvdQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@16.2.7': - resolution: {integrity: sha512-J4WlM72NMk076Qsg0jTdK3SNXatlSdnjW7L7oNGLst1tAGjHrJh/FYi+pw9wyIjEtGRKDNzD0zuiY16oWYWVaw==} + '@next/swc-win32-x64-msvc@16.2.9': + resolution: {integrity: sha512-qr2VL3Ce5QrwgO2yh1ujSBawrimjVKX8FGF/cOynmdYKJY0BdHpGVNIRK1tqONB10Vkm25Ub1BD2bkjWs4+96w==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -10149,6 +10207,9 @@ packages: '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -10224,6 +10285,9 @@ packages: '@types/node@25.6.0': resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} + '@types/node@25.9.0': + resolution: {integrity: sha512-AOQwYUNolgy3VosiRqXrACUXTN8nJUtPl7FJXMqZVyxiiCLhQuG3jXKvCS1ALr+Y2OmZhzzLVlYPEqJaiqkaJQ==} + '@types/nodemailer@7.0.11': resolution: {integrity: sha512-E+U4RzR2dKrx+u3N4DlsmLaDC6mMZOM/TPROxA0UAPiTgI0y4CEFBmZE+coGWTjakDriRsXG368lNk1u9Q0a2g==} @@ -10455,11 +10519,11 @@ packages: babel-plugin-react-compiler: optional: true - '@vitest/expect@4.1.5': - resolution: {integrity: sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==} + '@vitest/expect@4.1.7': + resolution: {integrity: sha512-1R+tw0ortHEbZDGMymm+pN7/AFQ/RkFFdtd7EN+VBpynKmLbP8A3rpEXdshBJ7+8hQ9zBJh/i1s0yKNtxAnU7w==} - '@vitest/mocker@4.1.5': - resolution: {integrity: sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==} + '@vitest/mocker@4.1.7': + resolution: {integrity: sha512-vY7nuamKgfvpA1Koa3oYIw/k7D6kZnpGyNMZW8loow2bsBYla1TFdqTaXncWdRn4pgwNs+90RhnXhJScDwQeJA==} peerDependencies: msw: ^2.4.9 vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -10472,23 +10536,29 @@ packages: '@vitest/pretty-format@4.1.5': resolution: {integrity: sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==} - '@vitest/runner@4.1.5': - resolution: {integrity: sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==} + '@vitest/pretty-format@4.1.7': + resolution: {integrity: sha512-umgCarTOYQWIaDMvGDRZij+6b9oVeLIyJzfN+AS88e0ZOU3QTgNNSTtjQOpcvWr3np1N0j4WgZj+sb3oYBDscw==} - '@vitest/snapshot@4.1.5': - resolution: {integrity: sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==} + '@vitest/runner@4.1.7': + resolution: {integrity: sha512-BapjmAQ2aI78WdMEfeUWivnfVzB+VPGwWRQcJE0OUq7qEeEcBsCSf+0T5iREBNE5nBb4wA5Ya0W6IA+sghdEFw==} - '@vitest/spy@4.1.5': - resolution: {integrity: sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==} + '@vitest/snapshot@4.1.7': + resolution: {integrity: sha512-ZacLzja+TmJeZ1h14xW2FB/WpeimUD3haBXQPyJqxvo8jQTmfeA8zv58mtjN2C7EHXZDYVcVYdYmAxjkWVvKCw==} + + '@vitest/spy@4.1.7': + resolution: {integrity: sha512-kbkI5LMWakyuTIvs6fUJ5qdIVb1XVKsYJAT4OJ938cHMROYMSfmoQdZy0aaAnjbbc8F61vkoTqz/Az+/HiIu5Q==} '@vitest/ui@4.1.5': resolution: {integrity: sha512-3Z9HNFiV0IF1fk0JPiK+7kE1GcaIPefQQIBYur6PM5yFIq6agys3uqP/0t966e1wXfmjbRCHDe7qW236Xjwnag==} peerDependencies: - vitest: 4.1.5 + vitest: 4.1.7 '@vitest/utils@4.1.5': resolution: {integrity: sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==} + '@vitest/utils@4.1.7': + resolution: {integrity: sha512-T532WBu791cBxJlCl6SO+J14l81DQx6uQHm1bQbmCDY7nqlEIgkza/UFnSBNaUtSf41unldDFjdOBYEQC4b5Hw==} + '@voidzero-dev/vite-plus-core@0.1.24': resolution: {integrity: sha512-iXPGBABnQnrDMx89H6MOCGcTZp+QW+3rY4YMVKdE6ydchSvPk2O3MI2vgaRVfOtWJ2IjnxSnf1n2yjP67ZBRFQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -10809,8 +10879,8 @@ packages: peerDependencies: ajv: ^8.8.2 - ajv@6.15.0: - resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + ajv@6.14.0: + resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} ajv@8.18.0: resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} @@ -10931,8 +11001,8 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - axios@1.15.0: - resolution: {integrity: sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q==} + axios@1.16.1: + resolution: {integrity: sha512-caYkukvroVPO8KrzuJEb50Hm07KwfBZPEC3VeFHTsqWHvKTsy54hjJz9BS/cdaypROE2rH6xvm9mHX4fgWkr3A==} babel-plugin-macros@3.1.0: resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==} @@ -10987,7 +11057,7 @@ packages: react-dom: ^18.0.0 || ^19.0.0 solid-js: ^1.0.0 svelte: ^4.0.0 || ^5.0.0 - vitest: ^2.0.0 || ^3.0.0 || ^4.0.0 + vitest: 4.1.7 vue: ^3.0.0 peerDependenciesMeta: '@lynx-js/react': @@ -11110,8 +11180,8 @@ packages: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} - call-bind@1.0.9: - resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} engines: {node: '>= 0.4'} call-bound@1.0.4: @@ -11657,8 +11727,8 @@ packages: resolution: {integrity: sha512-Qohcme7V1inbAfvjItgw0EaxVX5q2rdVEZHRBrEQdRZTssLDGsL8Lwrznl8oQ/6kuTJONLaDcGjkNP247XEhcA==} engines: {node: '>=10.13.0'} - enhanced-resolve@5.21.0: - resolution: {integrity: sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA==} + enhanced-resolve@5.21.4: + resolution: {integrity: sha512-wE4fDO8OjJhrPFH69HUQStq5oKvGRTNXEyW+k5C/pUQLASSsTu7obd2V3GvCDgPcY9AWjhJ4jz9Kh7iRvrxhJg==} engines: {node: '>=10.13.0'} entities@4.5.0: @@ -11683,8 +11753,8 @@ packages: error-stack-parser-es@1.0.5: resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} - es-abstract@1.24.2: - resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==} + es-abstract@1.24.1: + resolution: {integrity: sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw==} engines: {node: '>= 0.4'} es-define-property@1.0.1: @@ -11930,9 +12000,6 @@ packages: fast-sha256@1.3.0: resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==} - fast-uri@3.1.0: - resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - fast-uri@3.1.2: resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} @@ -12670,9 +12737,6 @@ packages: isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - isomorphic.js@0.2.5: - resolution: {integrity: sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==} - jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} @@ -12812,8 +12876,8 @@ packages: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} - kysely@0.28.15: - resolution: {integrity: sha512-r2clcf7HLWvDXaVUEvQymXJY4i3bSOIV3xsL/Upy3ZfSv5HeKsk9tsqbBptLvth5qHEIhxeHTA2jNLyQABkLBA==} + kysely@0.28.17: + resolution: {integrity: sha512-nbD8lB9EB3wNdMhOCdx5Li8DxnLbvKByylRLcJ1h+4SkrowVeECAyZlyiKMThF7xFdRz0jSQ2MoJr+wXux2y0Q==} engines: {node: '>=20.0.0'} leac@0.6.0: @@ -12869,13 +12933,8 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - lib0@0.2.117: - resolution: {integrity: sha512-DeXj9X5xDCjgKLU/7RR+/HQEVzuuEUiwldwOGsHK/sfAfELGWEyTcf0x+uOvCvK3O2zPmZePXWL85vtia6GyZw==} - engines: {node: '>=16'} - hasBin: true - - lib0@1.0.0-rc.13: - resolution: {integrity: sha512-4y73dAr8BHgIwQlBxJe2+QX4bFmPxS/t9SJQfJgH9sn/Zv/TisvWqNfYgqDIVVFevZ6yTW1ShuT08Ox8nTEmxg==} + lib0@1.0.0-rc.14: + resolution: {integrity: sha512-zXdJpWHTbkKGw7MsjillED5+CTl44I5UeZr2MViWFVhoAsoyNJmQGG5lm9ecnI2ZeV5tGhj47WGN2V+tY42LGg==} engines: {node: '>=22'} hasBin: true @@ -13429,8 +13488,8 @@ packages: next-validate-link@1.6.4: resolution: {integrity: sha512-wR/VKyJlaTbUT5k1uujEnk6O616YtWGt52s9FJa3tRCQ2qL2TGFTAklXJ0QdX1NTAEeP6rGFOTtHEDwveFrc2g==} - next@16.2.7: - resolution: {integrity: sha512-eMJxgjRzBaj3olkP4cBamHDXL79A8FC6u1GcsO1D1Tsx8bw/LLXUJCaoajVxtnhD3A1IJqIT8IcRJjgBIPJq4w==} + next@16.2.9: + resolution: {integrity: sha512-MEOJiq/UvuezAdqVSceHbqDgZt1kDw2tpGVOlsdIoJsQdbN2JY2hpVG4xnXGkbdJUOEWhnRfiu/O4Hpc9Juwww==} engines: {node: '>=20.9.0'} hasBin: true peerDependencies: @@ -14375,8 +14434,8 @@ packages: rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} - safe-array-concat@1.1.4: - resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} safe-buffer@5.1.2: @@ -14485,8 +14544,8 @@ packages: resolution: {integrity: sha512-eAVKTMedR5ckPo4xne/PjYQYrU3qx78gtJZ+sHlXEg5IHhhoQhMfZVzetTYuaJS0L2Ef3AcCRzCHV8T0WI6nIQ==} engines: {node: '>=20'} - side-channel-list@1.0.1: - resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} engines: {node: '>= 0.4'} side-channel-map@1.0.1: @@ -14788,24 +14847,51 @@ packages: engines: {node: '>=10'} deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - terser-webpack-plugin@5.5.0: - resolution: {integrity: sha512-UYhptBwhWvfIjKd/UuFo6D8uq9xpGLDK+z8EDsj/zWhrTaH34cKEbrkMKfV5YWqGBvAYA3tlzZbs2R+qYrbQJA==} + terser-webpack-plugin@5.6.0: + resolution: {integrity: sha512-Eum+5ajkaOhf5KbM26osvv21kLD7BaGqQ1UA4Ami4arYwylmGUQTgHFpHDdmJod1q4QXa66p0to/FBKID+J1vA==} engines: {node: '>= 10.13.0'} peerDependencies: + '@minify-html/node': '*' '@swc/core': '*' + '@swc/css': '*' + '@swc/html': '*' + clean-css: '*' + cssnano: '*' + csso: '*' esbuild: '*' + html-minifier-terser: '*' + lightningcss: '*' + postcss: '*' uglify-js: '*' webpack: ^5.1.0 peerDependenciesMeta: + '@minify-html/node': + optional: true '@swc/core': optional: true + '@swc/css': + optional: true + '@swc/html': + optional: true + clean-css: + optional: true + cssnano: + optional: true + csso: + optional: true esbuild: optional: true + html-minifier-terser: + optional: true + lightningcss: + optional: true + postcss: + optional: true uglify-js: optional: true - terser@5.46.2: - resolution: {integrity: sha512-uxfo9fPcSgLDYob/w1FuL0c99MWiJDnv+5qXSQc5+Ki5NjVNsYi66INnMFBjf6uFz6OnX12piJQPF4IpjJTNTw==} + terser@5.47.1: + resolution: {integrity: sha512-tPbLXTI6ohPASb/1YViL428oEHu6/qv1OxqYnfaonVCFHqx4+wCd95pHrQWsL5X4pl90CTyW9piSAsS2L0VoMw==} engines: {node: '>=10'} hasBin: true @@ -15011,6 +15097,9 @@ packages: undici-types@7.19.2: resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==} + undici-types@7.24.6: + resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} + undici@6.25.0: resolution: {integrity: sha512-ZgpWDC5gmNiuY9CnLVXEH8rl50xhRCuLNA97fAUnKi8RRuV4E6KG31pDTsLVUKnohJE0I3XDrTeEydAXRw47xg==} engines: {node: '>=18.17'} @@ -15201,7 +15290,7 @@ packages: '@types/react-dom': ^18.0.0 || ^19.0.0 react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 - vitest: ^4.0.0 + vitest: 4.1.7 peerDependenciesMeta: '@types/react': optional: true @@ -15211,20 +15300,20 @@ packages: vitest-tsconfig-paths@3.4.1: resolution: {integrity: sha512-CnRpA/jcqgZfnkk0yvwFW92UmIpf03wX/wLiQBNWAcOG7nv6Sdz3GsPESAMEqbVy8kHBoWB3XeNamu6PUrFZLA==} - vitest@4.1.5: - resolution: {integrity: sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==} + vitest@4.1.7: + resolution: {integrity: sha512-flYyaFd2CgoCoU+0UKt3pxksgC+S02iTDN0n3LtqaMeXsI9SBcdNujc2k0DeFLzUn/0k538yNjOSdwgCqcrwJA==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.1.5 - '@vitest/browser-preview': 4.1.5 - '@vitest/browser-webdriverio': 4.1.5 - '@vitest/coverage-istanbul': 4.1.5 - '@vitest/coverage-v8': 4.1.5 - '@vitest/ui': 4.1.5 + '@vitest/browser-playwright': 4.1.7 + '@vitest/browser-preview': 4.1.7 + '@vitest/browser-webdriverio': 4.1.7 + '@vitest/coverage-istanbul': 4.1.7 + '@vitest/coverage-v8': 4.1.7 + '@vitest/ui': 4.1.7 happy-dom: '*' jsdom: '*' vite: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -15379,8 +15468,8 @@ packages: wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - ws@6.2.4: - resolution: {integrity: sha512-PNIUUyLI5YpkJZj60YBzX1o0ByQ4ovvfmq9N/Kig/PAYbVlGyz4R6G0SEWrD0O9acc0sT2+IdMBVLFv8FSi0Nw==} + ws@6.2.3: + resolution: {integrity: sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==} peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ^5.0.2 @@ -15495,6 +15584,11 @@ packages: resolution: {integrity: sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==} engines: {node: '>= 6'} + yaml@2.8.3: + resolution: {integrity: sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==} + engines: {node: '>= 14.6'} + hasBin: true + yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} @@ -16250,20 +16344,20 @@ snapshots: '@base2/pretty-print-object@1.0.2': {} - '@better-auth/core@1.4.22(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.15)(nanostores@1.2.0)': + '@better-auth/core@1.4.22(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.17)(nanostores@1.2.0)': dependencies: '@better-auth/utils': 0.3.0 '@better-fetch/fetch': 1.1.21 '@standard-schema/spec': 1.1.0 better-call: 1.1.8(zod@4.3.6) jose: 6.2.2 - kysely: 0.28.15 + kysely: 0.28.17 nanostores: 1.2.0 zod: 4.3.6 - '@better-auth/telemetry@1.4.22(@better-auth/core@1.4.22(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.15)(nanostores@1.2.0))': + '@better-auth/telemetry@1.4.22(@better-auth/core@1.4.22(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.17)(nanostores@1.2.0))': dependencies: - '@better-auth/core': 1.4.22(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.15)(nanostores@1.2.0) + '@better-auth/core': 1.4.22(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.17)(nanostores@1.2.0) '@better-auth/utils': 0.3.0 '@better-fetch/fetch': 1.1.21 @@ -16612,7 +16706,7 @@ snapshots: '@eslint/eslintrc@3.3.5': dependencies: - ajv: 6.15.0 + ajv: 6.14.0 debug: 4.4.3 espree: 10.4.0 globals: 14.0.0 @@ -16678,12 +16772,12 @@ snapshots: dependencies: '@formatjs/fast-memoize': 3.1.1 - '@fumadocs/base-ui@16.5.0(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tailwindcss@4.2.2)': + '@fumadocs/base-ui@16.5.0(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tailwindcss@4.2.2)': dependencies: '@base-ui/react': 1.3.0(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) - '@fumadocs/ui': 16.5.0(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tailwindcss@4.2.2) + '@fumadocs/ui': 16.5.0(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tailwindcss@4.2.2) class-variance-authority: 0.7.1 - fumadocs-core: 16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6) + fumadocs-core: 16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6) lucide-react: 0.563.0(react@19.2.5) next-themes: 0.4.6(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react: 19.2.5 @@ -16692,12 +16786,12 @@ snapshots: scroll-into-view-if-needed: 3.1.0 optionalDependencies: '@types/react': 19.2.14 - next: 16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + next: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) tailwindcss: 4.2.2 - '@fumadocs/ui@16.5.0(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tailwindcss@4.2.2)': + '@fumadocs/ui@16.5.0(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tailwindcss@4.2.2)': dependencies: - fumadocs-core: 16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6) + fumadocs-core: 16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6) next-themes: 0.4.6(react-dom@19.2.5(react@19.2.5))(react@19.2.5) postcss-selector-parser: 7.1.1 react: 19.2.5 @@ -16705,7 +16799,7 @@ snapshots: tailwind-merge: 3.5.0 optionalDependencies: '@types/react': 19.2.14 - next: 16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + next: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) tailwindcss: 4.2.2 '@handlewithcare/prosemirror-inputrules@0.1.4(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)': @@ -16743,18 +16837,13 @@ snapshots: dependencies: hono: 4.12.14 - '@humanfs/core@0.19.2': - dependencies: - '@humanfs/types': 0.15.0 + '@humanfs/core@0.19.1': {} - '@humanfs/node@0.16.8': + '@humanfs/node@0.16.7': dependencies: - '@humanfs/core': 0.19.2 - '@humanfs/types': 0.15.0 + '@humanfs/core': 0.19.1 '@humanwhocodes/retry': 0.4.3 - '@humanfs/types@0.15.0': {} - '@humanwhocodes/module-importer@1.0.1': {} '@humanwhocodes/retry@0.4.3': {} @@ -16874,12 +16963,12 @@ snapshots: '@types/node': 25.5.0 optional: true - '@inquirer/confirm@5.1.21(@types/node@25.6.0)': + '@inquirer/confirm@5.1.21(@types/node@25.9.0)': dependencies: - '@inquirer/core': 10.3.2(@types/node@25.6.0) - '@inquirer/type': 3.0.10(@types/node@25.6.0) + '@inquirer/core': 10.3.2(@types/node@25.9.0) + '@inquirer/type': 3.0.10(@types/node@25.9.0) optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.9.0 '@inquirer/core@10.3.2(@types/node@20.19.37)': dependencies: @@ -16909,18 +16998,18 @@ snapshots: '@types/node': 25.5.0 optional: true - '@inquirer/core@10.3.2(@types/node@25.6.0)': + '@inquirer/core@10.3.2(@types/node@25.9.0)': dependencies: '@inquirer/ansi': 1.0.2 '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@25.6.0) + '@inquirer/type': 3.0.10(@types/node@25.9.0) cli-width: 4.1.0 mute-stream: 2.0.0 signal-exit: 4.1.0 wrap-ansi: 6.2.0 yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.9.0 '@inquirer/figures@1.0.15': {} @@ -16934,9 +17023,9 @@ snapshots: '@types/node': 25.5.0 optional: true - '@inquirer/type@3.0.10(@types/node@25.6.0)': + '@inquirer/type@3.0.10(@types/node@25.9.0)': optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.9.0 '@isaacs/cliui@8.0.2': dependencies: @@ -17213,7 +17302,7 @@ snapshots: '@liveblocks/core': 3.19.5(@types/json-schema@7.0.15) '@noble/hashes': 1.8.0 js-base64: 3.7.8 - lib0: 0.2.117 + lib0: 1.0.0-rc.14(patch_hash=e55ee919122bfd99c2418ad2ca66b24bdc0770c01033d31bbec567d195600f20) y-indexeddb: 9.0.12(yjs@13.6.30) yjs: 13.6.30 transitivePeerDependencies: @@ -17396,30 +17485,30 @@ snapshots: '@tybys/wasm-util': 0.10.1 optional: true - '@next/env@16.2.7': {} + '@next/env@16.2.9': {} - '@next/swc-darwin-arm64@16.2.7': + '@next/swc-darwin-arm64@16.2.9': optional: true - '@next/swc-darwin-x64@16.2.7': + '@next/swc-darwin-x64@16.2.9': optional: true - '@next/swc-linux-arm64-gnu@16.2.7': + '@next/swc-linux-arm64-gnu@16.2.9': optional: true - '@next/swc-linux-arm64-musl@16.2.7': + '@next/swc-linux-arm64-musl@16.2.9': optional: true - '@next/swc-linux-x64-gnu@16.2.7': + '@next/swc-linux-x64-gnu@16.2.9': optional: true - '@next/swc-linux-x64-musl@16.2.7': + '@next/swc-linux-x64-musl@16.2.9': optional: true - '@next/swc-win32-arm64-msvc@16.2.7': + '@next/swc-win32-arm64-msvc@16.2.9': optional: true - '@next/swc-win32-x64-msvc@16.2.7': + '@next/swc-win32-x64-msvc@16.2.9': optional: true '@noble/ciphers@2.1.1': {} @@ -17851,11 +17940,11 @@ snapshots: dependencies: playwright: 1.60.0 - '@polar-sh/better-auth@1.8.3(@polar-sh/sdk@0.42.5)(@stripe/react-stripe-js@4.0.2(@stripe/stripe-js@7.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@stripe/stripe-js@7.9.0)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(better-auth@1.4.22(better-sqlite3@12.8.0)(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(pg@8.20.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(vitest@4.1.5))(react-dom@19.2.5(react@19.2.5))(react-is@19.2.4)(react@19.2.5)(redux@5.0.1)(zod@4.3.6)': + '@polar-sh/better-auth@1.8.3(@polar-sh/sdk@0.42.5)(@stripe/react-stripe-js@4.0.2(@stripe/stripe-js@7.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@stripe/stripe-js@7.9.0)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(better-auth@1.4.22(better-sqlite3@12.8.0)(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(pg@8.20.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(msw@2.11.5(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))))(react-dom@19.2.5(react@19.2.5))(react-is@19.2.4)(react@19.2.5)(redux@5.0.1)(zod@4.3.6)': dependencies: '@polar-sh/checkout': 0.2.0(@stripe/react-stripe-js@4.0.2(@stripe/stripe-js@7.9.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(@stripe/stripe-js@7.9.0)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react-is@19.2.4)(react@19.2.5)(redux@5.0.1) '@polar-sh/sdk': 0.42.5 - better-auth: 1.4.22(better-sqlite3@12.8.0)(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(pg@8.20.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(vitest@4.1.5) + better-auth: 1.4.22(better-sqlite3@12.8.0)(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(pg@8.20.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(msw@2.11.5(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))) zod: 4.3.6 transitivePeerDependencies: - '@stripe/react-stripe-js' @@ -19224,7 +19313,7 @@ snapshots: '@sentry/core@10.47.0': {} - '@sentry/nextjs@10.47.0(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)(webpack@5.105.4(esbuild@0.27.5))': + '@sentry/nextjs@10.47.0(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)(webpack@5.105.4(esbuild@0.27.5)(postcss@8.5.14))': dependencies: '@opentelemetry/api': 1.9.1 '@opentelemetry/semantic-conventions': 1.40.0 @@ -19236,8 +19325,8 @@ snapshots: '@sentry/opentelemetry': 10.47.0(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.6.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) '@sentry/react': 10.47.0(react@19.2.5) '@sentry/vercel-edge': 10.47.0 - '@sentry/webpack-plugin': 5.1.1(webpack@5.105.4(esbuild@0.27.5)) - next: 16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + '@sentry/webpack-plugin': 5.1.1(webpack@5.105.4(esbuild@0.27.5)(postcss@8.5.14)) + next: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) rollup: 4.60.1 stacktrace-parser: 0.1.11 transitivePeerDependencies: @@ -19326,11 +19415,11 @@ snapshots: '@opentelemetry/resources': 2.6.1(@opentelemetry/api@1.9.1) '@sentry/core': 10.47.0 - '@sentry/webpack-plugin@5.1.1(webpack@5.105.4(esbuild@0.27.5))': + '@sentry/webpack-plugin@5.1.1(webpack@5.105.4(esbuild@0.27.5)(postcss@8.5.14))': dependencies: '@sentry/bundler-plugin-core': 5.1.1 uuid: 9.0.1 - webpack: 5.105.4(esbuild@0.27.5) + webpack: 5.105.4(esbuild@0.27.5)(postcss@8.5.14) transitivePeerDependencies: - encoding - supports-color @@ -19864,19 +19953,19 @@ snapshots: postcss: 8.5.14 tailwindcss: 4.2.2 - '@tailwindcss/vite@4.2.2(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))': + '@tailwindcss/vite@4.2.2(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@tailwindcss/node': 4.2.2 '@tailwindcss/oxide': 4.2.2 tailwindcss: 4.2.2 - vite: 8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3) - '@tailwindcss/vite@4.2.2(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))': + '@tailwindcss/vite@4.2.2(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@tailwindcss/node': 4.2.2 '@tailwindcss/oxide': 4.2.2 tailwindcss: 4.2.2 - vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3) '@tanstack/react-store@0.7.7(react-dom@19.2.5(react@19.2.5))(react@19.2.5)': dependencies: @@ -20067,11 +20156,11 @@ snapshots: '@types/eslint-scope@3.7.7': dependencies: '@types/eslint': 9.6.1 - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/eslint@9.6.1': dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/json-schema': 7.0.15 '@types/estree-jsx@1.0.5': @@ -20080,6 +20169,8 @@ snapshots: '@types/estree@1.0.8': {} + '@types/estree@1.0.9': {} + '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.3 @@ -20171,6 +20262,10 @@ snapshots: dependencies: undici-types: 7.19.2 + '@types/node@25.9.0': + dependencies: + undici-types: 7.24.6 + '@types/nodemailer@7.0.11': dependencies: '@types/node': 25.5.0 @@ -20378,19 +20473,19 @@ snapshots: '@uppy/core': 3.13.1 '@uppy/utils': 5.9.0 - '@vercel/analytics@1.6.1(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)': + '@vercel/analytics@1.6.1(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)': optionalDependencies: - next: 16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + next: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react: 19.2.5 '@vercel/oidc@3.0.5': {} - '@vitejs/devtools-kit@0.1.13(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))(ws@8.20.0)': + '@vitejs/devtools-kit@0.1.13(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(ws@8.20.0)': dependencies: '@vitejs/devtools-rpc': 0.1.13(typescript@5.9.3)(ws@8.20.0) birpc: 4.0.0 ohash: 2.0.11 - vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - typescript - ws @@ -20407,59 +20502,64 @@ snapshots: transitivePeerDependencies: - typescript - '@vitejs/plugin-react@6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))': + '@vitejs/plugin-react@6.0.1(babel-plugin-react-compiler@1.0.0)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: '@rolldown/pluginutils': 1.0.0-rc.7 - vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3) optionalDependencies: babel-plugin-react-compiler: 1.0.0 - '@vitest/expect@4.1.5': + '@vitest/expect@4.1.7': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.1.5 - '@vitest/utils': 4.1.5 + '@vitest/spy': 4.1.7 + '@vitest/utils': 4.1.7 chai: 6.2.2 tinyrainbow: 3.1.0 - '@vitest/mocker@4.1.5(msw@2.11.5(@types/node@20.19.37)(typescript@5.9.3))(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))': + '@vitest/mocker@4.1.7(msw@2.11.5(@types/node@20.19.37)(typescript@5.9.3))(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: - '@vitest/spy': 4.1.5 + '@vitest/spy': 4.1.7 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 2.11.5(@types/node@20.19.37)(typescript@5.9.3) - vite: 8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3) - '@vitest/mocker@4.1.5(msw@2.11.5(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))': + '@vitest/mocker@4.1.7(msw@2.11.5(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))': dependencies: - '@vitest/spy': 4.1.5 + '@vitest/spy': 4.1.7 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: msw: 2.11.5(@types/node@25.5.0)(typescript@5.9.3) - vite: 8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3) + optional: true '@vitest/pretty-format@4.1.5': dependencies: tinyrainbow: 3.1.0 - '@vitest/runner@4.1.5': + '@vitest/pretty-format@4.1.7': dependencies: - '@vitest/utils': 4.1.5 + tinyrainbow: 3.1.0 + + '@vitest/runner@4.1.7': + dependencies: + '@vitest/utils': 4.1.7 pathe: 2.0.3 - '@vitest/snapshot@4.1.5': + '@vitest/snapshot@4.1.7': dependencies: - '@vitest/pretty-format': 4.1.5 - '@vitest/utils': 4.1.5 + '@vitest/pretty-format': 4.1.7 + '@vitest/utils': 4.1.7 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.1.5': {} + '@vitest/spy@4.1.7': {} - '@vitest/ui@4.1.5(vitest@4.1.5)': + '@vitest/ui@4.1.5(vitest@4.1.7)': dependencies: '@vitest/utils': 4.1.5 fflate: 0.8.3 @@ -20468,7 +20568,7 @@ snapshots: sirv: 3.0.2 tinyglobby: 0.2.16 tinyrainbow: 3.1.0 - vitest: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(@vitest/ui@4.1.5)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(msw@2.11.5(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + vitest: 4.1.7(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(msw@2.11.5(@types/node@20.19.37)(typescript@5.9.3))(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) '@vitest/utils@4.1.5': dependencies: @@ -20476,7 +20576,13 @@ snapshots: convert-source-map: 2.0.0 tinyrainbow: 3.1.0 - '@voidzero-dev/vite-plus-core@0.1.24(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)': + '@vitest/utils@4.1.7': + dependencies: + '@vitest/pretty-format': 4.1.7 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 + + '@voidzero-dev/vite-plus-core@0.1.24(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': dependencies: '@oxc-project/runtime': 0.133.0 '@oxc-project/types': 0.133.0 @@ -20487,11 +20593,12 @@ snapshots: esbuild: 0.27.5 fsevents: 2.3.3 jiti: 2.6.1 - terser: 5.46.2 + terser: 5.47.1 tsx: 4.21.0 typescript: 5.9.3 + yaml: 2.8.3 - '@voidzero-dev/vite-plus-core@0.1.24(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)': + '@voidzero-dev/vite-plus-core@0.1.24(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': dependencies: '@oxc-project/runtime': 0.133.0 '@oxc-project/types': 0.133.0 @@ -20502,24 +20609,26 @@ snapshots: esbuild: 0.27.5 fsevents: 2.3.3 jiti: 2.6.1 - terser: 5.46.2 + terser: 5.47.1 tsx: 4.21.0 typescript: 5.9.3 + yaml: 2.8.3 - '@voidzero-dev/vite-plus-core@0.1.24(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)': + '@voidzero-dev/vite-plus-core@0.1.24(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3)': dependencies: '@oxc-project/runtime': 0.133.0 '@oxc-project/types': 0.133.0 lightningcss: 1.32.0 postcss: 8.5.14 optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.9.0 esbuild: 0.27.5 fsevents: 2.3.3 jiti: 2.6.1 - terser: 5.46.2 + terser: 5.47.1 tsx: 4.21.0 typescript: 5.9.3 + yaml: 2.8.3 '@voidzero-dev/vite-plus-darwin-arm64@0.1.24': optional: true @@ -20539,11 +20648,11 @@ snapshots: '@voidzero-dev/vite-plus-linux-x64-musl@0.1.24': optional: true - '@voidzero-dev/vite-plus-test@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))': + '@voidzero-dev/vite-plus-test@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@voidzero-dev/vite-plus-core': 0.1.24(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3) + '@voidzero-dev/vite-plus-core': 0.1.24(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) es-module-lexer: 1.7.0 obug: 2.1.1 pixelmatch: 7.2.0 @@ -20553,12 +20662,12 @@ snapshots: tinybench: 2.9.0 tinyexec: 1.0.4 tinyglobby: 0.2.16 - vite: 8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3) ws: 8.20.0 optionalDependencies: '@opentelemetry/api': 1.9.1 '@types/node': 20.19.37 - '@vitest/ui': 4.1.5(vitest@4.1.5) + '@vitest/ui': 4.1.5(vitest@4.1.7) jsdom: 29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0) transitivePeerDependencies: - '@arethetypeswrong/core' @@ -20582,11 +20691,11 @@ snapshots: - utf-8-validate - yaml - '@voidzero-dev/vite-plus-test@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))': + '@voidzero-dev/vite-plus-test@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@voidzero-dev/vite-plus-core': 0.1.24(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3) + '@voidzero-dev/vite-plus-core': 0.1.24(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) es-module-lexer: 1.7.0 obug: 2.1.1 pixelmatch: 7.2.0 @@ -20596,7 +20705,7 @@ snapshots: tinybench: 2.9.0 tinyexec: 1.0.4 tinyglobby: 0.2.16 - vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3) ws: 8.20.0 optionalDependencies: '@opentelemetry/api': 1.9.1 @@ -20624,11 +20733,11 @@ snapshots: - utf-8-validate - yaml - '@voidzero-dev/vite-plus-test@0.1.24(@opentelemetry/api@1.9.1)(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))': + '@voidzero-dev/vite-plus-test@0.1.24(@opentelemetry/api@1.9.1)(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@voidzero-dev/vite-plus-core': 0.1.24(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3) + '@voidzero-dev/vite-plus-core': 0.1.24(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) es-module-lexer: 1.7.0 obug: 2.1.1 pixelmatch: 7.2.0 @@ -20638,7 +20747,7 @@ snapshots: tinybench: 2.9.0 tinyexec: 1.0.4 tinyglobby: 0.2.16 - vite: 8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3) ws: 8.20.0 optionalDependencies: '@opentelemetry/api': 1.9.1 @@ -20666,11 +20775,11 @@ snapshots: - utf-8-validate - yaml - '@voidzero-dev/vite-plus-test@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))': + '@voidzero-dev/vite-plus-test@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@voidzero-dev/vite-plus-core': 0.1.24(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3) + '@voidzero-dev/vite-plus-core': 0.1.24(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) es-module-lexer: 1.7.0 obug: 2.1.1 pixelmatch: 7.2.0 @@ -20680,11 +20789,11 @@ snapshots: tinybench: 2.9.0 tinyexec: 1.0.4 tinyglobby: 0.2.16 - vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3) ws: 8.20.0 optionalDependencies: '@opentelemetry/api': 1.9.1 - '@types/node': 25.6.0 + '@types/node': 25.9.0 jsdom: 25.0.1(canvas@2.11.2) transitivePeerDependencies: - '@arethetypeswrong/core' @@ -20708,11 +20817,11 @@ snapshots: - utf-8-validate - yaml - '@voidzero-dev/vite-plus-test@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))': + '@voidzero-dev/vite-plus-test@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@voidzero-dev/vite-plus-core': 0.1.24(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3) + '@voidzero-dev/vite-plus-core': 0.1.24(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) es-module-lexer: 1.7.0 obug: 2.1.1 pixelmatch: 7.2.0 @@ -20722,11 +20831,11 @@ snapshots: tinybench: 2.9.0 tinyexec: 1.0.4 tinyglobby: 0.2.16 - vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3) ws: 8.20.0 optionalDependencies: '@opentelemetry/api': 1.9.1 - '@types/node': 25.6.0 + '@types/node': 25.9.0 jsdom: 29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0) transitivePeerDependencies: - '@arethetypeswrong/core' @@ -20854,29 +20963,29 @@ snapshots: dependencies: '@types/node': 20.19.39 - '@y/prosemirror@2.0.0-2(patch_hash=802334aa5d2410b9fc999d5fb5ffef01650a04e58b59fca24e142c55b3379728)(@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9)))(@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9))(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)': + '@y/prosemirror@2.0.0-2(patch_hash=168146d45476a6e2019bd9b140bf068fd17c12fb6b7d282509552826e74740dc)(@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.16))(@y/y@14.0.0-rc.16)(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)': dependencies: - '@y/protocols': 1.0.6-rc.1(@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9)) - '@y/y': 14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9) - lib0: 1.0.0-rc.13(patch_hash=328c50b547222f0e54a7a9f4f70926c0532c006dec4f24d6954635b8c3adb69e) + '@y/protocols': 1.0.6-rc.1(@y/y@14.0.0-rc.16) + '@y/y': 14.0.0-rc.16 + lib0: 1.0.0-rc.14(patch_hash=e55ee919122bfd99c2418ad2ca66b24bdc0770c01033d31bbec567d195600f20) prosemirror-model: 1.25.4 prosemirror-state: 1.4.4 prosemirror-view: 1.41.8 - '@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9))': + '@y/protocols@1.0.6-rc.1(@y/y@14.0.0-rc.16)': dependencies: - '@y/y': 14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9) - lib0: 1.0.0-rc.13(patch_hash=328c50b547222f0e54a7a9f4f70926c0532c006dec4f24d6954635b8c3adb69e) + '@y/y': 14.0.0-rc.16 + lib0: 1.0.0-rc.14(patch_hash=e55ee919122bfd99c2418ad2ca66b24bdc0770c01033d31bbec567d195600f20) - '@y/websocket@4.0.0-rc.2(@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9))': + '@y/websocket@4.0.0-rc.2(@y/y@14.0.0-rc.16)': dependencies: - '@y/protocols': 1.0.6-rc.1(@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9)) - '@y/y': 14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9) - lib0: 1.0.0-rc.13(patch_hash=328c50b547222f0e54a7a9f4f70926c0532c006dec4f24d6954635b8c3adb69e) + '@y/protocols': 1.0.6-rc.1(@y/y@14.0.0-rc.16) + '@y/y': 14.0.0-rc.16 + lib0: 1.0.0-rc.14(patch_hash=e55ee919122bfd99c2418ad2ca66b24bdc0770c01033d31bbec567d195600f20) - '@y/y@14.0.0-rc.16(patch_hash=4c87657af127f4fcf167b812054b3c34374c63cda90c4db9a831608c23b89df9)': + '@y/y@14.0.0-rc.16': dependencies: - lib0: 1.0.0-rc.13(patch_hash=328c50b547222f0e54a7a9f4f70926c0532c006dec4f24d6954635b8c3adb69e) + lib0: 1.0.0-rc.14(patch_hash=e55ee919122bfd99c2418ad2ca66b24bdc0770c01033d31bbec567d195600f20) '@zeit/schemas@2.36.0': {} @@ -20953,7 +21062,7 @@ snapshots: ajv: 8.20.0 fast-deep-equal: 3.1.3 - ajv@6.15.0: + ajv@6.14.0: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 @@ -20963,7 +21072,7 @@ snapshots: ajv@8.18.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 + fast-uri: 3.1.2 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -21028,10 +21137,10 @@ snapshots: array-includes@3.1.9: dependencies: - call-bind: 1.0.9 + call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.24.2 + es-abstract: 1.24.1 es-object-atoms: 1.1.1 get-intrinsic: 1.3.0 is-string: 1.1.1 @@ -21039,34 +21148,34 @@ snapshots: array.prototype.findlastindex@1.2.6: dependencies: - call-bind: 1.0.9 + call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.24.2 + es-abstract: 1.24.1 es-errors: 1.3.0 es-object-atoms: 1.1.1 es-shim-unscopables: 1.1.0 array.prototype.flat@1.3.3: dependencies: - call-bind: 1.0.9 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.24.2 + es-abstract: 1.24.1 es-shim-unscopables: 1.1.0 array.prototype.flatmap@1.3.3: dependencies: - call-bind: 1.0.9 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.24.2 + es-abstract: 1.24.1 es-shim-unscopables: 1.1.0 arraybuffer.prototype.slice@1.0.4: dependencies: array-buffer-byte-length: 1.0.2 - call-bind: 1.0.9 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.24.2 + es-abstract: 1.24.1 es-errors: 1.3.0 get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 @@ -21101,13 +21210,15 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 - axios@1.15.0: + axios@1.16.1: dependencies: follow-redirects: 1.16.0 form-data: 4.0.5 + https-proxy-agent: 5.0.1 proxy-from-env: 2.1.0 transitivePeerDependencies: - debug + - supports-color babel-plugin-macros@3.1.0: dependencies: @@ -21133,10 +21244,10 @@ snapshots: baseline-browser-mapping@2.10.17: {} - better-auth@1.4.22(better-sqlite3@12.8.0)(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(pg@8.20.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(vitest@4.1.5): + better-auth@1.4.22(better-sqlite3@12.8.0)(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(pg@8.20.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(msw@2.11.5(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))): dependencies: - '@better-auth/core': 1.4.22(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.15)(nanostores@1.2.0) - '@better-auth/telemetry': 1.4.22(@better-auth/core@1.4.22(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.15)(nanostores@1.2.0)) + '@better-auth/core': 1.4.22(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.17)(nanostores@1.2.0) + '@better-auth/telemetry': 1.4.22(@better-auth/core@1.4.22(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.21)(better-call@1.1.8(zod@4.3.6))(jose@6.2.2)(kysely@0.28.17)(nanostores@1.2.0)) '@better-auth/utils': 0.3.0 '@better-fetch/fetch': 1.1.21 '@noble/ciphers': 2.1.1 @@ -21144,16 +21255,16 @@ snapshots: better-call: 1.1.8(zod@4.3.6) defu: 6.1.6 jose: 6.2.2 - kysely: 0.28.15 + kysely: 0.28.17 nanostores: 1.2.0 zod: 4.3.6 optionalDependencies: better-sqlite3: 12.8.0 - next: 16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + next: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) pg: 8.20.0 react: 19.2.5 react-dom: 19.2.5(react@19.2.5) - vitest: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(@vitest/ui@4.1.5)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(msw@2.11.5(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + vitest: 4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(msw@2.11.5(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) better-call@1.1.8(zod@4.3.6): dependencies: @@ -21222,7 +21333,7 @@ snapshots: browserslist@4.28.2: dependencies: baseline-browser-mapping: 2.10.17 - caniuse-lite: 1.0.30001784 + caniuse-lite: 1.0.30001787 electron-to-chromium: 1.5.331 node-releases: 2.0.37 update-browserslist-db: 1.2.3(browserslist@4.28.2) @@ -21254,7 +21365,7 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 - call-bind@1.0.9: + call-bind@1.0.8: dependencies: call-bind-apply-helpers: 1.0.2 es-define-property: 1.0.1 @@ -21787,7 +21898,7 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.3.2 - enhanced-resolve@5.21.0: + enhanced-resolve@5.21.4: dependencies: graceful-fs: 4.2.11 tapable: 2.3.3 @@ -21809,12 +21920,12 @@ snapshots: error-stack-parser-es@1.0.5: {} - es-abstract@1.24.2: + es-abstract@1.24.1: dependencies: array-buffer-byte-length: 1.0.2 arraybuffer.prototype.slice: 1.0.4 available-typed-arrays: 1.0.7 - call-bind: 1.0.9 + call-bind: 1.0.8 call-bound: 1.0.4 data-view-buffer: 1.0.2 data-view-byte-length: 1.0.2 @@ -21851,7 +21962,7 @@ snapshots: object.assign: 4.1.7 own-keys: 1.0.1 regexp.prototype.flags: 1.5.4 - safe-array-concat: 1.1.4 + safe-array-concat: 1.1.3 safe-push-apply: 1.0.0 safe-regex-test: 1.1.0 set-proto: 1.0.0 @@ -22047,11 +22158,11 @@ snapshots: '@eslint/eslintrc': 3.3.5 '@eslint/js': 9.39.4 '@eslint/plugin-kit': 0.4.1 - '@humanfs/node': 0.16.8 + '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - ajv: 6.15.0 + '@types/estree': 1.0.9 + ajv: 6.14.0 chalk: 4.1.2 cross-spawn: 7.0.6 debug: 4.4.3 @@ -22194,8 +22305,6 @@ snapshots: fast-sha256@1.3.0: {} - fast-uri@3.1.0: {} - fast-uri@3.1.2: {} fast-xml-builder@1.1.4: @@ -22299,7 +22408,7 @@ snapshots: fsevents@2.3.3: optional: true - fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6): + fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6): dependencies: '@formatjs/intl-localematcher': 0.8.2 '@orama/orama': 3.1.18 @@ -22323,21 +22432,21 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 lucide-react: 0.562.0(react@19.2.5) - next: 16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + next: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react: 19.2.5 react-dom: 19.2.5(react@19.2.5) zod: 4.3.6 transitivePeerDependencies: - supports-color - fumadocs-mdx@14.2.11(@types/mdast@4.0.4)(@types/mdx@2.0.13)(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)): + fumadocs-mdx@14.2.11(@types/mdast@4.0.4)(@types/mdx@2.0.13)(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react@19.2.5)(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: '@mdx-js/mdx': 3.1.1 '@standard-schema/spec': 1.1.0 chokidar: 5.0.0 esbuild: 0.27.5 estree-util-value-to-estree: 3.5.0 - fumadocs-core: 16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6) + fumadocs-core: 16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6) js-yaml: 4.1.1 mdast-util-mdx: 3.0.0 mdast-util-to-markdown: 2.1.2 @@ -22354,17 +22463,17 @@ snapshots: '@types/mdast': 4.0.4 '@types/mdx': 2.0.13 '@types/react': 19.2.14 - next: 16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) + next: 16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) react: 19.2.5 - vite: 8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - supports-color - fumadocs-twoslash@3.1.15(@fumadocs/base-ui@16.5.0(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tailwindcss@4.2.2))(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3): + fumadocs-twoslash@3.1.15(@fumadocs/base-ui@16.5.0(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tailwindcss@4.2.2))(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(typescript@5.9.3): dependencies: '@radix-ui/react-popover': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5) '@shikijs/twoslash': 4.0.2(typescript@5.9.3) - fumadocs-ui: '@fumadocs/base-ui@16.5.0(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tailwindcss@4.2.2)' + fumadocs-ui: '@fumadocs/base-ui@16.5.0(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tailwindcss@4.2.2)' mdast-util-from-markdown: 2.0.3 mdast-util-gfm: 3.1.0 mdast-util-to-hast: 13.2.1 @@ -22380,10 +22489,10 @@ snapshots: - supports-color - typescript - fumadocs-typescript@5.2.1(7b71d35b2307cf0dedaa2cbc5003f54e): + fumadocs-typescript@5.2.1(5565cdb15ab48f43051a188bfe184646): dependencies: estree-util-value-to-estree: 3.5.0 - fumadocs-core: 16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6) + fumadocs-core: 16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6) hast-util-to-estree: 3.1.3 hast-util-to-jsx-runtime: 2.3.6 react: 19.2.5 @@ -22394,11 +22503,11 @@ snapshots: unified: 11.0.5 unist-util-visit: 5.1.0 optionalDependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/hast': 3.0.4 '@types/mdast': 4.0.4 '@types/react': 19.2.14 - fumadocs-ui: '@fumadocs/base-ui@16.5.0(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tailwindcss@4.2.2)' + fumadocs-ui: '@fumadocs/base-ui@16.5.0(@types/react@19.2.14)(fumadocs-core@16.5.0(@types/react@19.2.14)(lucide-react@0.562.0(react@19.2.5))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(zod@4.3.6))(next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5))(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(tailwindcss@4.2.2)' shiki: 4.0.2 transitivePeerDependencies: - supports-color @@ -22407,7 +22516,7 @@ snapshots: function.prototype.name@1.1.8: dependencies: - call-bind: 1.0.9 + call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 functions-have-names: 1.2.3 @@ -22775,7 +22884,7 @@ snapshots: is-array-buffer@3.0.5: dependencies: - call-bind: 1.0.9 + call-bind: 1.0.8 call-bound: 1.0.4 get-intrinsic: 1.3.0 @@ -22947,8 +23056,6 @@ snapshots: isexe@2.0.0: {} - isomorphic.js@0.2.5: {} - jackspeak@3.4.3: dependencies: '@isaacs/cliui': 8.0.2 @@ -23014,7 +23121,7 @@ snapshots: jest-worker@27.5.1: dependencies: - '@types/node': 25.6.0 + '@types/node': 25.9.0 merge-stream: 2.0.0 supports-color: 8.1.1 @@ -23142,7 +23249,7 @@ snapshots: kleur@3.0.3: {} - kysely@0.28.15: {} + kysely@0.28.17: {} leac@0.6.0: {} @@ -23213,11 +23320,7 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - lib0@0.2.117: - dependencies: - isomorphic.js: 0.2.5 - - lib0@1.0.0-rc.13(patch_hash=328c50b547222f0e54a7a9f4f70926c0532c006dec4f24d6954635b8c3adb69e): {} + lib0@1.0.0-rc.14(patch_hash=e55ee919122bfd99c2418ad2ca66b24bdc0770c01033d31bbec567d195600f20): {} lie@3.3.0: dependencies: @@ -23885,9 +23988,9 @@ snapshots: ms@2.1.3: {} - msw-snapshot@5.3.0(msw@2.11.5(@types/node@25.6.0)(typescript@5.9.3)): + msw-snapshot@5.3.0(msw@2.11.5(@types/node@25.9.0)(typescript@5.9.3)): dependencies: - msw: 2.11.5(@types/node@25.6.0)(typescript@5.9.3) + msw: 2.11.5(@types/node@25.9.0)(typescript@5.9.3) msw@2.11.5(@types/node@20.19.37)(typescript@5.9.3): dependencies: @@ -23941,9 +24044,9 @@ snapshots: - '@types/node' optional: true - msw@2.11.5(@types/node@25.6.0)(typescript@5.9.3): + msw@2.11.5(@types/node@25.9.0)(typescript@5.9.3): dependencies: - '@inquirer/confirm': 5.1.21(@types/node@25.6.0) + '@inquirer/confirm': 5.1.21(@types/node@25.9.0) '@mswjs/interceptors': 0.39.8 '@open-draft/deferred-promise': 2.2.0 '@types/statuses': 2.0.6 @@ -24019,9 +24122,9 @@ snapshots: transitivePeerDependencies: - supports-color - next@16.2.7(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5): + next@16.2.9(@babel/core@7.29.0)(@opentelemetry/api@1.9.1)(@playwright/test@1.60.0)(babel-plugin-react-compiler@1.0.0)(react-dom@19.2.5(react@19.2.5))(react@19.2.5): dependencies: - '@next/env': 16.2.7 + '@next/env': 16.2.9 '@swc/helpers': 0.5.15 baseline-browser-mapping: 2.10.17 caniuse-lite: 1.0.30001787 @@ -24030,14 +24133,14 @@ snapshots: react-dom: 19.2.5(react@19.2.5) styled-jsx: 5.1.6(@babel/core@7.29.0)(react@19.2.5) optionalDependencies: - '@next/swc-darwin-arm64': 16.2.7 - '@next/swc-darwin-x64': 16.2.7 - '@next/swc-linux-arm64-gnu': 16.2.7 - '@next/swc-linux-arm64-musl': 16.2.7 - '@next/swc-linux-x64-gnu': 16.2.7 - '@next/swc-linux-x64-musl': 16.2.7 - '@next/swc-win32-arm64-msvc': 16.2.7 - '@next/swc-win32-x64-msvc': 16.2.7 + '@next/swc-darwin-arm64': 16.2.9 + '@next/swc-darwin-x64': 16.2.9 + '@next/swc-linux-arm64-gnu': 16.2.9 + '@next/swc-linux-arm64-musl': 16.2.9 + '@next/swc-linux-x64-gnu': 16.2.9 + '@next/swc-linux-x64-musl': 16.2.9 + '@next/swc-win32-arm64-msvc': 16.2.9 + '@next/swc-win32-x64-msvc': 16.2.9 '@opentelemetry/api': 1.9.1 '@playwright/test': 1.60.0 babel-plugin-react-compiler: 1.0.0 @@ -24117,7 +24220,7 @@ snapshots: object.assign@4.1.7: dependencies: - call-bind: 1.0.9 + call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 @@ -24126,27 +24229,27 @@ snapshots: object.entries@1.1.9: dependencies: - call-bind: 1.0.9 + call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 object.fromentries@2.0.8: dependencies: - call-bind: 1.0.9 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.24.2 + es-abstract: 1.24.1 es-object-atoms: 1.1.1 object.groupby@1.0.3: dependencies: - call-bind: 1.0.9 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.24.2 + es-abstract: 1.24.1 object.values@1.2.1: dependencies: - call-bind: 1.0.9 + call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 @@ -24223,7 +24326,7 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 - oxfmt@0.52.0(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))): + oxfmt@0.52.0(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)): dependencies: tinypool: 2.1.0 optionalDependencies: @@ -24246,9 +24349,9 @@ snapshots: '@oxfmt/binding-win32-arm64-msvc': 0.52.0 '@oxfmt/binding-win32-ia32-msvc': 0.52.0 '@oxfmt/binding-win32-x64-msvc': 0.52.0 - vite-plus: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + vite-plus: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) - oxfmt@0.52.0(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))): + oxfmt@0.52.0(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)): dependencies: tinypool: 2.1.0 optionalDependencies: @@ -24271,9 +24374,9 @@ snapshots: '@oxfmt/binding-win32-arm64-msvc': 0.52.0 '@oxfmt/binding-win32-ia32-msvc': 0.52.0 '@oxfmt/binding-win32-x64-msvc': 0.52.0 - vite-plus: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + vite-plus: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) - oxfmt@0.52.0(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))): + oxfmt@0.52.0(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)): dependencies: tinypool: 2.1.0 optionalDependencies: @@ -24296,9 +24399,9 @@ snapshots: '@oxfmt/binding-win32-arm64-msvc': 0.52.0 '@oxfmt/binding-win32-ia32-msvc': 0.52.0 '@oxfmt/binding-win32-x64-msvc': 0.52.0 - vite-plus: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + vite-plus: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) - oxfmt@0.52.0(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))): + oxfmt@0.52.0(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)): dependencies: tinypool: 2.1.0 optionalDependencies: @@ -24321,9 +24424,9 @@ snapshots: '@oxfmt/binding-win32-arm64-msvc': 0.52.0 '@oxfmt/binding-win32-ia32-msvc': 0.52.0 '@oxfmt/binding-win32-x64-msvc': 0.52.0 - vite-plus: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + vite-plus: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) - oxfmt@0.52.0(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))): + oxfmt@0.52.0(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)): dependencies: tinypool: 2.1.0 optionalDependencies: @@ -24346,7 +24449,7 @@ snapshots: '@oxfmt/binding-win32-arm64-msvc': 0.52.0 '@oxfmt/binding-win32-ia32-msvc': 0.52.0 '@oxfmt/binding-win32-x64-msvc': 0.52.0 - vite-plus: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + vite-plus: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) oxlint-tsgolint@0.23.0: optionalDependencies: @@ -24357,7 +24460,7 @@ snapshots: '@oxlint-tsgolint/win32-arm64': 0.23.0 '@oxlint-tsgolint/win32-x64': 0.23.0 - oxlint@1.67.0(oxlint-tsgolint@0.23.0)(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))): + oxlint@1.67.0(oxlint-tsgolint@0.23.0)(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)): optionalDependencies: '@oxlint/binding-android-arm-eabi': 1.67.0 '@oxlint/binding-android-arm64': 1.67.0 @@ -24379,9 +24482,9 @@ snapshots: '@oxlint/binding-win32-ia32-msvc': 1.67.0 '@oxlint/binding-win32-x64-msvc': 1.67.0 oxlint-tsgolint: 0.23.0 - vite-plus: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + vite-plus: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) - oxlint@1.67.0(oxlint-tsgolint@0.23.0)(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))): + oxlint@1.67.0(oxlint-tsgolint@0.23.0)(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)): optionalDependencies: '@oxlint/binding-android-arm-eabi': 1.67.0 '@oxlint/binding-android-arm64': 1.67.0 @@ -24403,9 +24506,9 @@ snapshots: '@oxlint/binding-win32-ia32-msvc': 1.67.0 '@oxlint/binding-win32-x64-msvc': 1.67.0 oxlint-tsgolint: 0.23.0 - vite-plus: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + vite-plus: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) - oxlint@1.67.0(oxlint-tsgolint@0.23.0)(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))): + oxlint@1.67.0(oxlint-tsgolint@0.23.0)(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)): optionalDependencies: '@oxlint/binding-android-arm-eabi': 1.67.0 '@oxlint/binding-android-arm64': 1.67.0 @@ -24427,9 +24530,9 @@ snapshots: '@oxlint/binding-win32-ia32-msvc': 1.67.0 '@oxlint/binding-win32-x64-msvc': 1.67.0 oxlint-tsgolint: 0.23.0 - vite-plus: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + vite-plus: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) - oxlint@1.67.0(oxlint-tsgolint@0.23.0)(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))): + oxlint@1.67.0(oxlint-tsgolint@0.23.0)(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)): optionalDependencies: '@oxlint/binding-android-arm-eabi': 1.67.0 '@oxlint/binding-android-arm64': 1.67.0 @@ -24451,9 +24554,9 @@ snapshots: '@oxlint/binding-win32-ia32-msvc': 1.67.0 '@oxlint/binding-win32-x64-msvc': 1.67.0 oxlint-tsgolint: 0.23.0 - vite-plus: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + vite-plus: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) - oxlint@1.67.0(oxlint-tsgolint@0.23.0)(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))): + oxlint@1.67.0(oxlint-tsgolint@0.23.0)(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)): optionalDependencies: '@oxlint/binding-android-arm-eabi': 1.67.0 '@oxlint/binding-android-arm64': 1.67.0 @@ -24475,7 +24578,7 @@ snapshots: '@oxlint/binding-win32-ia32-msvc': 1.67.0 '@oxlint/binding-win32-x64-msvc': 1.67.0 oxlint-tsgolint: 0.23.0 - vite-plus: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + vite-plus: 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) p-limit@3.1.0: dependencies: @@ -25162,9 +25265,9 @@ snapshots: reflect.getprototypeof@1.0.10: dependencies: - call-bind: 1.0.9 + call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.24.2 + es-abstract: 1.24.1 es-errors: 1.3.0 es-object-atoms: 1.1.1 get-intrinsic: 1.3.0 @@ -25183,7 +25286,7 @@ snapshots: regexp.prototype.flags@1.5.4: dependencies: - call-bind: 1.0.9 + call-bind: 1.0.8 define-properties: 1.2.1 es-errors: 1.3.0 get-proto: 1.0.1 @@ -25380,9 +25483,9 @@ snapshots: dependencies: tslib: 2.8.1 - safe-array-concat@1.1.4: + safe-array-concat@1.1.3: dependencies: - call-bind: 1.0.9 + call-bind: 1.0.8 call-bound: 1.0.4 get-intrinsic: 1.3.0 has-symbols: 1.1.0 @@ -25556,7 +25659,7 @@ snapshots: '@shikijs/vscode-textmate': 10.0.2 '@types/hast': 3.0.4 - side-channel-list@1.0.1: + side-channel-list@1.0.0: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 @@ -25580,7 +25683,7 @@ snapshots: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 - side-channel-list: 1.0.1 + side-channel-list: 1.0.0 side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 @@ -25747,24 +25850,24 @@ snapshots: string.prototype.trim@1.2.10: dependencies: - call-bind: 1.0.9 + call-bind: 1.0.8 call-bound: 1.0.4 define-data-property: 1.1.4 define-properties: 1.2.1 - es-abstract: 1.24.2 + es-abstract: 1.24.1 es-object-atoms: 1.1.1 has-property-descriptors: 1.0.2 string.prototype.trimend@1.0.9: dependencies: - call-bind: 1.0.9 + call-bind: 1.0.8 call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 string.prototype.trimstart@1.0.8: dependencies: - call-bind: 1.0.9 + call-bind: 1.0.8 define-properties: 1.2.1 es-object-atoms: 1.1.1 @@ -25895,17 +25998,18 @@ snapshots: yallist: 4.0.0 optional: true - terser-webpack-plugin@5.5.0(esbuild@0.27.5)(webpack@5.105.4(esbuild@0.27.5)): + terser-webpack-plugin@5.6.0(esbuild@0.27.5)(postcss@8.5.14)(webpack@5.105.4(esbuild@0.27.5)(postcss@8.5.14)): dependencies: '@jridgewell/trace-mapping': 0.3.31 jest-worker: 27.5.1 schema-utils: 4.3.3 - terser: 5.46.2 - webpack: 5.105.4(esbuild@0.27.5) + terser: 5.47.1 + webpack: 5.105.4(esbuild@0.27.5)(postcss@8.5.14) optionalDependencies: esbuild: 0.27.5 + postcss: 8.5.14 - terser@5.46.2: + terser@5.47.1: dependencies: '@jridgewell/source-map': 0.3.11 acorn: 8.16.0 @@ -26060,7 +26164,7 @@ snapshots: typed-array-byte-length@1.0.3: dependencies: - call-bind: 1.0.9 + call-bind: 1.0.8 for-each: 0.3.5 gopd: 1.2.0 has-proto: 1.2.0 @@ -26069,7 +26173,7 @@ snapshots: typed-array-byte-offset@1.0.4: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.9 + call-bind: 1.0.8 for-each: 0.3.5 gopd: 1.2.0 has-proto: 1.2.0 @@ -26078,7 +26182,7 @@ snapshots: typed-array-length@1.0.7: dependencies: - call-bind: 1.0.9 + call-bind: 1.0.8 for-each: 0.3.5 gopd: 1.2.0 is-typed-array: 1.1.15 @@ -26108,6 +26212,8 @@ snapshots: undici-types@7.19.2: {} + undici-types@7.24.6: {} + undici@6.25.0: {} undici@7.25.0: {} @@ -26248,13 +26354,13 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 - vite-node@6.0.0(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0): + vite-node@6.0.0(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: cac: 7.0.0 es-module-lexer: 2.0.0 obug: 2.1.1 pathe: 2.0.3 - vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - '@types/node' - '@vitejs/devtools' @@ -26269,13 +26375,13 @@ snapshots: - tsx - yaml - vite-plugin-externalize-deps@0.10.0(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)): + vite-plugin-externalize-deps@0.10.0(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: - vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3) - vite-plugin-inspect@12.0.0-beta.1(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))(ws@8.20.0): + vite-plugin-inspect@12.0.0-beta.1(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(ws@8.20.0): dependencies: - '@vitejs/devtools-kit': 0.1.13(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))(ws@8.20.0) + '@vitejs/devtools-kit': 0.1.13(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(ws@8.20.0) ansis: 4.2.0 error-stack-parser-es: 1.0.5 obug: 2.1.1 @@ -26284,19 +26390,19 @@ snapshots: perfect-debounce: 2.1.0 sirv: 3.0.2 unplugin-utils: 0.3.1 - vite: 8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3) transitivePeerDependencies: - typescript - ws - vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)): + vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3): dependencies: '@oxc-project/types': 0.133.0 '@oxlint/plugins': 1.61.0 - '@voidzero-dev/vite-plus-core': 0.1.24(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3) - '@voidzero-dev/vite-plus-test': 0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) - oxfmt: 0.52.0(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))) - oxlint: 1.67.0(oxlint-tsgolint@0.23.0)(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))) + '@voidzero-dev/vite-plus-core': 0.1.24(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + '@voidzero-dev/vite-plus-test': 0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) + oxfmt: 0.52.0(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)) + oxlint: 1.67.0(oxlint-tsgolint@0.23.0)(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)) oxlint-tsgolint: 0.23.0 optionalDependencies: '@voidzero-dev/vite-plus-darwin-arm64': 0.1.24 @@ -26339,14 +26445,14 @@ snapshots: - vite - yaml - vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)): + vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3): dependencies: '@oxc-project/types': 0.133.0 '@oxlint/plugins': 1.61.0 - '@voidzero-dev/vite-plus-core': 0.1.24(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3) - '@voidzero-dev/vite-plus-test': 0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) - oxfmt: 0.52.0(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))) - oxlint: 1.67.0(oxlint-tsgolint@0.23.0)(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))) + '@voidzero-dev/vite-plus-core': 0.1.24(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + '@voidzero-dev/vite-plus-test': 0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) + oxfmt: 0.52.0(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)) + oxlint: 1.67.0(oxlint-tsgolint@0.23.0)(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)) oxlint-tsgolint: 0.23.0 optionalDependencies: '@voidzero-dev/vite-plus-darwin-arm64': 0.1.24 @@ -26389,14 +26495,14 @@ snapshots: - vite - yaml - vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)): + vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3): dependencies: '@oxc-project/types': 0.133.0 '@oxlint/plugins': 1.61.0 - '@voidzero-dev/vite-plus-core': 0.1.24(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3) - '@voidzero-dev/vite-plus-test': 0.1.24(@opentelemetry/api@1.9.1)(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) - oxfmt: 0.52.0(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))) - oxlint: 1.67.0(oxlint-tsgolint@0.23.0)(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))) + '@voidzero-dev/vite-plus-core': 0.1.24(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + '@voidzero-dev/vite-plus-test': 0.1.24(@opentelemetry/api@1.9.1)(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) + oxfmt: 0.52.0(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)) + oxlint: 1.67.0(oxlint-tsgolint@0.23.0)(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)) oxlint-tsgolint: 0.23.0 optionalDependencies: '@voidzero-dev/vite-plus-darwin-arm64': 0.1.24 @@ -26439,14 +26545,14 @@ snapshots: - vite - yaml - vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)): + vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3): dependencies: '@oxc-project/types': 0.133.0 '@oxlint/plugins': 1.61.0 - '@voidzero-dev/vite-plus-core': 0.1.24(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3) - '@voidzero-dev/vite-plus-test': 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) - oxfmt: 0.52.0(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))) - oxlint: 1.67.0(oxlint-tsgolint@0.23.0)(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))) + '@voidzero-dev/vite-plus-core': 0.1.24(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + '@voidzero-dev/vite-plus-test': 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) + oxfmt: 0.52.0(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)) + oxlint: 1.67.0(oxlint-tsgolint@0.23.0)(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@25.0.1(canvas@2.11.2))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)) oxlint-tsgolint: 0.23.0 optionalDependencies: '@voidzero-dev/vite-plus-darwin-arm64': 0.1.24 @@ -26489,14 +26595,14 @@ snapshots: - vite - yaml - vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)): + vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3): dependencies: '@oxc-project/types': 0.133.0 '@oxlint/plugins': 1.61.0 - '@voidzero-dev/vite-plus-core': 0.1.24(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3) - '@voidzero-dev/vite-plus-test': 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) - oxfmt: 0.52.0(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))) - oxlint: 1.67.0(oxlint-tsgolint@0.23.0)(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.46.2)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0))) + '@voidzero-dev/vite-plus-core': 0.1.24(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.3) + '@voidzero-dev/vite-plus-test': 0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) + oxfmt: 0.52.0(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)) + oxlint: 1.67.0(oxlint-tsgolint@0.23.0)(vite-plus@0.1.24(@opentelemetry/api@1.9.1)(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(terser@5.47.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3)) oxlint-tsgolint: 0.23.0 optionalDependencies: '@voidzero-dev/vite-plus-darwin-arm64': 0.1.24 @@ -26539,7 +26645,7 @@ snapshots: - vite - yaml - vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0): + vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 @@ -26551,10 +26657,11 @@ snapshots: esbuild: 0.27.5 fsevents: 2.3.3 jiti: 2.6.1 - terser: 5.46.2 + terser: 5.47.1 tsx: 4.21.0 + yaml: 2.8.3 - vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0): + vite@8.0.8(@types/node@22.13.13)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 @@ -26566,10 +26673,11 @@ snapshots: esbuild: 0.27.5 fsevents: 2.3.3 jiti: 2.6.1 - terser: 5.46.2 + terser: 5.47.1 tsx: 4.21.0 + yaml: 2.8.3 - vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0): + vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 @@ -26581,10 +26689,12 @@ snapshots: esbuild: 0.27.5 fsevents: 2.3.3 jiti: 2.6.1 - terser: 5.46.2 + terser: 5.47.1 tsx: 4.21.0 + yaml: 2.8.3 + optional: true - vite@8.0.8(@types/node@25.6.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0): + vite@8.0.8(@types/node@25.9.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 @@ -26592,18 +26702,19 @@ snapshots: rolldown: 1.0.0-rc.15 tinyglobby: 0.2.16 optionalDependencies: - '@types/node': 25.6.0 + '@types/node': 25.9.0 esbuild: 0.27.5 fsevents: 2.3.3 jiti: 2.6.1 - terser: 5.46.2 + terser: 5.47.1 tsx: 4.21.0 + yaml: 2.8.3 - vitest-browser-react@2.2.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(vitest@4.1.5): + vitest-browser-react@2.2.0(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.5(react@19.2.5))(react@19.2.5)(vitest@4.1.7): dependencies: react: 19.2.5 react-dom: 19.2.5(react@19.2.5) - vitest: 4.1.5(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(msw@2.11.5(@types/node@20.19.37)(typescript@5.9.3))(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) + vitest: 4.1.7(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(msw@2.11.5(@types/node@20.19.37)(typescript@5.9.3))(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) optionalDependencies: '@types/react': 19.2.14 '@types/react-dom': 19.2.3(@types/react@19.2.14) @@ -26617,15 +26728,15 @@ snapshots: transitivePeerDependencies: - supports-color - vitest@4.1.5(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(msw@2.11.5(@types/node@20.19.37)(typescript@5.9.3))(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)): + vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@20.19.37)(@vitest/ui@4.1.5)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(msw@2.11.5(@types/node@20.19.37)(typescript@5.9.3))(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: - '@vitest/expect': 4.1.5 - '@vitest/mocker': 4.1.5(msw@2.11.5(@types/node@20.19.37)(typescript@5.9.3))(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) - '@vitest/pretty-format': 4.1.5 - '@vitest/runner': 4.1.5 - '@vitest/snapshot': 4.1.5 - '@vitest/spy': 4.1.5 - '@vitest/utils': 4.1.5 + '@vitest/expect': 4.1.7 + '@vitest/mocker': 4.1.7(msw@2.11.5(@types/node@20.19.37)(typescript@5.9.3))(vite@8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/pretty-format': 4.1.7 + '@vitest/runner': 4.1.7 + '@vitest/snapshot': 4.1.7 + '@vitest/spy': 4.1.7 + '@vitest/utils': 4.1.7 es-module-lexer: 2.1.0 expect-type: 1.3.0 magic-string: 0.30.21 @@ -26637,25 +26748,25 @@ snapshots: tinyexec: 1.0.4 tinyglobby: 0.2.16 tinyrainbow: 3.1.0 - vite: 8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.8(@types/node@20.19.37)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.1 '@types/node': 20.19.37 - '@vitest/ui': 4.1.5(vitest@4.1.5) + '@vitest/ui': 4.1.5(vitest@4.1.7) jsdom: 29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0) transitivePeerDependencies: - msw - vitest@4.1.5(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(@vitest/ui@4.1.5)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(msw@2.11.5(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)): + vitest@4.1.7(@opentelemetry/api@1.9.1)(@types/node@25.5.0)(jsdom@29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0))(msw@2.11.5(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)): dependencies: - '@vitest/expect': 4.1.5 - '@vitest/mocker': 4.1.5(msw@2.11.5(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0)) - '@vitest/pretty-format': 4.1.5 - '@vitest/runner': 4.1.5 - '@vitest/snapshot': 4.1.5 - '@vitest/spy': 4.1.5 - '@vitest/utils': 4.1.5 + '@vitest/expect': 4.1.7 + '@vitest/mocker': 4.1.7(msw@2.11.5(@types/node@25.5.0)(typescript@5.9.3))(vite@8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3)) + '@vitest/pretty-format': 4.1.7 + '@vitest/runner': 4.1.7 + '@vitest/snapshot': 4.1.7 + '@vitest/spy': 4.1.7 + '@vitest/utils': 4.1.7 es-module-lexer: 2.1.0 expect-type: 1.3.0 magic-string: 0.30.21 @@ -26667,15 +26778,15 @@ snapshots: tinyexec: 1.0.4 tinyglobby: 0.2.16 tinyrainbow: 3.1.0 - vite: 8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.46.2)(tsx@4.21.0) + vite: 8.0.8(@types/node@25.5.0)(esbuild@0.27.5)(jiti@2.6.1)(terser@5.47.1)(tsx@4.21.0)(yaml@2.8.3) why-is-node-running: 2.3.0 optionalDependencies: '@opentelemetry/api': 1.9.1 '@types/node': 25.5.0 - '@vitest/ui': 4.1.5(vitest@4.1.5) jsdom: 29.0.2(@noble/hashes@2.0.1)(canvas@3.1.0) transitivePeerDependencies: - msw + optional: true w3c-keyname@2.2.8: {} @@ -26685,13 +26796,14 @@ snapshots: wait-on@9.0.5: dependencies: - axios: 1.15.0 + axios: 1.16.1 joi: 18.1.2 lodash: 4.18.1 minimist: 1.2.8 rxjs: 7.8.2 transitivePeerDependencies: - debug + - supports-color watchpack@2.5.1: dependencies: @@ -26708,10 +26820,10 @@ snapshots: webpack-sources@3.4.1: {} - webpack@5.105.4(esbuild@0.27.5): + webpack@5.105.4(esbuild@0.27.5)(postcss@8.5.14): dependencies: '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/json-schema': 7.0.15 '@webassemblyjs/ast': 1.14.1 '@webassemblyjs/wasm-edit': 1.14.1 @@ -26720,7 +26832,7 @@ snapshots: acorn-import-phases: 1.0.4(acorn@8.16.0) browserslist: 4.28.2 chrome-trace-event: 1.0.4 - enhanced-resolve: 5.21.0 + enhanced-resolve: 5.21.4 es-module-lexer: 2.1.0 eslint-scope: 5.1.1 events: 3.3.0 @@ -26732,12 +26844,21 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.3 tapable: 2.3.3 - terser-webpack-plugin: 5.5.0(esbuild@0.27.5)(webpack@5.105.4(esbuild@0.27.5)) + terser-webpack-plugin: 5.6.0(esbuild@0.27.5)(postcss@8.5.14)(webpack@5.105.4(esbuild@0.27.5)(postcss@8.5.14)) watchpack: 2.5.1 webpack-sources: 3.4.1 transitivePeerDependencies: + - '@minify-html/node' - '@swc/core' + - '@swc/css' + - '@swc/html' + - clean-css + - cssnano + - csso - esbuild + - html-minifier-terser + - lightningcss + - postcss - uglify-js whatwg-encoding@3.1.1: @@ -26802,7 +26923,7 @@ snapshots: which-typed-array@1.1.20: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.9 + call-bind: 1.0.8 call-bound: 1.0.4 for-each: 0.3.5 get-proto: 1.0.1 @@ -26851,7 +26972,7 @@ snapshots: wrappy@1.0.2: {} - ws@6.2.4: + ws@6.2.3: dependencies: async-limiter: 1.0.1 optional: true @@ -26885,19 +27006,19 @@ snapshots: y-indexeddb@9.0.12(yjs@13.6.30): dependencies: - lib0: 0.2.117 + lib0: 1.0.0-rc.14(patch_hash=e55ee919122bfd99c2418ad2ca66b24bdc0770c01033d31bbec567d195600f20) yjs: 13.6.30 y-leveldb@0.1.2(yjs@13.6.30): dependencies: level: 6.0.1 - lib0: 0.2.117 + lib0: 1.0.0-rc.14(patch_hash=e55ee919122bfd99c2418ad2ca66b24bdc0770c01033d31bbec567d195600f20) yjs: 13.6.30 optional: true y-partykit@0.0.25: dependencies: - lib0: 0.2.117 + lib0: 1.0.0-rc.14(patch_hash=e55ee919122bfd99c2418ad2ca66b24bdc0770c01033d31bbec567d195600f20) lodash.debounce: 4.0.8 react: 18.3.1 y-protocols: 1.0.7(yjs@13.6.30) @@ -26905,7 +27026,7 @@ snapshots: y-prosemirror@1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.8)(y-protocols@1.0.7(yjs@13.6.30))(yjs@13.6.30): dependencies: - lib0: 0.2.117 + lib0: 1.0.0-rc.14(patch_hash=e55ee919122bfd99c2418ad2ca66b24bdc0770c01033d31bbec567d195600f20) prosemirror-model: 1.25.4 prosemirror-state: 1.4.4 prosemirror-view: 1.41.8 @@ -26914,17 +27035,17 @@ snapshots: y-protocols@1.0.7(yjs@13.6.30): dependencies: - lib0: 0.2.117 + lib0: 1.0.0-rc.14(patch_hash=e55ee919122bfd99c2418ad2ca66b24bdc0770c01033d31bbec567d195600f20) yjs: 13.6.30 y-websocket@2.1.0(yjs@13.6.30): dependencies: - lib0: 0.2.117 + lib0: 1.0.0-rc.14(patch_hash=e55ee919122bfd99c2418ad2ca66b24bdc0770c01033d31bbec567d195600f20) lodash.debounce: 4.0.8 y-protocols: 1.0.7(yjs@13.6.30) yjs: 13.6.30 optionalDependencies: - ws: 6.2.4 + ws: 6.2.3 y-leveldb: 0.1.2(yjs@13.6.30) transitivePeerDependencies: - bufferutil @@ -26939,6 +27060,9 @@ snapshots: yaml@1.10.3: {} + yaml@2.8.3: + optional: true + yargs-parser@21.1.1: {} yargs@17.7.2: @@ -26953,7 +27077,7 @@ snapshots: yjs@13.6.30: dependencies: - lib0: 0.2.117 + lib0: 1.0.0-rc.14(patch_hash=e55ee919122bfd99c2418ad2ca66b24bdc0770c01033d31bbec567d195600f20) yocto-queue@0.1.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 5e9bdbbc20..d4fcfb2b90 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -17,9 +17,14 @@ overrides: "@headlessui/react": "^2.2.4" "@tiptap/core": "^3.0.0" "@tiptap/pm": "^3.0.0" - "@y/prosemirror>lib0": "1.0.0-rc.13" + "vitest": "4.1.7" + "@vitest/runner": "4.1.7" "@y/y": "14.0.0-rc.16" "@y/prosemirror": "2.0.0-2" + # Force the whole @y/* v14 ecosystem (@y/prosemirror, @y/y, @y/protocols, + # @y/websocket — all declare lib0 ^1.0.0-rc.13) onto the single patched + # lib0 rc.14, so the matchNodes diff patch is the only lib0 delta instance. + "lib0": "1.0.0-rc.14" allowBuilds: "@parcel/watcher": true "@sentry/cli": true @@ -34,8 +39,7 @@ allowBuilds: leveldown: false patchedDependencies: "@y/prosemirror@2.0.0-2": "patches/@y__prosemirror@2.0.0-2.patch" - '@y/y@14.0.0-rc.16': patches/@y__y@14.0.0-rc.16.patch - lib0@1.0.0-rc.13: patches/lib0@1.0.0-rc.13.patch + lib0@1.0.0-rc.14: patches/lib0@1.0.0-rc.14.patch catalog: vite-plus: ^0.1.24 minimumReleaseAgeExclude: diff --git a/scripts/patch-lib0.sh b/scripts/patch-lib0.sh index 70a99d14dc..e7e4d2c644 100755 --- a/scripts/patch-lib0.sh +++ b/scripts/patch-lib0.sh @@ -27,7 +27,7 @@ echo "==> Building lib0 (npm run dist) ..." (cd "$LOCAL_LIB0" && npm run dist) # Best-effort cleanup of any leftover patch dir (case-insensitive FS resolves this fine). -STALE_PATCH_DIR="$BLOCKNOTE_ROOT/node_modules/.pnpm_patches/lib0@1.0.0-rc.13" +STALE_PATCH_DIR="$BLOCKNOTE_ROOT/node_modules/.pnpm_patches/lib0@1.0.0-rc.14" # 1. Clean up any leftover patch dir, then start fresh if [[ -d "$STALE_PATCH_DIR" ]]; then @@ -35,15 +35,15 @@ if [[ -d "$STALE_PATCH_DIR" ]]; then rm -rf "$STALE_PATCH_DIR" fi -echo "==> Running pnpm patch lib0@1.0.0-rc.13 ..." +echo "==> Running pnpm patch lib0@1.0.0-rc.14 ..." cd "$BLOCKNOTE_ROOT" # Capture pnpm's reported patch dir so we use the canonical on-disk path casing. # Constructing PATCH_DIR manually breaks on macOS when the repo is entered via a # differently-cased path (e.g. blockNote vs BlockNote): pnpm patch-commit matches # the path against state.json case-sensitively and fails with ERR_PNPM_INVALID_PATCH_DIR. -PATCH_OUTPUT="$(pnpm patch lib0@1.0.0-rc.13)" +PATCH_OUTPUT="$(pnpm patch lib0@1.0.0-rc.14)" echo "$PATCH_OUTPUT" -PATCH_DIR="$(printf '%s\n' "$PATCH_OUTPUT" | grep -Eo '/.*/\.pnpm_patches/lib0@1\.0\.0-rc\.13' | head -n1)" +PATCH_DIR="$(printf '%s\n' "$PATCH_OUTPUT" | grep -Eo '/.*/\.pnpm_patches/lib0@1\.0\.0-rc\.14' | head -n1)" if [[ -z "$PATCH_DIR" || ! -d "$PATCH_DIR" ]]; then echo "ERROR: Could not determine patch dir from 'pnpm patch' output" @@ -70,7 +70,7 @@ const orig = JSON.parse(fs.readFileSync('$PATCH_DIR/package.json', 'utf8')); const local = JSON.parse(fs.readFileSync('$LOCAL_LIB0/package.json', 'utf8')); // Keep the original version so pnpm doesn't try to fetch a different version from registry -orig.version = '1.0.0-rc.13'; +orig.version = '1.0.0-rc.14'; // Update exports orig.exports = local.exports; @@ -95,4 +95,4 @@ echo "==> Running pnpm patch-commit ..." pnpm patch-commit "$PATCH_DIR" echo "" -echo "==> Done! Patch regenerated at patches/lib0@1.0.0-rc.13.patch" +echo "==> Done! Patch regenerated at patches/lib0@1.0.0-rc.14.patch" diff --git a/scripts/patch-yjs.sh b/scripts/patch-yjs.sh index 1a443eb3fc..43a1253216 100755 --- a/scripts/patch-yjs.sh +++ b/scripts/patch-yjs.sh @@ -12,7 +12,7 @@ set -euo pipefail # Version that is actually installed in this repo (pnpm patches the installed # version). The local ../yjs checkout may be a newer rc; we still pin to this. YJS_PKG="@y/y" -YJS_VERSION="14.0.0-rc.16" +YJS_VERSION="14.0.0-rc.17" # pnpm keeps the scope path for the temp patch dir (e.g. .pnpm_patches/@y/y@VER) # but escapes "/" to "__" for the committed patch file name. diff --git a/tests/.gitignore b/tests/.gitignore new file mode 100644 index 0000000000..362e4126db --- /dev/null +++ b/tests/.gitignore @@ -0,0 +1,6 @@ +# vitest-browser auto-saved debug screenshots on test failure (separate +# from `toMatchScreenshot` reference shots, which use `*-chromium-darwin.png`). +src/browser/**/__screenshots__/**/*-1.png + +# vitest-browser attachments (debug artifacts saved during test runs). +.vitest-attachments diff --git a/tests/.vitest-attachments/src/browser/y-prosemirror/propChanges.test.tsx/prop-change-image-source-actual-chromium-darwin.png b/tests/.vitest-attachments/src/browser/y-prosemirror/propChanges.test.tsx/prop-change-image-source-actual-chromium-darwin.png new file mode 100644 index 0000000000..9ea07ef01c Binary files /dev/null and b/tests/.vitest-attachments/src/browser/y-prosemirror/propChanges.test.tsx/prop-change-image-source-actual-chromium-darwin.png differ diff --git a/tests/package.json b/tests/package.json index ffcbcad408..e7c52a9b63 100644 --- a/tests/package.json +++ b/tests/package.json @@ -21,6 +21,8 @@ "@types/react": "^19.2.3", "@types/react-dom": "^19.2.3", "@vitest/ui": "4.1.5", + "@y/protocols": "^1.0.6-rc.1", + "@y/y": "^14.0.0-rc.17", "htmlfy": "^0.6.7", "react": "^19.2.5", "react-dom": "^19.2.5", diff --git a/tests/src/end-to-end/ai/__screenshots__/ai.test.tsx/ai_menu_scroll_position-chromium-darwin.png b/tests/src/end-to-end/ai/__screenshots__/ai.test.tsx/ai_menu_scroll_position-chromium-darwin.png new file mode 100644 index 0000000000..b88641b008 Binary files /dev/null and b/tests/src/end-to-end/ai/__screenshots__/ai.test.tsx/ai_menu_scroll_position-chromium-darwin.png differ diff --git a/tests/src/end-to-end/ai/__screenshots__/ai.test.tsx/ai_menu_scroll_position-firefox-darwin.png b/tests/src/end-to-end/ai/__screenshots__/ai.test.tsx/ai_menu_scroll_position-firefox-darwin.png new file mode 100644 index 0000000000..a70951ceb8 Binary files /dev/null and b/tests/src/end-to-end/ai/__screenshots__/ai.test.tsx/ai_menu_scroll_position-firefox-darwin.png differ diff --git a/tests/src/end-to-end/ai/__screenshots__/ai.test.tsx/ai_menu_scroll_position-webkit-darwin.png b/tests/src/end-to-end/ai/__screenshots__/ai.test.tsx/ai_menu_scroll_position-webkit-darwin.png new file mode 100644 index 0000000000..47b0c5ef7e Binary files /dev/null and b/tests/src/end-to-end/ai/__screenshots__/ai.test.tsx/ai_menu_scroll_position-webkit-darwin.png differ diff --git a/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-drag-handle-menu-chromium-darwin.png b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-drag-handle-menu-chromium-darwin.png new file mode 100644 index 0000000000..6c66dd2374 Binary files /dev/null and b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-drag-handle-menu-chromium-darwin.png differ diff --git a/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-drag-handle-menu-firefox-darwin.png b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-drag-handle-menu-firefox-darwin.png new file mode 100644 index 0000000000..af6b706f8a Binary files /dev/null and b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-drag-handle-menu-firefox-darwin.png differ diff --git a/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-drag-handle-menu-webkit-darwin.png b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-drag-handle-menu-webkit-darwin.png new file mode 100644 index 0000000000..5b4cf56988 Binary files /dev/null and b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-drag-handle-menu-webkit-darwin.png differ diff --git a/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-emoji-picker-chromium-darwin.png b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-emoji-picker-chromium-darwin.png new file mode 100644 index 0000000000..2b1e027155 Binary files /dev/null and b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-emoji-picker-chromium-darwin.png differ diff --git a/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-emoji-picker-firefox-darwin.png b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-emoji-picker-firefox-darwin.png new file mode 100644 index 0000000000..c2f8d15fde Binary files /dev/null and b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-emoji-picker-firefox-darwin.png differ diff --git a/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-emoji-picker-webkit-darwin.png b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-emoji-picker-webkit-darwin.png new file mode 100644 index 0000000000..bfcde8feaa Binary files /dev/null and b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-emoji-picker-webkit-darwin.png differ diff --git a/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-formatting-toolbar-chromium-darwin.png b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-formatting-toolbar-chromium-darwin.png new file mode 100644 index 0000000000..dd1fc82cf1 Binary files /dev/null and b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-formatting-toolbar-chromium-darwin.png differ diff --git a/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-formatting-toolbar-firefox-darwin.png b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-formatting-toolbar-firefox-darwin.png new file mode 100644 index 0000000000..edde98a115 Binary files /dev/null and b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-formatting-toolbar-firefox-darwin.png differ diff --git a/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-formatting-toolbar-webkit-darwin.png b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-formatting-toolbar-webkit-darwin.png new file mode 100644 index 0000000000..b62f13e4f9 Binary files /dev/null and b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-formatting-toolbar-webkit-darwin.png differ diff --git a/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-image-toolbar-chromium-darwin.png b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-image-toolbar-chromium-darwin.png new file mode 100644 index 0000000000..211524214f Binary files /dev/null and b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-image-toolbar-chromium-darwin.png differ diff --git a/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-image-toolbar-firefox-darwin.png b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-image-toolbar-firefox-darwin.png new file mode 100644 index 0000000000..530c88569b Binary files /dev/null and b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-image-toolbar-firefox-darwin.png differ diff --git a/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-image-toolbar-webkit-darwin.png b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-image-toolbar-webkit-darwin.png new file mode 100644 index 0000000000..366a133f61 Binary files /dev/null and b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-image-toolbar-webkit-darwin.png differ diff --git a/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-link-toolbar-chromium-darwin.png b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-link-toolbar-chromium-darwin.png new file mode 100644 index 0000000000..e4707dc71a Binary files /dev/null and b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-link-toolbar-chromium-darwin.png differ diff --git a/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-link-toolbar-firefox-darwin.png b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-link-toolbar-firefox-darwin.png new file mode 100644 index 0000000000..125f729b43 Binary files /dev/null and b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-link-toolbar-firefox-darwin.png differ diff --git a/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-link-toolbar-webkit-darwin.png b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-link-toolbar-webkit-darwin.png new file mode 100644 index 0000000000..74dfec0eeb Binary files /dev/null and b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-link-toolbar-webkit-darwin.png differ diff --git a/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-side-menu-chromium-darwin.png b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-side-menu-chromium-darwin.png new file mode 100644 index 0000000000..80aa2e0363 Binary files /dev/null and b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-side-menu-chromium-darwin.png differ diff --git a/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-side-menu-firefox-darwin.png b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-side-menu-firefox-darwin.png new file mode 100644 index 0000000000..7886c2ff15 Binary files /dev/null and b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-side-menu-firefox-darwin.png differ diff --git a/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-side-menu-webkit-darwin.png b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-side-menu-webkit-darwin.png new file mode 100644 index 0000000000..bcbd3f3711 Binary files /dev/null and b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-side-menu-webkit-darwin.png differ diff --git a/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-slash-menu-chromium-darwin.png b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-slash-menu-chromium-darwin.png new file mode 100644 index 0000000000..a4d51b18ab Binary files /dev/null and b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-slash-menu-chromium-darwin.png differ diff --git a/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-slash-menu-firefox-darwin.png b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-slash-menu-firefox-darwin.png new file mode 100644 index 0000000000..fc5ddfcd1f Binary files /dev/null and b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-slash-menu-firefox-darwin.png differ diff --git a/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-slash-menu-webkit-darwin.png b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-slash-menu-webkit-darwin.png new file mode 100644 index 0000000000..1ba006f518 Binary files /dev/null and b/tests/src/end-to-end/ariakit/__screenshots__/ariakit.test.tsx/ariakit-slash-menu-webkit-darwin.png differ diff --git a/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/backgroundColorMark-chromium-darwin.png b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/backgroundColorMark-chromium-darwin.png new file mode 100644 index 0000000000..d5dbe9761c Binary files /dev/null and b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/backgroundColorMark-chromium-darwin.png differ diff --git a/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/backgroundColorMark-firefox-darwin.png b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/backgroundColorMark-firefox-darwin.png new file mode 100644 index 0000000000..a359b07e21 Binary files /dev/null and b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/backgroundColorMark-firefox-darwin.png differ diff --git a/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/backgroundColorMark-webkit-darwin.png b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/backgroundColorMark-webkit-darwin.png new file mode 100644 index 0000000000..31f2737e10 Binary files /dev/null and b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/backgroundColorMark-webkit-darwin.png differ diff --git a/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockBackgroundColor-chromium-darwin.png b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockBackgroundColor-chromium-darwin.png new file mode 100644 index 0000000000..e852f1eda8 Binary files /dev/null and b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockBackgroundColor-chromium-darwin.png differ diff --git a/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockBackgroundColor-firefox-darwin.png b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockBackgroundColor-firefox-darwin.png new file mode 100644 index 0000000000..6494056884 Binary files /dev/null and b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockBackgroundColor-firefox-darwin.png differ diff --git a/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockBackgroundColor-webkit-darwin.png b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockBackgroundColor-webkit-darwin.png new file mode 100644 index 0000000000..eb6e9c1b8f Binary files /dev/null and b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockBackgroundColor-webkit-darwin.png differ diff --git a/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockTextColor-chromium-darwin.png b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockTextColor-chromium-darwin.png new file mode 100644 index 0000000000..cdbf93c4e2 Binary files /dev/null and b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockTextColor-chromium-darwin.png differ diff --git a/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockTextColor-firefox-darwin.png b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockTextColor-firefox-darwin.png new file mode 100644 index 0000000000..d840afcb13 Binary files /dev/null and b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockTextColor-firefox-darwin.png differ diff --git a/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockTextColor-webkit-darwin.png b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockTextColor-webkit-darwin.png new file mode 100644 index 0000000000..f3d01a4dc9 Binary files /dev/null and b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockTextColor-webkit-darwin.png differ diff --git a/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockTextColorTable-chromium-darwin.png b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockTextColorTable-chromium-darwin.png new file mode 100644 index 0000000000..68798900a4 Binary files /dev/null and b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockTextColorTable-chromium-darwin.png differ diff --git a/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockTextColorTable-firefox-darwin.png b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockTextColorTable-firefox-darwin.png new file mode 100644 index 0000000000..99a717b056 Binary files /dev/null and b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockTextColorTable-firefox-darwin.png differ diff --git a/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockTextColorTable-webkit-darwin.png b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockTextColorTable-webkit-darwin.png new file mode 100644 index 0000000000..02a2dbf91d Binary files /dev/null and b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/blockTextColorTable-webkit-darwin.png differ diff --git a/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/colorPickerFormattingToolbar-chromium-darwin.png b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/colorPickerFormattingToolbar-chromium-darwin.png new file mode 100644 index 0000000000..51c9a4ba1c Binary files /dev/null and b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/colorPickerFormattingToolbar-chromium-darwin.png differ diff --git a/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/colorPickerFormattingToolbar-firefox-darwin.png b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/colorPickerFormattingToolbar-firefox-darwin.png new file mode 100644 index 0000000000..1fbdaafd35 Binary files /dev/null and b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/colorPickerFormattingToolbar-firefox-darwin.png differ diff --git a/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/colorPickerFormattingToolbar-webkit-darwin.png b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/colorPickerFormattingToolbar-webkit-darwin.png new file mode 100644 index 0000000000..1e88bcae18 Binary files /dev/null and b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/colorPickerFormattingToolbar-webkit-darwin.png differ diff --git a/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/colorPickerSideMenu-chromium-darwin.png b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/colorPickerSideMenu-chromium-darwin.png new file mode 100644 index 0000000000..ee26a78962 Binary files /dev/null and b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/colorPickerSideMenu-chromium-darwin.png differ diff --git a/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/colorPickerSideMenu-firefox-darwin.png b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/colorPickerSideMenu-firefox-darwin.png new file mode 100644 index 0000000000..c0868e264f Binary files /dev/null and b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/colorPickerSideMenu-firefox-darwin.png differ diff --git a/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/colorPickerSideMenu-webkit-darwin.png b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/colorPickerSideMenu-webkit-darwin.png new file mode 100644 index 0000000000..293cf8c131 Binary files /dev/null and b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/colorPickerSideMenu-webkit-darwin.png differ diff --git a/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/textColorMark-chromium-darwin.png b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/textColorMark-chromium-darwin.png new file mode 100644 index 0000000000..c18cf039c8 Binary files /dev/null and b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/textColorMark-chromium-darwin.png differ diff --git a/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/textColorMark-firefox-darwin.png b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/textColorMark-firefox-darwin.png new file mode 100644 index 0000000000..fb46bd27d1 Binary files /dev/null and b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/textColorMark-firefox-darwin.png differ diff --git a/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/textColorMark-webkit-darwin.png b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/textColorMark-webkit-darwin.png new file mode 100644 index 0000000000..1ad13e8306 Binary files /dev/null and b/tests/src/end-to-end/colors/__screenshots__/colors.test.tsx/textColorMark-webkit-darwin.png differ diff --git a/tests/src/end-to-end/customblocks/__screenshots__/customblocks.test.tsx/react-interactivity-chromium-darwin.png b/tests/src/end-to-end/customblocks/__screenshots__/customblocks.test.tsx/react-interactivity-chromium-darwin.png new file mode 100644 index 0000000000..de8dbffa5d Binary files /dev/null and b/tests/src/end-to-end/customblocks/__screenshots__/customblocks.test.tsx/react-interactivity-chromium-darwin.png differ diff --git a/tests/src/end-to-end/customblocks/__screenshots__/customblocks.test.tsx/react-interactivity-firefox-darwin.png b/tests/src/end-to-end/customblocks/__screenshots__/customblocks.test.tsx/react-interactivity-firefox-darwin.png new file mode 100644 index 0000000000..a4fb4c0bfa Binary files /dev/null and b/tests/src/end-to-end/customblocks/__screenshots__/customblocks.test.tsx/react-interactivity-firefox-darwin.png differ diff --git a/tests/src/end-to-end/customblocks/__screenshots__/customblocks.test.tsx/react-interactivity-webkit-darwin.png b/tests/src/end-to-end/customblocks/__screenshots__/customblocks.test.tsx/react-interactivity-webkit-darwin.png new file mode 100644 index 0000000000..d66edd7bed Binary files /dev/null and b/tests/src/end-to-end/customblocks/__screenshots__/customblocks.test.tsx/react-interactivity-webkit-darwin.png differ diff --git a/tests/src/end-to-end/customblocks/__screenshots__/customblocks.test.tsx/vanilla-interactivity-chromium-darwin.png b/tests/src/end-to-end/customblocks/__screenshots__/customblocks.test.tsx/vanilla-interactivity-chromium-darwin.png new file mode 100644 index 0000000000..639655e922 Binary files /dev/null and b/tests/src/end-to-end/customblocks/__screenshots__/customblocks.test.tsx/vanilla-interactivity-chromium-darwin.png differ diff --git a/tests/src/end-to-end/customblocks/__screenshots__/customblocks.test.tsx/vanilla-interactivity-firefox-darwin.png b/tests/src/end-to-end/customblocks/__screenshots__/customblocks.test.tsx/vanilla-interactivity-firefox-darwin.png new file mode 100644 index 0000000000..957081346a Binary files /dev/null and b/tests/src/end-to-end/customblocks/__screenshots__/customblocks.test.tsx/vanilla-interactivity-firefox-darwin.png differ diff --git a/tests/src/end-to-end/customblocks/__screenshots__/customblocks.test.tsx/vanilla-interactivity-webkit-darwin.png b/tests/src/end-to-end/customblocks/__screenshots__/customblocks.test.tsx/vanilla-interactivity-webkit-darwin.png new file mode 100644 index 0000000000..8502feb5d1 Binary files /dev/null and b/tests/src/end-to-end/customblocks/__screenshots__/customblocks.test.tsx/vanilla-interactivity-webkit-darwin.png differ diff --git a/tests/src/end-to-end/draghandle/__screenshots__/draghandle.test.tsx/draghandlemenu-chromium-darwin.png b/tests/src/end-to-end/draghandle/__screenshots__/draghandle.test.tsx/draghandlemenu-chromium-darwin.png new file mode 100644 index 0000000000..70ea279d84 Binary files /dev/null and b/tests/src/end-to-end/draghandle/__screenshots__/draghandle.test.tsx/draghandlemenu-chromium-darwin.png differ diff --git a/tests/src/end-to-end/draghandle/__screenshots__/draghandle.test.tsx/draghandlemenu-firefox-darwin.png b/tests/src/end-to-end/draghandle/__screenshots__/draghandle.test.tsx/draghandlemenu-firefox-darwin.png new file mode 100644 index 0000000000..22773b4a75 Binary files /dev/null and b/tests/src/end-to-end/draghandle/__screenshots__/draghandle.test.tsx/draghandlemenu-firefox-darwin.png differ diff --git a/tests/src/end-to-end/draghandle/__screenshots__/draghandle.test.tsx/draghandlemenu-webkit-darwin.png b/tests/src/end-to-end/draghandle/__screenshots__/draghandle.test.tsx/draghandlemenu-webkit-darwin.png new file mode 100644 index 0000000000..eb4066cfd2 Binary files /dev/null and b/tests/src/end-to-end/draghandle/__screenshots__/draghandle.test.tsx/draghandlemenu-webkit-darwin.png differ diff --git a/tests/src/end-to-end/images/__screenshots__/images.test.tsx/create-image-chromium-darwin.png b/tests/src/end-to-end/images/__screenshots__/images.test.tsx/create-image-chromium-darwin.png new file mode 100644 index 0000000000..ed0903b1a9 Binary files /dev/null and b/tests/src/end-to-end/images/__screenshots__/images.test.tsx/create-image-chromium-darwin.png differ diff --git a/tests/src/end-to-end/images/__screenshots__/images.test.tsx/create-image-firefox-darwin.png b/tests/src/end-to-end/images/__screenshots__/images.test.tsx/create-image-firefox-darwin.png new file mode 100644 index 0000000000..f01c15cae1 Binary files /dev/null and b/tests/src/end-to-end/images/__screenshots__/images.test.tsx/create-image-firefox-darwin.png differ diff --git a/tests/src/end-to-end/images/__screenshots__/images.test.tsx/create-image-webkit-darwin.png b/tests/src/end-to-end/images/__screenshots__/images.test.tsx/create-image-webkit-darwin.png new file mode 100644 index 0000000000..b2054dfabb Binary files /dev/null and b/tests/src/end-to-end/images/__screenshots__/images.test.tsx/create-image-webkit-darwin.png differ diff --git a/tests/src/end-to-end/images/__screenshots__/images.test.tsx/embed-image-chromium-darwin.png b/tests/src/end-to-end/images/__screenshots__/images.test.tsx/embed-image-chromium-darwin.png new file mode 100644 index 0000000000..4b37572735 Binary files /dev/null and b/tests/src/end-to-end/images/__screenshots__/images.test.tsx/embed-image-chromium-darwin.png differ diff --git a/tests/src/end-to-end/images/__screenshots__/images.test.tsx/embed-image-firefox-darwin.png b/tests/src/end-to-end/images/__screenshots__/images.test.tsx/embed-image-firefox-darwin.png new file mode 100644 index 0000000000..76cc4cf4da Binary files /dev/null and b/tests/src/end-to-end/images/__screenshots__/images.test.tsx/embed-image-firefox-darwin.png differ diff --git a/tests/src/end-to-end/images/__screenshots__/images.test.tsx/embed-image-webkit-darwin.png b/tests/src/end-to-end/images/__screenshots__/images.test.tsx/embed-image-webkit-darwin.png new file mode 100644 index 0000000000..4c2fd0cc64 Binary files /dev/null and b/tests/src/end-to-end/images/__screenshots__/images.test.tsx/embed-image-webkit-darwin.png differ diff --git a/tests/src/end-to-end/images/__screenshots__/images.test.tsx/resize-image-chromium-darwin.png b/tests/src/end-to-end/images/__screenshots__/images.test.tsx/resize-image-chromium-darwin.png new file mode 100644 index 0000000000..d32702ca5b Binary files /dev/null and b/tests/src/end-to-end/images/__screenshots__/images.test.tsx/resize-image-chromium-darwin.png differ diff --git a/tests/src/end-to-end/images/__screenshots__/images.test.tsx/resize-image-firefox-darwin.png b/tests/src/end-to-end/images/__screenshots__/images.test.tsx/resize-image-firefox-darwin.png new file mode 100644 index 0000000000..7f28b06902 Binary files /dev/null and b/tests/src/end-to-end/images/__screenshots__/images.test.tsx/resize-image-firefox-darwin.png differ diff --git a/tests/src/end-to-end/images/__screenshots__/images.test.tsx/resize-image-webkit-darwin.png b/tests/src/end-to-end/images/__screenshots__/images.test.tsx/resize-image-webkit-darwin.png new file mode 100644 index 0000000000..1a2a502e44 Binary files /dev/null and b/tests/src/end-to-end/images/__screenshots__/images.test.tsx/resize-image-webkit-darwin.png differ diff --git a/tests/src/end-to-end/keyboardhandlers/__snapshots__/backspacePreservesNestedBlocks.json b/tests/src/end-to-end/keyboardhandlers/__snapshots__/backspacePreservesNestedBlocks.json index 3f10691703..d92226edab 100644 --- a/tests/src/end-to-end/keyboardhandlers/__snapshots__/backspacePreservesNestedBlocks.json +++ b/tests/src/end-to-end/keyboardhandlers/__snapshots__/backspacePreservesNestedBlocks.json @@ -20,7 +20,7 @@ "content": [ { "type": "text", - "text": "ParagraphParagraph" + "text": "Paragraph" } ] } @@ -29,7 +29,7 @@ { "type": "blockContainer", "attrs": { - "id": "2" + "id": "1" }, "content": [ { @@ -42,7 +42,7 @@ "content": [ { "type": "text", - "text": "Paragraph" + "text": "Paragrap" } ] }, @@ -52,7 +52,7 @@ { "type": "blockContainer", "attrs": { - "id": "3" + "id": "2" }, "content": [ { @@ -68,6 +68,33 @@ "text": "Paragraph" } ] + }, + { + "type": "blockGroup", + "content": [ + { + "type": "blockContainer", + "attrs": { + "id": "3" + }, + "content": [ + { + "type": "paragraph", + "attrs": { + "backgroundColor": "default", + "textColor": "default", + "textAlignment": "left" + }, + "content": [ + { + "type": "text", + "text": "Paragraph" + } + ] + } + ] + } + ] } ] } diff --git a/tests/src/end-to-end/placeholder/__screenshots__/placeholder.test.tsx/initial-placeholder-chromium-darwin.png b/tests/src/end-to-end/placeholder/__screenshots__/placeholder.test.tsx/initial-placeholder-chromium-darwin.png new file mode 100644 index 0000000000..9a0b0c4757 Binary files /dev/null and b/tests/src/end-to-end/placeholder/__screenshots__/placeholder.test.tsx/initial-placeholder-chromium-darwin.png differ diff --git a/tests/src/end-to-end/placeholder/__screenshots__/placeholder.test.tsx/initial-placeholder-firefox-darwin.png b/tests/src/end-to-end/placeholder/__screenshots__/placeholder.test.tsx/initial-placeholder-firefox-darwin.png new file mode 100644 index 0000000000..3369e5cedf Binary files /dev/null and b/tests/src/end-to-end/placeholder/__screenshots__/placeholder.test.tsx/initial-placeholder-firefox-darwin.png differ diff --git a/tests/src/end-to-end/placeholder/__screenshots__/placeholder.test.tsx/initial-placeholder-webkit-darwin.png b/tests/src/end-to-end/placeholder/__screenshots__/placeholder.test.tsx/initial-placeholder-webkit-darwin.png new file mode 100644 index 0000000000..5af893e42a Binary files /dev/null and b/tests/src/end-to-end/placeholder/__screenshots__/placeholder.test.tsx/initial-placeholder-webkit-darwin.png differ diff --git a/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-drag-handle-menu-chromium-darwin.png b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-drag-handle-menu-chromium-darwin.png new file mode 100644 index 0000000000..4a56990e6d Binary files /dev/null and b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-drag-handle-menu-chromium-darwin.png differ diff --git a/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-drag-handle-menu-firefox-darwin.png b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-drag-handle-menu-firefox-darwin.png new file mode 100644 index 0000000000..9efdd1f62b Binary files /dev/null and b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-drag-handle-menu-firefox-darwin.png differ diff --git a/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-drag-handle-menu-webkit-darwin.png b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-drag-handle-menu-webkit-darwin.png new file mode 100644 index 0000000000..081785cc6c Binary files /dev/null and b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-drag-handle-menu-webkit-darwin.png differ diff --git a/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-emoji-picker-chromium-darwin.png b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-emoji-picker-chromium-darwin.png new file mode 100644 index 0000000000..b01558fa8c Binary files /dev/null and b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-emoji-picker-chromium-darwin.png differ diff --git a/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-emoji-picker-firefox-darwin.png b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-emoji-picker-firefox-darwin.png new file mode 100644 index 0000000000..6748e9d0a4 Binary files /dev/null and b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-emoji-picker-firefox-darwin.png differ diff --git a/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-emoji-picker-webkit-darwin.png b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-emoji-picker-webkit-darwin.png new file mode 100644 index 0000000000..d287aa89f1 Binary files /dev/null and b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-emoji-picker-webkit-darwin.png differ diff --git a/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-formatting-toolbar-chromium-darwin.png b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-formatting-toolbar-chromium-darwin.png new file mode 100644 index 0000000000..5b5d882f71 Binary files /dev/null and b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-formatting-toolbar-chromium-darwin.png differ diff --git a/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-formatting-toolbar-firefox-darwin.png b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-formatting-toolbar-firefox-darwin.png new file mode 100644 index 0000000000..c46f8abd75 Binary files /dev/null and b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-formatting-toolbar-firefox-darwin.png differ diff --git a/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-formatting-toolbar-webkit-darwin.png b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-formatting-toolbar-webkit-darwin.png new file mode 100644 index 0000000000..0cc8d4b65a Binary files /dev/null and b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-formatting-toolbar-webkit-darwin.png differ diff --git a/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-image-toolbar-chromium-darwin.png b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-image-toolbar-chromium-darwin.png new file mode 100644 index 0000000000..e7d6337719 Binary files /dev/null and b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-image-toolbar-chromium-darwin.png differ diff --git a/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-image-toolbar-firefox-darwin.png b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-image-toolbar-firefox-darwin.png new file mode 100644 index 0000000000..ea12e3e9a5 Binary files /dev/null and b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-image-toolbar-firefox-darwin.png differ diff --git a/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-image-toolbar-webkit-darwin.png b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-image-toolbar-webkit-darwin.png new file mode 100644 index 0000000000..45eb1bc4cc Binary files /dev/null and b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-image-toolbar-webkit-darwin.png differ diff --git a/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-link-toolbar-chromium-darwin.png b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-link-toolbar-chromium-darwin.png new file mode 100644 index 0000000000..c68a52eb59 Binary files /dev/null and b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-link-toolbar-chromium-darwin.png differ diff --git a/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-link-toolbar-firefox-darwin.png b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-link-toolbar-firefox-darwin.png new file mode 100644 index 0000000000..bc6549ba63 Binary files /dev/null and b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-link-toolbar-firefox-darwin.png differ diff --git a/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-link-toolbar-webkit-darwin.png b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-link-toolbar-webkit-darwin.png new file mode 100644 index 0000000000..620b249ed5 Binary files /dev/null and b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-link-toolbar-webkit-darwin.png differ diff --git a/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-side-menu-chromium-darwin.png b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-side-menu-chromium-darwin.png new file mode 100644 index 0000000000..39b0974af2 Binary files /dev/null and b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-side-menu-chromium-darwin.png differ diff --git a/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-side-menu-firefox-darwin.png b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-side-menu-firefox-darwin.png new file mode 100644 index 0000000000..44c4e5264c Binary files /dev/null and b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-side-menu-firefox-darwin.png differ diff --git a/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-side-menu-webkit-darwin.png b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-side-menu-webkit-darwin.png new file mode 100644 index 0000000000..329e7eec0f Binary files /dev/null and b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-side-menu-webkit-darwin.png differ diff --git a/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-slash-menu-chromium-darwin.png b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-slash-menu-chromium-darwin.png new file mode 100644 index 0000000000..2d697e8c1e Binary files /dev/null and b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-slash-menu-chromium-darwin.png differ diff --git a/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-slash-menu-firefox-darwin.png b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-slash-menu-firefox-darwin.png new file mode 100644 index 0000000000..6a347e1da9 Binary files /dev/null and b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-slash-menu-firefox-darwin.png differ diff --git a/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-slash-menu-webkit-darwin.png b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-slash-menu-webkit-darwin.png new file mode 100644 index 0000000000..f63c65c521 Binary files /dev/null and b/tests/src/end-to-end/shadcn/__screenshots__/shadcn.test.tsx/shadcn-slash-menu-webkit-darwin.png differ diff --git a/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_end_product-chromium-darwin.png b/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_end_product-chromium-darwin.png new file mode 100644 index 0000000000..10c922b846 Binary files /dev/null and b/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_end_product-chromium-darwin.png differ diff --git a/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_end_product-firefox-darwin.png b/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_end_product-firefox-darwin.png new file mode 100644 index 0000000000..c2c5daf93c Binary files /dev/null and b/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_end_product-firefox-darwin.png differ diff --git a/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_end_product-webkit-darwin.png b/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_end_product-webkit-darwin.png new file mode 100644 index 0000000000..703b2370a6 Binary files /dev/null and b/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_end_product-webkit-darwin.png differ diff --git a/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_page_down-chromium-darwin.png b/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_page_down-chromium-darwin.png new file mode 100644 index 0000000000..fb7fa571a4 Binary files /dev/null and b/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_page_down-chromium-darwin.png differ diff --git a/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_page_down-firefox-darwin.png b/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_page_down-firefox-darwin.png new file mode 100644 index 0000000000..c58468b198 Binary files /dev/null and b/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_page_down-firefox-darwin.png differ diff --git a/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_page_down-webkit-darwin.png b/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_page_down-webkit-darwin.png new file mode 100644 index 0000000000..deb69f5967 Binary files /dev/null and b/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_page_down-webkit-darwin.png differ diff --git a/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_page_up-chromium-darwin.png b/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_page_up-chromium-darwin.png new file mode 100644 index 0000000000..3148e4956f Binary files /dev/null and b/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_page_up-chromium-darwin.png differ diff --git a/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_page_up-firefox-darwin.png b/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_page_up-firefox-darwin.png new file mode 100644 index 0000000000..f0986ff1b1 Binary files /dev/null and b/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_page_up-firefox-darwin.png differ diff --git a/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_page_up-webkit-darwin.png b/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_page_up-webkit-darwin.png new file mode 100644 index 0000000000..f70a319fc5 Binary files /dev/null and b/tests/src/end-to-end/slashmenu/__screenshots__/slashmenu.test.tsx/slash_menu_page_up-webkit-darwin.png differ diff --git a/tests/src/end-to-end/static/__screenshots__/static.test.tsx/static-rendering-chromium-darwin.png b/tests/src/end-to-end/static/__screenshots__/static.test.tsx/static-rendering-chromium-darwin.png new file mode 100644 index 0000000000..5b867d97ad Binary files /dev/null and b/tests/src/end-to-end/static/__screenshots__/static.test.tsx/static-rendering-chromium-darwin.png differ diff --git a/tests/src/end-to-end/static/__screenshots__/static.test.tsx/static-rendering-equality-chromium-darwin.png b/tests/src/end-to-end/static/__screenshots__/static.test.tsx/static-rendering-equality-chromium-darwin.png new file mode 100644 index 0000000000..149d5716a4 Binary files /dev/null and b/tests/src/end-to-end/static/__screenshots__/static.test.tsx/static-rendering-equality-chromium-darwin.png differ diff --git a/tests/src/end-to-end/static/__screenshots__/static.test.tsx/static-rendering-equality-firefox-darwin.png b/tests/src/end-to-end/static/__screenshots__/static.test.tsx/static-rendering-equality-firefox-darwin.png new file mode 100644 index 0000000000..3510171575 Binary files /dev/null and b/tests/src/end-to-end/static/__screenshots__/static.test.tsx/static-rendering-equality-firefox-darwin.png differ diff --git a/tests/src/end-to-end/static/__screenshots__/static.test.tsx/static-rendering-equality-webkit-darwin.png b/tests/src/end-to-end/static/__screenshots__/static.test.tsx/static-rendering-equality-webkit-darwin.png new file mode 100644 index 0000000000..bf6c079190 Binary files /dev/null and b/tests/src/end-to-end/static/__screenshots__/static.test.tsx/static-rendering-equality-webkit-darwin.png differ diff --git a/tests/src/end-to-end/static/__screenshots__/static.test.tsx/static-rendering-firefox-darwin.png b/tests/src/end-to-end/static/__screenshots__/static.test.tsx/static-rendering-firefox-darwin.png new file mode 100644 index 0000000000..5a799a1028 Binary files /dev/null and b/tests/src/end-to-end/static/__screenshots__/static.test.tsx/static-rendering-firefox-darwin.png differ diff --git a/tests/src/end-to-end/static/__screenshots__/static.test.tsx/static-rendering-webkit-darwin.png b/tests/src/end-to-end/static/__screenshots__/static.test.tsx/static-rendering-webkit-darwin.png new file mode 100644 index 0000000000..86896d1535 Binary files /dev/null and b/tests/src/end-to-end/static/__screenshots__/static.test.tsx/static-rendering-webkit-darwin.png differ diff --git a/tests/src/end-to-end/tables/__screenshots__/advancedtables.test.tsx/tableCellColors-chromium-darwin.png b/tests/src/end-to-end/tables/__screenshots__/advancedtables.test.tsx/tableCellColors-chromium-darwin.png new file mode 100644 index 0000000000..478accd5c0 Binary files /dev/null and b/tests/src/end-to-end/tables/__screenshots__/advancedtables.test.tsx/tableCellColors-chromium-darwin.png differ diff --git a/tests/src/end-to-end/tables/__screenshots__/advancedtables.test.tsx/tableCellColors-firefox-darwin.png b/tests/src/end-to-end/tables/__screenshots__/advancedtables.test.tsx/tableCellColors-firefox-darwin.png new file mode 100644 index 0000000000..1b87c19fe0 Binary files /dev/null and b/tests/src/end-to-end/tables/__screenshots__/advancedtables.test.tsx/tableCellColors-firefox-darwin.png differ diff --git a/tests/src/end-to-end/tables/__screenshots__/advancedtables.test.tsx/tableCellColors-webkit-darwin.png b/tests/src/end-to-end/tables/__screenshots__/advancedtables.test.tsx/tableCellColors-webkit-darwin.png new file mode 100644 index 0000000000..04096b19ee Binary files /dev/null and b/tests/src/end-to-end/tables/__screenshots__/advancedtables.test.tsx/tableCellColors-webkit-darwin.png differ diff --git a/tests/src/end-to-end/textalignment/__screenshots__/textAlignment.test.tsx/alignTextMultipleBlocks-chromium-darwin.png b/tests/src/end-to-end/textalignment/__screenshots__/textAlignment.test.tsx/alignTextMultipleBlocks-chromium-darwin.png new file mode 100644 index 0000000000..9346f93f7c Binary files /dev/null and b/tests/src/end-to-end/textalignment/__screenshots__/textAlignment.test.tsx/alignTextMultipleBlocks-chromium-darwin.png differ diff --git a/tests/src/end-to-end/textalignment/__screenshots__/textAlignment.test.tsx/alignTextMultipleBlocks-firefox-darwin.png b/tests/src/end-to-end/textalignment/__screenshots__/textAlignment.test.tsx/alignTextMultipleBlocks-firefox-darwin.png new file mode 100644 index 0000000000..14f49a48bd Binary files /dev/null and b/tests/src/end-to-end/textalignment/__screenshots__/textAlignment.test.tsx/alignTextMultipleBlocks-firefox-darwin.png differ diff --git a/tests/src/end-to-end/textalignment/__screenshots__/textAlignment.test.tsx/alignTextMultipleBlocks-webkit-darwin.png b/tests/src/end-to-end/textalignment/__screenshots__/textAlignment.test.tsx/alignTextMultipleBlocks-webkit-darwin.png new file mode 100644 index 0000000000..2ecd69e233 Binary files /dev/null and b/tests/src/end-to-end/textalignment/__screenshots__/textAlignment.test.tsx/alignTextMultipleBlocks-webkit-darwin.png differ diff --git a/tests/src/end-to-end/textalignment/__screenshots__/textAlignment.test.tsx/alignTextSingleBlock-chromium-darwin.png b/tests/src/end-to-end/textalignment/__screenshots__/textAlignment.test.tsx/alignTextSingleBlock-chromium-darwin.png new file mode 100644 index 0000000000..ac3b7805bc Binary files /dev/null and b/tests/src/end-to-end/textalignment/__screenshots__/textAlignment.test.tsx/alignTextSingleBlock-chromium-darwin.png differ diff --git a/tests/src/end-to-end/textalignment/__screenshots__/textAlignment.test.tsx/alignTextSingleBlock-firefox-darwin.png b/tests/src/end-to-end/textalignment/__screenshots__/textAlignment.test.tsx/alignTextSingleBlock-firefox-darwin.png new file mode 100644 index 0000000000..11aa026792 Binary files /dev/null and b/tests/src/end-to-end/textalignment/__screenshots__/textAlignment.test.tsx/alignTextSingleBlock-firefox-darwin.png differ diff --git a/tests/src/end-to-end/textalignment/__screenshots__/textAlignment.test.tsx/alignTextSingleBlock-webkit-darwin.png b/tests/src/end-to-end/textalignment/__screenshots__/textAlignment.test.tsx/alignTextSingleBlock-webkit-darwin.png new file mode 100644 index 0000000000..1b11ccd6ee Binary files /dev/null and b/tests/src/end-to-end/textalignment/__screenshots__/textAlignment.test.tsx/alignTextSingleBlock-webkit-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-drag-handle-menu-chromium-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-drag-handle-menu-chromium-darwin.png new file mode 100644 index 0000000000..d57904f3f3 Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-drag-handle-menu-chromium-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-drag-handle-menu-firefox-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-drag-handle-menu-firefox-darwin.png new file mode 100644 index 0000000000..0642ced230 Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-drag-handle-menu-firefox-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-drag-handle-menu-webkit-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-drag-handle-menu-webkit-darwin.png new file mode 100644 index 0000000000..5018cc5727 Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-drag-handle-menu-webkit-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-editor-chromium-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-editor-chromium-darwin.png new file mode 100644 index 0000000000..072db36c62 Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-editor-chromium-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-editor-firefox-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-editor-firefox-darwin.png new file mode 100644 index 0000000000..3b4906c23d Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-editor-firefox-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-editor-webkit-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-editor-webkit-darwin.png new file mode 100644 index 0000000000..4b2355d0e4 Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-editor-webkit-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-emoji-picker-chromium-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-emoji-picker-chromium-darwin.png new file mode 100644 index 0000000000..183c045a07 Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-emoji-picker-chromium-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-emoji-picker-firefox-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-emoji-picker-firefox-darwin.png new file mode 100644 index 0000000000..630b5e0191 Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-emoji-picker-firefox-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-emoji-picker-webkit-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-emoji-picker-webkit-darwin.png new file mode 100644 index 0000000000..3a32e3921b Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-emoji-picker-webkit-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-formatting-toolbar-chromium-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-formatting-toolbar-chromium-darwin.png new file mode 100644 index 0000000000..539a4b2565 Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-formatting-toolbar-chromium-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-formatting-toolbar-firefox-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-formatting-toolbar-firefox-darwin.png new file mode 100644 index 0000000000..91fef7b028 Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-formatting-toolbar-firefox-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-formatting-toolbar-webkit-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-formatting-toolbar-webkit-darwin.png new file mode 100644 index 0000000000..dcd9cd107f Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-formatting-toolbar-webkit-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-image-toolbar-chromium-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-image-toolbar-chromium-darwin.png new file mode 100644 index 0000000000..0a6d67d0f8 Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-image-toolbar-chromium-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-image-toolbar-firefox-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-image-toolbar-firefox-darwin.png new file mode 100644 index 0000000000..cea4cd7495 Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-image-toolbar-firefox-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-image-toolbar-webkit-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-image-toolbar-webkit-darwin.png new file mode 100644 index 0000000000..efa8bb1002 Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-image-toolbar-webkit-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-link-toolbar-chromium-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-link-toolbar-chromium-darwin.png new file mode 100644 index 0000000000..b9db796e44 Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-link-toolbar-chromium-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-link-toolbar-firefox-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-link-toolbar-firefox-darwin.png new file mode 100644 index 0000000000..0ad29afb5a Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-link-toolbar-firefox-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-link-toolbar-webkit-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-link-toolbar-webkit-darwin.png new file mode 100644 index 0000000000..c7a6f48071 Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-link-toolbar-webkit-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-side-menu-chromium-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-side-menu-chromium-darwin.png new file mode 100644 index 0000000000..aa1161039a Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-side-menu-chromium-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-side-menu-firefox-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-side-menu-firefox-darwin.png new file mode 100644 index 0000000000..6b4b884136 Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-side-menu-firefox-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-side-menu-webkit-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-side-menu-webkit-darwin.png new file mode 100644 index 0000000000..c5a782eecc Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-side-menu-webkit-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-slash-menu-chromium-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-slash-menu-chromium-darwin.png new file mode 100644 index 0000000000..601f767a1f Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-slash-menu-chromium-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-slash-menu-firefox-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-slash-menu-firefox-darwin.png new file mode 100644 index 0000000000..dcadc50f42 Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-slash-menu-firefox-darwin.png differ diff --git a/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-slash-menu-webkit-darwin.png b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-slash-menu-webkit-darwin.png new file mode 100644 index 0000000000..14fa2bef5f Binary files /dev/null and b/tests/src/end-to-end/theming/__screenshots__/theming.test.tsx/dark-slash-menu-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-add-heading-to-empty-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-add-heading-to-empty-chromium-darwin.png new file mode 100644 index 0000000000..9ac7de87e3 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-add-heading-to-empty-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-add-heading-to-empty-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-add-heading-to-empty-firefox-darwin.png new file mode 100644 index 0000000000..f77316b34a Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-add-heading-to-empty-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-add-heading-to-empty-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-add-heading-to-empty-webkit-darwin.png new file mode 100644 index 0000000000..e46cf790bd Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-add-heading-to-empty-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-add-paragraph-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-add-paragraph-chromium-darwin.png new file mode 100644 index 0000000000..7879863915 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-add-paragraph-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-add-paragraph-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-add-paragraph-firefox-darwin.png new file mode 100644 index 0000000000..c460c7a034 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-add-paragraph-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-add-paragraph-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-add-paragraph-webkit-darwin.png new file mode 100644 index 0000000000..ce8964ecf2 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-add-paragraph-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-delete-image-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-delete-image-chromium-darwin.png new file mode 100644 index 0000000000..02eb72e568 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-delete-image-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-delete-nested-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-delete-nested-chromium-darwin.png new file mode 100644 index 0000000000..9b8c040c43 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-delete-nested-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-delete-nested-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-delete-nested-firefox-darwin.png new file mode 100644 index 0000000000..7a22157eab Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-delete-nested-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-delete-nested-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-delete-nested-webkit-darwin.png new file mode 100644 index 0000000000..87a87b9e3d Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-delete-nested-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-delete-parent-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-delete-parent-chromium-darwin.png new file mode 100644 index 0000000000..53b74fc34c Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-delete-parent-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-delete-parent-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-delete-parent-firefox-darwin.png new file mode 100644 index 0000000000..a638030fb7 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-delete-parent-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-delete-parent-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-delete-parent-webkit-darwin.png new file mode 100644 index 0000000000..66b591fb64 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-delete-parent-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-remove-all-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-remove-all-chromium-darwin.png new file mode 100644 index 0000000000..91ade80f28 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-remove-all-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-remove-all-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-remove-all-firefox-darwin.png new file mode 100644 index 0000000000..add8ffa437 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-remove-all-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-remove-all-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-remove-all-webkit-darwin.png new file mode 100644 index 0000000000..5f26fdce0d Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-remove-all-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-remove-paragraph-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-remove-paragraph-chromium-darwin.png new file mode 100644 index 0000000000..c1b96c3c30 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-remove-paragraph-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-remove-paragraph-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-remove-paragraph-firefox-darwin.png new file mode 100644 index 0000000000..fe7e5fd740 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-remove-paragraph-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-remove-paragraph-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-remove-paragraph-webkit-darwin.png new file mode 100644 index 0000000000..b65e654ca5 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/addRemoveBlocks.test.tsx/add-remove-remove-paragraph-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.concurrent.test.tsx/concurrent-bold-vs-italic-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.concurrent.test.tsx/concurrent-bold-vs-italic-chromium-darwin.png new file mode 100644 index 0000000000..72db5c194b Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.concurrent.test.tsx/concurrent-bold-vs-italic-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.concurrent.test.tsx/concurrent-bold-vs-italic-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.concurrent.test.tsx/concurrent-bold-vs-italic-firefox-darwin.png new file mode 100644 index 0000000000..99acc7fe77 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.concurrent.test.tsx/concurrent-bold-vs-italic-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.concurrent.test.tsx/concurrent-bold-vs-italic-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.concurrent.test.tsx/concurrent-bold-vs-italic-webkit-darwin.png new file mode 100644 index 0000000000..a80142d25f Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.concurrent.test.tsx/concurrent-bold-vs-italic-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.concurrent.test.tsx/concurrent-typo-fix-vs-delete-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.concurrent.test.tsx/concurrent-typo-fix-vs-delete-chromium-darwin.png new file mode 100644 index 0000000000..88a1658327 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.concurrent.test.tsx/concurrent-typo-fix-vs-delete-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.concurrent.test.tsx/concurrent-typo-fix-vs-delete-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.concurrent.test.tsx/concurrent-typo-fix-vs-delete-firefox-darwin.png new file mode 100644 index 0000000000..efca4163df Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.concurrent.test.tsx/concurrent-typo-fix-vs-delete-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.concurrent.test.tsx/concurrent-typo-fix-vs-delete-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.concurrent.test.tsx/concurrent-typo-fix-vs-delete-webkit-darwin.png new file mode 100644 index 0000000000..8c1596d4d5 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.concurrent.test.tsx/concurrent-typo-fix-vs-delete-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-add-bold-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-add-bold-chromium-darwin.png new file mode 100644 index 0000000000..3368c3fa51 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-add-bold-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-add-bold-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-add-bold-firefox-darwin.png new file mode 100644 index 0000000000..78c97263d9 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-add-bold-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-add-bold-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-add-bold-webkit-darwin.png new file mode 100644 index 0000000000..89a3181f08 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-add-bold-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-add-italic-to-bold-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-add-italic-to-bold-chromium-darwin.png new file mode 100644 index 0000000000..81861d9e7a Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-add-italic-to-bold-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-add-italic-to-bold-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-add-italic-to-bold-firefox-darwin.png new file mode 100644 index 0000000000..9145a8a4e9 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-add-italic-to-bold-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-add-italic-to-bold-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-add-italic-to-bold-webkit-darwin.png new file mode 100644 index 0000000000..1e57496c89 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-add-italic-to-bold-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-remove-bold-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-remove-bold-chromium-darwin.png new file mode 100644 index 0000000000..a9ebe2792d Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-remove-bold-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-remove-bold-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-remove-bold-firefox-darwin.png new file mode 100644 index 0000000000..4db478eb5f Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-remove-bold-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-remove-bold-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-remove-bold-webkit-darwin.png new file mode 100644 index 0000000000..fb0b8dc150 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-remove-bold-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-universe-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-universe-chromium-darwin.png new file mode 100644 index 0000000000..65ccdd1333 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-universe-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-universe-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-universe-firefox-darwin.png new file mode 100644 index 0000000000..c820f29f74 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-universe-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-universe-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-universe-webkit-darwin.png new file mode 100644 index 0000000000..473e2f035c Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/basicText.test.tsx/suggestion-mode-universe-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/moveBlocks.test.tsx/move-paragraph-up-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/moveBlocks.test.tsx/move-paragraph-up-chromium-darwin.png new file mode 100644 index 0000000000..3c19857d00 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/moveBlocks.test.tsx/move-paragraph-up-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/moveBlocks.test.tsx/move-paragraph-up-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/moveBlocks.test.tsx/move-paragraph-up-firefox-darwin.png new file mode 100644 index 0000000000..5990832ff9 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/moveBlocks.test.tsx/move-paragraph-up-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/moveBlocks.test.tsx/move-paragraph-up-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/moveBlocks.test.tsx/move-paragraph-up-webkit-darwin.png new file mode 100644 index 0000000000..4f2e23d177 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/moveBlocks.test.tsx/move-paragraph-up-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/moveBlocks.test.tsx/move-paragraph-with-children-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/moveBlocks.test.tsx/move-paragraph-with-children-chromium-darwin.png new file mode 100644 index 0000000000..9ed6adc419 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/moveBlocks.test.tsx/move-paragraph-with-children-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/moveBlocks.test.tsx/move-paragraph-with-children-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/moveBlocks.test.tsx/move-paragraph-with-children-firefox-darwin.png new file mode 100644 index 0000000000..2b8d9f0126 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/moveBlocks.test.tsx/move-paragraph-with-children-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/moveBlocks.test.tsx/move-paragraph-with-children-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/moveBlocks.test.tsx/move-paragraph-with-children-webkit-darwin.png new file mode 100644 index 0000000000..72b2072332 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/moveBlocks.test.tsx/move-paragraph-with-children-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.concurrent.test.tsx/concurrent-indent-cascade-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.concurrent.test.tsx/concurrent-indent-cascade-chromium-darwin.png new file mode 100644 index 0000000000..db5c14698b Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.concurrent.test.tsx/concurrent-indent-cascade-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.concurrent.test.tsx/concurrent-indent-cascade-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.concurrent.test.tsx/concurrent-indent-cascade-firefox-darwin.png new file mode 100644 index 0000000000..3698464072 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.concurrent.test.tsx/concurrent-indent-cascade-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.concurrent.test.tsx/concurrent-indent-cascade-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.concurrent.test.tsx/concurrent-indent-cascade-webkit-darwin.png new file mode 100644 index 0000000000..566254eca7 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.concurrent.test.tsx/concurrent-indent-cascade-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.test.tsx/nesting-indent-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.test.tsx/nesting-indent-chromium-darwin.png new file mode 100644 index 0000000000..ba53b28c5c Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.test.tsx/nesting-indent-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.test.tsx/nesting-indent-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.test.tsx/nesting-indent-firefox-darwin.png new file mode 100644 index 0000000000..4374f8eb3f Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.test.tsx/nesting-indent-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.test.tsx/nesting-indent-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.test.tsx/nesting-indent-webkit-darwin.png new file mode 100644 index 0000000000..f7d6abc5b6 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.test.tsx/nesting-indent-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.test.tsx/nesting-unindent-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.test.tsx/nesting-unindent-chromium-darwin.png new file mode 100644 index 0000000000..320e6e64b9 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.test.tsx/nesting-unindent-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.test.tsx/nesting-unindent-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.test.tsx/nesting-unindent-firefox-darwin.png new file mode 100644 index 0000000000..ea23950a4f Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.test.tsx/nesting-unindent-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.test.tsx/nesting-unindent-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.test.tsx/nesting-unindent-webkit-darwin.png new file mode 100644 index 0000000000..b3b2110f33 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/nesting.test.tsx/nesting-unindent-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.concurrent.test.tsx/concurrent-textColor-vs-backgroundColor-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.concurrent.test.tsx/concurrent-textColor-vs-backgroundColor-chromium-darwin.png new file mode 100644 index 0000000000..e89115a122 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.concurrent.test.tsx/concurrent-textColor-vs-backgroundColor-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.concurrent.test.tsx/concurrent-textColor-vs-backgroundColor-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.concurrent.test.tsx/concurrent-textColor-vs-backgroundColor-webkit-darwin.png new file mode 100644 index 0000000000..8a270ebfd4 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.concurrent.test.tsx/concurrent-textColor-vs-backgroundColor-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-heading-level-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-heading-level-chromium-darwin.png new file mode 100644 index 0000000000..a24ea4f850 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-heading-level-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-heading-level-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-heading-level-firefox-darwin.png new file mode 100644 index 0000000000..86d8da9596 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-heading-level-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-heading-level-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-heading-level-webkit-darwin.png new file mode 100644 index 0000000000..93bb1d24af Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-heading-level-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-image-source-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-image-source-chromium-darwin.png new file mode 100644 index 0000000000..c70e7f109d Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-image-source-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-image-source-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-image-source-firefox-darwin.png new file mode 100644 index 0000000000..ad8d5fbc24 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-image-source-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-image-source-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-image-source-webkit-darwin.png new file mode 100644 index 0000000000..ce1c322908 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-image-source-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-image-width-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-image-width-chromium-darwin.png new file mode 100644 index 0000000000..de6f09ded9 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-image-width-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-image-width-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-image-width-firefox-darwin.png new file mode 100644 index 0000000000..382bed5ee6 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-image-width-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-image-width-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-image-width-webkit-darwin.png new file mode 100644 index 0000000000..a535f047fa Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-image-width-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-text-alignment-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-text-alignment-chromium-darwin.png new file mode 100644 index 0000000000..014cb49737 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-text-alignment-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-text-alignment-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-text-alignment-firefox-darwin.png new file mode 100644 index 0000000000..e05c74d5af Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-text-alignment-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-text-alignment-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-text-alignment-webkit-darwin.png new file mode 100644 index 0000000000..856a81831a Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/propChanges.test.tsx/prop-change-text-alignment-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-add-column-and-add-row-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-add-column-and-add-row-chromium-darwin.png new file mode 100644 index 0000000000..cb38158fbb Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-add-column-and-add-row-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-add-column-and-add-row-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-add-column-and-add-row-firefox-darwin.png new file mode 100644 index 0000000000..2a3e8a5477 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-add-column-and-add-row-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-add-column-and-add-row-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-add-column-and-add-row-webkit-darwin.png new file mode 100644 index 0000000000..6834223910 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-add-column-and-add-row-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-delete-column-vs-add-row-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-delete-column-vs-add-row-chromium-darwin.png new file mode 100644 index 0000000000..0983a7a95c Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-delete-column-vs-add-row-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-delete-column-vs-add-row-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-delete-column-vs-add-row-firefox-darwin.png new file mode 100644 index 0000000000..7a17319887 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-delete-column-vs-add-row-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-delete-column-vs-add-row-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-delete-column-vs-add-row-webkit-darwin.png new file mode 100644 index 0000000000..58b03f10be Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-delete-column-vs-add-row-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-row-and-column-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-row-and-column-chromium-darwin.png new file mode 100644 index 0000000000..0aa99ecb81 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-row-and-column-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-row-and-column-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-row-and-column-firefox-darwin.png new file mode 100644 index 0000000000..5c973ac7b4 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-row-and-column-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-row-and-column-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-row-and-column-webkit-darwin.png new file mode 100644 index 0000000000..3b2052ffb4 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.concurrent.test.tsx/table-concurrent-row-and-column-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-add-column-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-add-column-chromium-darwin.png new file mode 100644 index 0000000000..82e7337324 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-add-column-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-add-column-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-add-column-firefox-darwin.png new file mode 100644 index 0000000000..f5e5cc56dd Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-add-column-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-add-column-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-add-column-webkit-darwin.png new file mode 100644 index 0000000000..a9c056c9b4 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-add-column-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-add-row-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-add-row-chromium-darwin.png new file mode 100644 index 0000000000..2cf1fd4a9a Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-add-row-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-add-row-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-add-row-firefox-darwin.png new file mode 100644 index 0000000000..70356dc534 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-add-row-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-add-row-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-add-row-webkit-darwin.png new file mode 100644 index 0000000000..aa202f2039 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-add-row-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-column-color-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-column-color-chromium-darwin.png new file mode 100644 index 0000000000..5b425af816 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-column-color-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-column-color-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-column-color-firefox-darwin.png new file mode 100644 index 0000000000..d1916ed3a1 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-column-color-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-column-color-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-column-color-webkit-darwin.png new file mode 100644 index 0000000000..ecec49801d Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-column-color-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-edit-cell-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-edit-cell-chromium-darwin.png new file mode 100644 index 0000000000..6ba4f54b7d Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-edit-cell-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-edit-cell-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-edit-cell-firefox-darwin.png new file mode 100644 index 0000000000..153a296bea Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-edit-cell-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-edit-cell-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-edit-cell-webkit-darwin.png new file mode 100644 index 0000000000..4fc9f7d034 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-edit-cell-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-merge-cells-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-merge-cells-chromium-darwin.png new file mode 100644 index 0000000000..52b23207fc Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-merge-cells-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-merge-cells-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-merge-cells-firefox-darwin.png new file mode 100644 index 0000000000..6c09dc0540 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-merge-cells-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-merge-cells-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-merge-cells-webkit-darwin.png new file mode 100644 index 0000000000..c36595db15 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-merge-cells-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-remove-column-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-remove-column-chromium-darwin.png new file mode 100644 index 0000000000..8fc285a283 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-remove-column-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-remove-column-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-remove-column-firefox-darwin.png new file mode 100644 index 0000000000..856719e816 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-remove-column-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-remove-column-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-remove-column-webkit-darwin.png new file mode 100644 index 0000000000..f19c38507d Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-remove-column-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-remove-row-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-remove-row-chromium-darwin.png new file mode 100644 index 0000000000..b028cbad28 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-remove-row-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-remove-row-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-remove-row-firefox-darwin.png new file mode 100644 index 0000000000..7faf644412 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-remove-row-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-remove-row-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-remove-row-webkit-darwin.png new file mode 100644 index 0000000000..60393c7505 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-remove-row-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-split-cell-chromium-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-split-cell-chromium-darwin.png new file mode 100644 index 0000000000..e0349d9773 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-split-cell-chromium-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-split-cell-firefox-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-split-cell-firefox-darwin.png new file mode 100644 index 0000000000..5db212af52 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-split-cell-firefox-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-split-cell-webkit-darwin.png b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-split-cell-webkit-darwin.png new file mode 100644 index 0000000000..67fc1a41f7 Binary files /dev/null and b/tests/src/end-to-end/y-prosemirror/__screenshots__/tables.test.tsx/table-split-cell-webkit-darwin.png differ diff --git a/tests/src/end-to-end/y-prosemirror/addRemoveBlocks.test.tsx b/tests/src/end-to-end/y-prosemirror/addRemoveBlocks.test.tsx new file mode 100644 index 0000000000..9b13e2a8b9 --- /dev/null +++ b/tests/src/end-to-end/y-prosemirror/addRemoveBlocks.test.tsx @@ -0,0 +1,490 @@ +/* eslint-disable testing-library/render-result-naming-convention */ +/** + * Vitest browser-mode tests for add/remove block suggestions: + * inserting and deleting whole blocks (not just editing their text / + * props). Same shape as the other categories. + */ +import { SuggestionsExtension } from "@blocknote/core/y"; +import { expect, test } from "vite-plus/test"; +import { expectScreenshot, expectVisible } from "./fixtures/browserExpect.js"; + +import { + editorHtml, + setupSuggestionTest, + waitForSuggestion, + ydocXml, +} from "./fixtures/suggestionFixture.js"; + +// Inline SVG data URL – avoids a network fetch for the image src. +const IMG_SRC = + "data:image/svg+xml;utf8,"; + +// Empty doc gets a heading inserted at the top. +// KNOWN BUG: starting from a truly empty doc and using `replaceBlocks` +// to add a heading hits the same y-prosemirror `deltaToPSteps: +// No node at mark step's position` we already document for type +// changes (see `typeChanges.test.tsx`). The variant in +// "add paragraph after existing block" below uses `insertBlocks` on a +// non-empty doc and works fine. Marked `test.fails` until upstream. +test.fails("suggestion mode: add heading to empty doc", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "add heading at top" }); + + editor.replaceBlocks(editor.document, []); + sync(); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + editor.replaceBlocks(editor.document, [ + { id: "h0", type: "heading", props: { level: 1 }, content: "New heading" }, + ]); + + await waitForSuggestion(editor); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "add-remove-add-heading-to-empty", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + + + " + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + New heading + + " + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + + + + + + + + + New heading + + + + + + " + `); +}); + +// Add a paragraph after an existing heading. +test("suggestion mode: add paragraph after existing block", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "append paragraph" }); + + editor.replaceBlocks(editor.document, [ + { id: "h0", type: "heading", props: { level: 1 }, content: "Title" }, + ]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("Title")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + editor.insertBlocks( + [{ id: "p0", type: "paragraph", content: "Body text" }], + "h0", + "after", + ); + + await waitForSuggestion(editor); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "add-remove-add-paragraph", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + + + + + + + + + + New heading + + + + + + " + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + Title + + + Body text + + " + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + Title + + + + + + Body text + + + + + + " + `); +}); + +// TODO: block-level deletions DO carry a node-level +// `` mark in the PM doc (visible in the snapshots +// below), so the data is there. But that mark only has an inline +// `toDOM` (renders text-content deletions as `` with strikethrough +// – see SuggestionMarks.ts) and no styling at the block level, so the +// deleted block still *visually* renders identically to an accepted +// block. Decide whether block-level `` should +// also have a visible affordance (a left bar, fade-out, …) so +// reviewers can tell from the editor that a block is pending removal. +// +// Heading + paragraph -> remove the paragraph. +test("suggestion mode: remove paragraph from heading+paragraph", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "remove body" }); + + editor.replaceBlocks(editor.document, [ + { id: "h0", type: "heading", props: { level: 1 }, content: "Title" }, + { id: "p0", type: "paragraph", content: "Body text" }, + ]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("Body text")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + editor.removeBlocks(["p0"]); + + await waitForSuggestion(editor); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "add-remove-remove-paragraph", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + Title + + + Body text + + " + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + Title + + " + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + Title + + + + Body text + + + + " + `); +}); + +// Remove every block from a doc that has one paragraph. +test("suggestion mode: remove all blocks", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "delete all" }); + + editor.replaceBlocks(editor.document, [ + { id: "p0", type: "paragraph", content: "Only block" }, + ]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("Only block")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + editor.removeBlocks(["p0"]); + + await waitForSuggestion(editor); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "add-remove-remove-all", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + Only block + + " + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + + + " + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + + Only block + + + + " + `); +}); + +// Delete a nested child block, parent stays. +test("suggestion mode: delete nested block", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "delete inner block" }); + + editor.replaceBlocks(editor.document, [ + { + id: "parent", + type: "paragraph", + content: "Parent", + children: [{ id: "child", type: "paragraph", content: "Child" }], + }, + ]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("Child")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + editor.removeBlocks(["child"]); + + await waitForSuggestion(editor); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "add-remove-delete-nested", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + Parent + + + Child + + + + " + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + Parent + + " + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + Parent + + + + Child + + + + + + " + `); +}); + +// Delete a parent block that has children. Documents what happens to +// the children – BlockNote may keep them as top-level siblings or +// delete them too. +test("suggestion mode: delete parent block (with children)", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "delete outer block" }); + + editor.replaceBlocks(editor.document, [ + { + id: "parent", + type: "paragraph", + content: "Parent", + children: [{ id: "child", type: "paragraph", content: "Child" }], + }, + ]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("Parent")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + editor.removeBlocks(["parent"]); + + await waitForSuggestion(editor); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "add-remove-delete-parent", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + Parent + + + Child + + + + " + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + + + " + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + + Parent + + + + + Child + + + + + + " + `); +}); + +// Delete the sole image block in suggestion mode. An image is an atom +// blockContent with no inline text and no blockGroup child, so the only +// schema-valid way to attribute its deletion is to wrap the whole +// blockContainer at the blockGroup level. The @y/y attribution diff +// instead aligns the lone base/suggestion blockContainers and diffs their +// children, emitting an in-place content replace that produces a +// blockContainer with two blockContent children (the delete-marked image +// plus the new paragraph). That violates the `blockContent blockGroup?` +// content expression, so deltaToPSteps throws +// `RangeError: Invalid content for node blockContainer`. Marked +// `test.fails` until @y/y can represent deleting a sole atom block. +test.fails("suggestion mode: delete image block", async () => { + const { editor, sync } = await setupSuggestionTest({ + userAction: "delete image", + }); + + editor.replaceBlocks(editor.document, [ + { + id: "img", + type: "image", + props: { url: IMG_SRC, previewWidth: 150 }, + }, + ]); + sync(); + await expect + .poll(() => (editor.document[0]?.props as { url?: string })?.url) + .toBe(IMG_SRC); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + // Throws synchronously inside the suggestion sync (see comment above). + editor.removeBlocks(["img"]); + + await waitForSuggestion(editor); +}); diff --git a/tests/src/end-to-end/y-prosemirror/basicText.concurrent.test.tsx b/tests/src/end-to-end/y-prosemirror/basicText.concurrent.test.tsx new file mode 100644 index 0000000000..d316db6462 --- /dev/null +++ b/tests/src/end-to-end/y-prosemirror/basicText.concurrent.test.tsx @@ -0,0 +1,264 @@ +/* eslint-disable testing-library/render-result-naming-convention */ +/** + * Vitest browser-mode tests for two-user concurrent suggestion edits. + * Each test sets up three side-by-side editors (User A, User B, + * Merged) backed by `baseDoc` + `suggestionDocA`/`B`/`Merged`, applies + * independent suggestion edits from A and B, calls `sync()` to fan + * both updates into the merged doc, and snapshots the converged state. + * + * TODO: BlockNote's `mapAttributionToMark` (YSync.ts) hashes user IDs + * from the attribution data to pick a color from a fixed palette, but + * `Y.Attributions()` ships empty and nothing in the editor pipeline + * populates it from the editor's `user` / awareness. Result: every + * mark in every test renders as `userColorPalette[0]` (#30bced), + * regardless of which user actually made the edit. In the merged + * snapshots below we therefore cannot tell A's marks from B's. Decide + * whether the attribution layer should automatically tag writes with + * the local awareness user, or whether tests should construct an + * `Attributions` instance with pre-registered client-id → user-id + * mappings. + */ +import { expect, test } from "vite-plus/test"; +import { expectScreenshot, expectVisible } from "./fixtures/browserExpect.js"; + +import { setupConcurrentSuggestionTest } from "./fixtures/concurrentSuggestionFixture.js"; +import { + editorHtml, + waitForSuggestion, + ydocXml, +} from "./fixtures/suggestionFixture.js"; + +// Concurrent text edits on overlapping range: A fixes a typo while B +// deletes the whole word. After CRDT merge, snapshot what the merged +// editor ends up displaying. +test("concurrent: A fixes typo, B deletes the word", async () => { + const { + userA, + userB, + merged, + baseDoc, + suggestionDocA, + suggestionDocB, + suggestionDocMerged, + screen, + seed, + enableSuggestions, + sync, + } = await setupConcurrentSuggestionTest({ + userAAction: "fix typo", + userBAction: "delete word", + }); + + // Seed: A writes "hello wrold" (typo) directly to baseDoc since + // suggestion mode isn't on yet. Then `seed()` fans baseDoc into + // all three suggestion docs so everyone starts from the same state. + userA.editor.replaceBlocks(userA.editor.document, [ + { id: "block-hello", type: "paragraph", content: "hello wrold" }, + ]); + seed(); + + await expectVisible( + screen.getByTestId(userA.testId).getByText("hello wrold"), + ); + + // Switch all editors into suggestion mode (subsequent edits in A + // and B are recorded as suggestions, merged starts watching its + // suggestion doc for incoming updates). + enableSuggestions(); + + // A: fix typo "wrold" -> "world". + const [blockA] = userA.editor.document; + userA.editor.updateBlock(blockA, { + type: "paragraph", + content: "hello world", + }); + + // B: delete the misspelled word entirely. + const [blockB] = userB.editor.document; + userB.editor.updateBlock(blockB, { type: "paragraph", content: "hello " }); + + await waitForSuggestion(userA.editor); + await waitForSuggestion(userB.editor); + + // Merge A's and B's suggestions into the merged doc. + sync(); + await waitForSuggestion(merged.editor); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "concurrent-typo-fix-vs-delete", + ); + + // TODO: the merged YDoc ends up at "hello o" – an `o` survives even + // though both A (who replaced "wrold" with "world") and B (who + // deleted "wrold" outright) effectively wanted "wrold" gone. The + // CRDT keeps A's inserted `o` because B's delete-range covered the + // original "wrold" letters but not A's freshly-inserted characters, + // so the union of "delete everything B saw" + "keep what A added" + // leaves a stray `o`. Worth deciding whether this is the desired + // merge semantic for the product or whether the suggestion layer + // should resolve overlapping edits differently. + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + hello wrold + + " + `); + expect(ydocXml(suggestionDocA)).toMatchInlineSnapshot(` + " + + hello world + + " + `); + expect(ydocXml(suggestionDocB)).toMatchInlineSnapshot(` + " + + hello + + " + `); + expect(ydocXml(suggestionDocMerged)).toMatchInlineSnapshot(` + " + + hello o + + " + `); + expect(editorHtml(merged.editor)).toMatchInlineSnapshot(` + " + + + + hello + w + o + rold + + + + " + `); +}); + +// Concurrent format edits on the same word: A adds bold, B adds +// italic. After CRDT merge, both marks should land on "world". +test("concurrent: A bolds the word, B italicises the word", async () => { + const { + userA, + userB, + merged, + baseDoc, + suggestionDocA, + suggestionDocB, + suggestionDocMerged, + screen, + seed, + enableSuggestions, + sync, + } = await setupConcurrentSuggestionTest({ + userAAction: "bold 'world'", + userBAction: "italicise 'world'", + }); + + // Seed: A writes plain "hello world" directly to baseDoc, then + // `seed()` fans it into all three suggestion docs. + userA.editor.replaceBlocks(userA.editor.document, [ + { id: "block-hello", type: "paragraph", content: "hello world" }, + ]); + seed(); + + await expectVisible( + screen.getByTestId(userA.testId).getByText("hello world"), + ); + + enableSuggestions(); + + // A: bold "world". + const [blockA] = userA.editor.document; + userA.editor.updateBlock(blockA, { + type: "paragraph", + content: [ + { type: "text", text: "hello ", styles: {} }, + { type: "text", text: "world", styles: { bold: true } }, + ], + }); + + // B: italic "world". + const [blockB] = userB.editor.document; + userB.editor.updateBlock(blockB, { + type: "paragraph", + content: [ + { type: "text", text: "hello ", styles: {} }, + { type: "text", text: "world", styles: { italic: true } }, + ], + }); + + await waitForSuggestion(userA.editor); + await waitForSuggestion(userB.editor); + + sync(); + await waitForSuggestion(merged.editor); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "concurrent-bold-vs-italic", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + hello world + + " + `); + expect(ydocXml(suggestionDocA)).toMatchInlineSnapshot(` + " + + + hello + world + + + " + `); + expect(ydocXml(suggestionDocB)).toMatchInlineSnapshot(` + " + + + hello + world + + + " + `); + expect(ydocXml(suggestionDocMerged)).toMatchInlineSnapshot(` + " + + + hello + + world + + + + " + `); + expect(editorHtml(merged.editor)).toMatchInlineSnapshot(` + " + + + + hello + + + world + + + + + + " + `); +}); diff --git a/tests/src/end-to-end/y-prosemirror/basicText.test.tsx b/tests/src/end-to-end/y-prosemirror/basicText.test.tsx new file mode 100644 index 0000000000..b40a5b27e8 --- /dev/null +++ b/tests/src/end-to-end/y-prosemirror/basicText.test.tsx @@ -0,0 +1,327 @@ +/* eslint-disable testing-library/render-result-naming-convention */ +/** + * Vitest browser-mode tests for suggestion-mode editing. Each test + * sets up a fresh editor + base/suggestion Y.Doc pair via + * `setupSuggestionTest()`, applies an edit in suggestion mode, and + * captures a screenshot plus inline XML snapshots of both Y.Docs and + * the ProseMirror document. The PM doc is where the suggestion marks + * live – the Y.Docs only carry the content of the different branches. + */ +import { SuggestionsExtension } from "@blocknote/core/y"; +import { expect, test } from "vite-plus/test"; +import { expectScreenshot, expectVisible } from "./fixtures/browserExpect.js"; + +import { + editorHtml, + setupSuggestionTest, + waitForSuggestion, + ydocXml, +} from "./fixtures/suggestionFixture.js"; + +// Pure text edit: replace one word with another and confirm the diff +// is rendered as inline / spans around the changed letters. +test("suggestion mode: 'hello world' -> 'hello universe'", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "rename last word" }); + + // 1. Set the base doc to "hello world". The block id is pinned so the + // snapshots stay deterministic. + editor.replaceBlocks(editor.document, [ + { id: "block-hello", type: "paragraph", content: "hello world" }, + ]); + + // 2. Replay base updates into the suggestion doc so both docs start + // from the same state. + sync(); + + await expectVisible(screen.getByTestId("editor-A").getByText("hello world")); + + // 3. Subsequent edits are recorded as suggestions instead of mutating + // the doc directly. + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + // 4. Replace "world" with "universe" via updateBlock. + const [block] = editor.document; + editor.updateBlock(block, { type: "paragraph", content: "hello universe" }); + + // Wait for the suggestion edit to land in the DOM (React commits the + // re-render on the next frame; without this the screenshot can race + // the update). "unive" only exists once "world" -> "universe" has + // been split into / spans, so this is a precise sentinel. + await expectVisible(screen.getByTestId("editor-A").getByText("unive")); + + // 5a. Visual snapshot of the rendered editor. + await expectScreenshot( + screen.getByTestId("editor-root"), + "suggestion-mode-universe", + ); + + // 5b. Y.Doc XML – just the merged textual state; suggestion marks + // don't live here. + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + hello world + + " + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + hello universe + + " + `); + + // 5c. ProseMirror XML – this is where the suggestion marks + // (`y-attributed-insert` / `y-attributed-delete`) live. + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + + hello + wo + unive + r + ld + se + + + + " + `); +}); + +// Format-only addition: text content stays the same but a style mark +// (bold) is added on top. Surfaces how suggestions track pure format +// changes via the `y-attributed-format` mark. All three suggestion +// marks (`y-attributed-insert` / `-delete` / `-format`) have a `toDOM` +// in SuggestionMarks.ts; the format mark renders a +// `` which the editor CSS highlights, so +// the screenshot shows bold "world" with the blue suggestion marker. +test("suggestion mode: add bold to 'world'", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "bold 'world'" }); + + // Base: plain "hello world". + editor.replaceBlocks(editor.document, [ + { id: "block-hello", type: "paragraph", content: "hello world" }, + ]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("hello world")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + // Suggestion edit: bold the word "world" (content text is unchanged, + // only the style differs). + const [block] = editor.document; + editor.updateBlock(block, { + type: "paragraph", + content: [ + { type: "text", text: "hello ", styles: {} }, + { type: "text", text: "world", styles: { bold: true } }, + ], + }); + + await waitForSuggestion(editor); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "suggestion-mode-add-bold", + ); + + // The base ("hello world") and suggestion ("hello world") + // YDoc snapshots differ here because `ydocXml` walks the deep delta + // (`toDeltaDeep`), which surfaces per-run formatting marks that + // `Y.XmlFragment.toString()` would otherwise drop. + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + hello world + + " + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + + hello + world + + + " + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + + hello + + world + + + + + " + `); +}); + +// Format-only removal: bold mark is stripped from an already-styled +// word, text content unchanged. Mirror of the add-bold case to check +// removal is handled symmetrically. +test("suggestion mode: remove bold from 'world'", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "unbold 'world'" }); + + // Base: "hello " + bold "world". + editor.replaceBlocks(editor.document, [ + { + id: "block-hello", + type: "paragraph", + content: [ + { type: "text", text: "hello ", styles: {} }, + { type: "text", text: "world", styles: { bold: true } }, + ], + }, + ]); + sync(); + // Use the full paragraph text – the User A column heading also + // contains the word "world", which would clash with getByText. + await expectVisible(screen.getByTestId("editor-A").getByText("hello world")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + // Suggestion edit: strip bold from "world". + const [block] = editor.document; + editor.updateBlock(block, { + type: "paragraph", + content: "hello world", + }); + + await waitForSuggestion(editor); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "suggestion-mode-remove-bold", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + + hello + world + + + " + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + hello world + + " + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + + hello + world + + + + " + `); +}); + +// TODO: the snapshot below reveals that `y-attributed-format` wraps +// *all* marks on the affected range, not just the newly added one. +// The PM XML shows +// world +// so from the attribution data alone we can't tell which mark is new +// (italic) and which is pre-existing (bold). If accept/reject logic +// needs to revert only the new mark, this granularity is insufficient. +// +// Format added on top of an existing format: bold "world" gets italic +// layered on (bold is preserved). Checks that suggestion attribution +// is recorded only for the new mark, not the pre-existing one. +test("suggestion mode: add italic to already-bold 'world'", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "italic on top of bold" }); + + // Base: "hello " + bold "world". + editor.replaceBlocks(editor.document, [ + { + id: "block-hello", + type: "paragraph", + content: [ + { type: "text", text: "hello ", styles: {} }, + { type: "text", text: "world", styles: { bold: true } }, + ], + }, + ]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("hello world")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + // Suggestion edit: add italic to "world" while keeping it bold. + const [block] = editor.document; + editor.updateBlock(block, { + type: "paragraph", + content: [ + { type: "text", text: "hello ", styles: {} }, + { type: "text", text: "world", styles: { bold: true, italic: true } }, + ], + }); + + await waitForSuggestion(editor); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "suggestion-mode-add-italic-to-bold", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + + hello + world + + + " + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + + hello + + world + + + + " + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + + hello + + + world + + + + + + " + `); +}); diff --git a/tests/src/end-to-end/y-prosemirror/fixtures/browserExpect.ts b/tests/src/end-to-end/y-prosemirror/fixtures/browserExpect.ts new file mode 100644 index 0000000000..cee20bf522 --- /dev/null +++ b/tests/src/end-to-end/y-prosemirror/fixtures/browserExpect.ts @@ -0,0 +1,40 @@ +import { expect } from "vite-plus/test"; + +/** + * Browser-mode `expect` helpers for the y-prosemirror suggestion suite. + * + * The vite-plus `expect` exposes the browser matchers (`.element(locator)` with + * its auto-retry visibility wait, and `.toMatchScreenshot`) at runtime, but its + * published TypeScript types don't surface them (same reason `utils/editor.ts` + * casts `expect` for its `expectElement` helper). These thin wrappers centralise + * the cast so the test bodies stay clean and fully typed. + */ + +/** Any object that can be screenshot-tested (vitest-browser locator, etc). */ +type LocatorLike = unknown; + +interface ElementAssertion { + toBeVisible(): Promise; +} + +interface BrowserExpect { + element(locator: unknown): ElementAssertion; +} + +const browserExpect = expect as unknown as BrowserExpect; + +/** + * Assert a locator resolves to a visible element, retrying until it does. Use as + * the wait between an async editor edit and a snapshot/screenshot. + */ +export function expectVisible(locator: unknown): Promise { + return browserExpect.element(locator).toBeVisible(); +} + +/** Capture a visual regression screenshot of the element a locator resolves to. */ +export function expectScreenshot( + locator: LocatorLike, + name?: string, +): Promise { + return (expect(locator) as any).toMatchScreenshot(name); +} diff --git a/tests/src/end-to-end/y-prosemirror/fixtures/concurrentSuggestionFixture.tsx b/tests/src/end-to-end/y-prosemirror/fixtures/concurrentSuggestionFixture.tsx new file mode 100644 index 0000000000..c34dee74d4 --- /dev/null +++ b/tests/src/end-to-end/y-prosemirror/fixtures/concurrentSuggestionFixture.tsx @@ -0,0 +1,252 @@ +/* eslint-disable testing-library/render-result-naming-convention */ +/** + * Fixture for two-user concurrent suggestion tests. + * + * Layout: + * ┌──────┬─────────────────────┬─────────────────────┬────────┐ + * │ Base │ User A: │ User B: void; + /** + * Switch all three editors into suggestion mode. Call after `seed()` + * – subsequent edits in A and B are recorded as suggestions, and the + * merged editor starts observing `suggestionDocMerged` for updates. + */ + enableSuggestions: () => void; + /** Fan A's and B's suggestion updates into `suggestionDocMerged`. */ + sync: () => void; +} + +const USER_A = { name: "User A", color: "#30bced" }; +const USER_B = { name: "User B", color: "#ee6352" }; +const USER_MERGED = { name: "Merged", color: "#888888" }; +const USER_BASE = { name: "Base", color: "#888888" }; + +export interface ConcurrentSuggestionFixtureOptions { + /** 1-5 word description of what User A does (rendered as column heading). */ + userAAction: string; + /** 1-5 word description of what User B does (rendered as column heading). */ + userBAction: string; +} + +export async function setupConcurrentSuggestionTest({ + userAAction, + userBAction, +}: ConcurrentSuggestionFixtureOptions): Promise { + const baseDoc = new Y.Doc(); + const suggestionDocA = new Y.Doc({ isSuggestionDoc: true }); + const suggestionDocB = new Y.Doc({ isSuggestionDoc: true }); + const suggestionDocMerged = new Y.Doc({ isSuggestionDoc: true }); + + // `Y.Doc.clientID` is randomly generated and CRDT tiebreaks on it, + // so concurrent edits that touch the same logical position can + // converge to different shapes between runs. We deliberately do + // NOT pin clientIDs here – any test whose merge result depends on + // tiebreaking is therefore flaky on purpose, so the underlying + // non-determinism stays visible. Skip or `.fails`-mark those tests + // explicitly rather than papering over them. + + const managerA = Y.createAttributionManagerFromDiff(baseDoc, suggestionDocA, { + attrs: new Y.Attributions(), + }); + managerA.suggestionMode = true; + + const managerB = Y.createAttributionManagerFromDiff(baseDoc, suggestionDocB, { + attrs: new Y.Attributions(), + }); + managerB.suggestionMode = true; + + // Merged is a viewer – it shows both users' suggestions but doesn't + // record new ones, so `suggestionMode = false`. + const managerMerged = Y.createAttributionManagerFromDiff( + baseDoc, + suggestionDocMerged, + { attrs: new Y.Attributions() }, + ); + managerMerged.suggestionMode = false; + + const awarenessA = makeAwareness(baseDoc, USER_A); + const awarenessB = makeAwareness(baseDoc, USER_B); + const awarenessMerged = makeAwareness(baseDoc, USER_MERGED); + + let editorBase!: BlockNoteEditor; + let editorA!: BlockNoteEditor; + let editorB!: BlockNoteEditor; + let editorMerged!: BlockNoteEditor; + + function Editors() { + editorBase = useCreateBlockNote( + withCollaboration({ + collaboration: { + fragment: baseDoc.get("doc"), + provider: { awareness: new Awareness(baseDoc) }, + user: USER_BASE, + }, + }), + ); + editorA = useCreateBlockNote( + withCollaboration({ + collaboration: { + fragment: baseDoc.get("doc"), + provider: { awareness: awarenessA }, + suggestionDoc: suggestionDocA, + attributionManager: managerA, + user: USER_A, + }, + }), + ); + editorB = useCreateBlockNote( + withCollaboration({ + collaboration: { + fragment: baseDoc.get("doc"), + provider: { awareness: awarenessB }, + suggestionDoc: suggestionDocB, + attributionManager: managerB, + user: USER_B, + }, + }), + ); + editorMerged = useCreateBlockNote( + withCollaboration({ + collaboration: { + fragment: baseDoc.get("doc"), + provider: { awareness: awarenessMerged }, + suggestionDoc: suggestionDocMerged, + attributionManager: managerMerged, + user: USER_MERGED, + }, + }), + ); + + return ( +
+
+ Base + +
+
+ User A: {userAAction} + +
+
+ User B: {userBAction} + +
+
+ Merged + +
+
+ ); + } + + // Four columns at 1fr each need a wider viewport so the rightmost + // column doesn't clip BlockNote content. + await page.viewport(1800, 800); + + await render(); + + return { + userA: { editor: editorA, testId: "editor-A" }, + userB: { editor: editorB, testId: "editor-B" }, + merged: { editor: editorMerged, testId: "editor-merged" }, + baseDoc, + suggestionDocA, + suggestionDocB, + suggestionDocMerged, + screen: page, + seed: () => { + const update = Y.encodeStateAsUpdate(baseDoc); + Y.applyUpdate(suggestionDocA, update); + Y.applyUpdate(suggestionDocB, update); + Y.applyUpdate(suggestionDocMerged, update); + }, + enableSuggestions: () => { + editorA.getExtension(SuggestionsExtension)!.enableSuggestions(); + editorB.getExtension(SuggestionsExtension)!.enableSuggestions(); + editorMerged.getExtension(SuggestionsExtension)!.enableSuggestions(); + }, + sync: () => { + Y.applyUpdate(suggestionDocMerged, Y.encodeStateAsUpdate(suggestionDocA)); + Y.applyUpdate(suggestionDocMerged, Y.encodeStateAsUpdate(suggestionDocB)); + }, + }; +} + +function makeAwareness( + doc: Y.Doc, + user: { name: string; color: string }, +): Awareness { + const a = new Awareness(doc); + a.setLocalStateField("user", user); + return a; +} diff --git a/tests/src/end-to-end/y-prosemirror/fixtures/suggestionFixture.tsx b/tests/src/end-to-end/y-prosemirror/fixtures/suggestionFixture.tsx new file mode 100644 index 0000000000..3c52d1c26f --- /dev/null +++ b/tests/src/end-to-end/y-prosemirror/fixtures/suggestionFixture.tsx @@ -0,0 +1,322 @@ +/* eslint-disable testing-library/render-result-naming-convention */ +/** + * Shared fixture for browser-mode suggestion tests. + * + * Layout: + * ┌──────────┬──────────────────────┐ + * │ Base │ User A: │ + * └──────────┴──────────────────────┘ + * + * - `Base` is a read-only editor bound to `baseDoc` – it shows the + * pre-suggestion state and is visible in the screenshot so the + * reviewer can see the "before" without leaving the file. + * - `User A` is the suggesting editor. Its column heading includes a + * short caller-supplied action description so the screenshot is + * self-explanatory. + * + * The provider/yhub round-trip is replaced by a manual `sync()`. + */ +import "@blocknote/core/fonts/inter.css"; +import "@blocknote/mantine/style.css"; +import "@blocknote/core/style.css"; + +import { BlockNoteEditor } from "@blocknote/core"; +import { withCollaboration } from "@blocknote/core/y"; +import { BlockNoteView } from "@blocknote/mantine"; +import { useCreateBlockNote } from "@blocknote/react"; +import { Node as PMNode } from "@tiptap/pm/model"; +import { Awareness } from "@y/protocols/awareness"; +import * as Y from "@y/y"; +import { prettify } from "htmlfy"; +import { expect } from "vite-plus/test"; +import { render } from "vitest-browser-react"; +import { page } from "../../../utils/context.js"; + +export interface SuggestionFixture { + /** User A's editor – this is the one the test makes suggestions through. */ + editor: BlockNoteEditor; + /** + * The `page` locator object (vite-plus browser context). Exposes + * `getByTestId` / `getByText` for querying the rendered editors. Named + * `screen` for parity with the testing-library convention the tests use. + */ + screen: typeof page; + baseDoc: Y.Doc; + suggestionDoc: Y.Doc; + /** Replay updates from `baseDoc` into `suggestionDoc`. */ + sync: () => void; +} + +export interface SuggestionFixtureOptions { + /** + * 1-5 word description of what User A does (e.g. "fix typo", + * "bold world"). Rendered in the User A column heading so the + * screenshot is self-explanatory. + */ + userAction: string; +} + +export async function setupSuggestionTest({ + userAction, +}: SuggestionFixtureOptions): Promise { + const baseDoc = new Y.Doc(); + const baseAwareness = new Awareness(baseDoc); + baseAwareness.setLocalStateField("user", { + name: "User A", + color: "#30bced", + }); + + const suggestionDoc = new Y.Doc({ isSuggestionDoc: true }); + const attributionManager = Y.createAttributionManagerFromDiff( + baseDoc, + suggestionDoc, + { attrs: new Y.Attributions() }, + ); + attributionManager.suggestionMode = true; + + let editorA!: BlockNoteEditor; + let editorBase!: BlockNoteEditor; + + function Editors() { + editorA = useCreateBlockNote( + withCollaboration({ + collaboration: { + fragment: baseDoc.get("doc"), + provider: { awareness: baseAwareness }, + suggestionDoc, + attributionManager, + user: { name: "User A", color: "#30bced" }, + }, + }), + ); + editorBase = useCreateBlockNote( + withCollaboration({ + collaboration: { + fragment: baseDoc.get("doc"), + provider: { awareness: new Awareness(baseDoc) }, + user: { name: "Base", color: "#888888" }, + }, + }), + ); + return ( +
+
+ Base + +
+
+ User A: {userAction} + +
+
+ ); + } + + await page.viewport(1200, 800); + + await render(); + + return { + editor: editorA, + screen: page, + baseDoc, + suggestionDoc, + sync: () => Y.applyUpdate(suggestionDoc, Y.encodeStateAsUpdate(baseDoc)), + }; +} + +/** + * Wait until any suggestion mark (`y-attributed-insert` / + * `y-attributed-delete`) is present in the editor's PM doc. Use this + * after a suggestion-mode edit before snapshotting/screenshotting – + * the PM transaction is sync but the React/DOM commit is not. + * + * For tests whose edit changes visible text, prefer waiting on the + * inserted text via `expect.element(getByText(...))` – it's more + * meaningful. + */ +export async function waitForSuggestion( + editor: BlockNoteEditor, +): Promise { + await expect + .poll(() => editor.prosemirrorState.doc.toString().includes("y-attributed")) + .toBe(true); +} + +/** + * Pretty-print a Y.Doc's `doc` XmlFragment for an inline snapshot. + * + * `Y.XmlFragment.toString()` (and `toJSON()`, which collapses text + * runs into a bare string) only serialise the element/text structure – + * inline formatting marks and attribution metadata don't surface, so + * "hello world" and "hello **world**" produce identical snapshots. + * + * Instead we walk the *deep delta* (`toDeltaDeep`), which carries both + * the per-run `format` (marks like `bold`/`italic`) and `attribution` + * (suggestion metadata) on every insert op. Those marks are rendered as + * nested tags (`world`) and attribution as an + * `attribution="..."` attribute so the snapshots actually differ. + */ +export function ydocXml(doc: Y.Doc): string { + const delta = (doc.get("doc") as any).toDeltaDeep().toJSON(); + return prettify(deltaToXml(delta), { tag_wrap: true }); +} + +/** + * A single op from a deep-delta JSON tree. For a final document render + * only `insert` ops appear (retain/delete are diff artefacts); the + * insert payload is either a text run (`string`) or an array of nested + * element deltas. `format` holds inline marks, `attribution` holds + * suggestion metadata. + */ +interface DeltaJson { + type?: string; + name?: string; + attrs?: Record; + children?: DeltaInsertOp[]; +} + +interface DeltaInsertOp { + type?: string; + insert?: string | DeltaJson[]; + format?: Record; + attribution?: Record; +} + +/** Render a deep-delta JSON node (a `{ type: 'delta', ... }` object). */ +function deltaToXml(node: DeltaJson): string { + let inner = ""; + for (const op of node.children ?? []) { + inner += opToXml(op); + } + + if (node.name == null) { + // The root XmlFragment has no tag of its own – emit its children. + return inner; + } + return `<${node.name}${deltaAttrsToString(node.attrs)}>${inner}`; +} + +/** Render one insert op, applying its `format` marks and `attribution`. */ +function opToXml(op: DeltaInsertOp): string { + let out: string; + if (typeof op.insert === "string") { + out = escapeXml(op.insert); + } else if (Array.isArray(op.insert)) { + out = op.insert.map(deltaToXml).join(""); + } else { + out = ""; + } + + // Wrap with inline marks (bold/italic/…). A "trivial" value (`true` + // or an empty `{}`) renders as a bare tag (``); richer values + // surface as a `value="…"` attribute. Object values (e.g. suggestion + // format metadata) are JSON-encoded since `String(obj)` throws + // "Cannot convert object to primitive value". + // + // Marks are sorted by name so nesting order is deterministic: YJS + // delta `format` key order isn't stable (especially after a + // concurrent merge of two marks), which would otherwise make these + // snapshots flaky. Sorted ascending => the alphabetically-first mark + // ends up innermost (e.g. `world`). + for (const [name, value] of Object.entries(op.format ?? {}).sort(([a], [b]) => + a < b ? -1 : a > b ? 1 : 0, + )) { + const isObject = value !== null && typeof value === "object"; + const isTrivial = + value === true || (isObject && Object.keys(value).length === 0); + if (isTrivial) { + out = `<${name}>${out}`; + } else { + const rendered = isObject ? JSON.stringify(value) : String(value); + out = `<${name} value="${escapeXml(rendered)}">${out}`; + } + } + + // Surface suggestion attribution as a wrapping element so it's visible + // in the snapshot (and distinct from a plain formatting mark). + if (op.attribution != null && Object.keys(op.attribution).length > 0) { + out = `${out}`; + } + + return out; +} + +/** Format a delta node's `attrs` map (e.g. block-level paragraph props). */ +function deltaAttrsToString(attrs: DeltaJson["attrs"] | undefined): string { + if (attrs == null) { + return ""; + } + return Object.entries(attrs) + .map(([key, raw]) => { + // attrs are `SetAttrOp` JSON: `{ type: 'insert', value }`. + const value = + raw != null && typeof raw === "object" && "value" in raw + ? (raw as { value: unknown }).value + : raw; + const rendered = + value !== null && typeof value === "object" + ? JSON.stringify(value) + : String(value); + return ` ${key}="${escapeXml(rendered)}"`; + }) + .sort() + .join(""); +} + +/** + * Pretty-print the editor's ProseMirror doc for an inline snapshot. + * + * We walk the node tree directly rather than going through + * `DOMSerializer` (BlockNote's `renderHTML` adds CSS scaffolding that + * we don't want in snapshots) or `Node.toString()` (drops attrs, so + * block ids and suggestion-mark colors would disappear). + */ +export function editorHtml(editor: BlockNoteEditor): string { + return prettify(pmNodeToXml(editor.prosemirrorState.doc), { + tag_wrap: true, + }); +} + +function pmNodeToXml(node: PMNode): string { + let out: string; + if (node.isText) { + out = escapeXml(node.text ?? ""); + } else { + let inner = ""; + node.content.forEach((child) => { + inner += pmNodeToXml(child); + }); + out = `<${node.type.name}${formatAttrs(node.attrs)}>${inner}`; + } + // PM stores marks outermost-first; wrap innermost-first to preserve order. + // Non-text nodes can also carry marks (used by y-prosemirror for + // block-level attributions), so this applies to both branches. + for (const mark of node.marks) { + out = `<${mark.type.name}${formatAttrs(mark.attrs)}>${out}`; + } + return out; +} + +function formatAttrs(attrs: Record): string { + return Object.entries(attrs) + .filter(([, v]) => v !== null && v !== undefined) + .map(([k, v]) => ` ${k}="${escapeXml(String(v))}"`) + .join(""); +} + +function escapeXml(text: string): string { + return text + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """); +} diff --git a/tests/src/end-to-end/y-prosemirror/moveBlocks.test.tsx b/tests/src/end-to-end/y-prosemirror/moveBlocks.test.tsx new file mode 100644 index 0000000000..ff76a49f8d --- /dev/null +++ b/tests/src/end-to-end/y-prosemirror/moveBlocks.test.tsx @@ -0,0 +1,197 @@ +/* eslint-disable testing-library/render-result-naming-convention */ +/** + * Vitest browser-mode tests for move-block suggestions: relocating a + * whole block (with or without children) using `moveBlocksUp` / + * `moveBlocksDown`. Same shape as the other categories. + */ +import { SuggestionsExtension } from "@blocknote/core/y"; +import { expect, test } from "vite-plus/test"; +import { expectScreenshot, expectVisible } from "./fixtures/browserExpect.js"; + +import { + editorHtml, + setupSuggestionTest, + waitForSuggestion, + ydocXml, +} from "./fixtures/suggestionFixture.js"; + +// Move a plain paragraph one slot up. Base has three siblings; we +// move the middle one to the top. +test("suggestion mode: move paragraph up", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "move middle up" }); + + editor.replaceBlocks(editor.document, [ + { id: "first", type: "paragraph", content: "First" }, + { id: "middle", type: "paragraph", content: "Middle" }, + { id: "last", type: "paragraph", content: "Last" }, + ]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("First")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + editor.moveBlocksUp("middle"); + + await waitForSuggestion(editor); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "move-paragraph-up", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + First + + + Middle + + + Last + + " + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + Middle + + + First + + + Last + + " + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + + + + Middle + + + + + + First + + + + Middle + + + + Last + + + " + `); +}); + +// Move a paragraph that has a nested child. The whole subtree should +// travel together. +test("suggestion mode: move paragraph with children", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "move parent + child up" }); + + editor.replaceBlocks(editor.document, [ + { id: "first", type: "paragraph", content: "First" }, + { + id: "parent", + type: "paragraph", + content: "Parent", + children: [{ id: "child", type: "paragraph", content: "Child" }], + }, + ]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("First")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + editor.moveBlocksUp("parent"); + + await waitForSuggestion(editor); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "move-paragraph-with-children", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + First + + + Parent + + + Child + + + + " + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + Parent + + + Child + + + + + First + + " + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + + + + Parent + + + + + + + + + Child + + + + + + + + + + First + + + + Parent + + + Child + + + + + + " + `); +}); diff --git a/tests/src/end-to-end/y-prosemirror/nesting.concurrent.test.tsx b/tests/src/end-to-end/y-prosemirror/nesting.concurrent.test.tsx new file mode 100644 index 0000000000..1a4cf7df05 --- /dev/null +++ b/tests/src/end-to-end/y-prosemirror/nesting.concurrent.test.tsx @@ -0,0 +1,310 @@ +/* eslint-disable testing-library/render-result-naming-convention */ +/** + * Vitest browser-mode tests for two-user concurrent nesting + * suggestions. Same shape as `propChanges.concurrent.test.tsx`. + */ +import { expect, test } from "vite-plus/test"; +import { expectScreenshot, expectVisible } from "./fixtures/browserExpect.js"; + +import { setupConcurrentSuggestionTest } from "./fixtures/concurrentSuggestionFixture.js"; +import { + editorHtml, + waitForSuggestion, + ydocXml, +} from "./fixtures/suggestionFixture.js"; + +// Two cascading indents from a flat list of three siblings: +// A nests N1 under N0; +// B nests N2 under N1. +// The merge converges with A's nesting winning (N1 under N0) and +// B's nesting of N2 dropped, captured in the snapshots below. +test("concurrent: A indents N1, B indents N2 below N1", async () => { + const { + userA, + userB, + merged, + baseDoc, + suggestionDocA, + suggestionDocB, + suggestionDocMerged, + screen, + seed, + enableSuggestions, + sync, + } = await setupConcurrentSuggestionTest({ + // Keep node names out of the action labels – `getByText` below + // would otherwise match the column heading and trigger a + // strict-mode locator violation. + userAAction: "indent middle block", + userBAction: "indent last block", + }); + + // Base: three siblings. + userA.editor.replaceBlocks(userA.editor.document, [ + { id: "n0", type: "paragraph", content: "N0" }, + { id: "n1", type: "paragraph", content: "N1" }, + { id: "n2", type: "paragraph", content: "N2" }, + ]); + seed(); + await expectVisible(screen.getByTestId(userA.testId).getByText("N0")); + + enableSuggestions(); + + // A: nest N1 under N0. + userA.editor.setTextCursorPosition("n1", "start"); + userA.editor.nestBlock(); + + // B: nest N2 under N1 (in B's local view N1 is still a sibling). + userB.editor.setTextCursorPosition("n2", "start"); + userB.editor.nestBlock(); + + await waitForSuggestion(userA.editor); + await waitForSuggestion(userB.editor); + + sync(); + await waitForSuggestion(merged.editor); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "concurrent-indent-cascade", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + N0 + + + N1 + + + N2 + + " + `); + expect(ydocXml(suggestionDocA)).toMatchInlineSnapshot(` + " + + N0 + + + N1 + + + + + N2 + + " + `); + expect(ydocXml(suggestionDocB)).toMatchInlineSnapshot(` + " + + N0 + + + N1 + + + N2 + + + + " + `); + expect(ydocXml(suggestionDocMerged)).toMatchInlineSnapshot(` + " + + N0 + + + N1 + + + + " + `); + expect(editorHtml(merged.editor)).toMatchInlineSnapshot(` + " + + + N0 + + + + + + + N1 + + + + + + + + + + N1 + + + + + + + N2 + + + + + + " + `); +}); + +// Two non-overlapping child inserts under the same parent: +// A adds N1 as a child of N0; +// B adds N2 as a child of N0. +// +// KNOWN ISSUE: the CRDT merge result here is non-deterministic across +// runs because it depends on `Y.Doc.clientID` tiebreaking, which is +// randomly generated. Empirically we see two distinct outcomes: +// - A wins: N1 nested under N0, N2 ends up as a *sibling* of N0 +// with `` (B's nesting is silently lost); +// - B wins: N2 nested under N0, plus an auto-injected empty +// paragraph appears with N1 nested under *that* empty paragraph. +// Both are arguably bugs. We deliberately don't pin clientIDs at the +// fixture level (that would mask this), so the test is skipped until +// upstream merge behaviour is decided/fixed. The inline snapshots +// below preserve the "A wins" variant captured against a pinned-ID +// run, as documentation of one of the two observed outcomes. +test.skip("concurrent: A nests N1 under N0, B nests N2 under N0", async () => { + const { + userA, + userB, + merged, + baseDoc, + suggestionDocA, + suggestionDocB, + suggestionDocMerged, + screen, + seed, + enableSuggestions, + sync, + } = await setupConcurrentSuggestionTest({ + userAAction: "add child N1", + userBAction: "add child N2", + }); + + // Base: single block N0. + userA.editor.replaceBlocks(userA.editor.document, [ + { id: "n0", type: "paragraph", content: "N0" }, + ]); + seed(); + await expectVisible(screen.getByTestId(userA.testId).getByText("N0")); + + enableSuggestions(); + + // A: insert N1 as sibling of N0, then nest under N0. + userA.editor.insertBlocks( + [{ id: "n1", type: "paragraph", content: "N1" }], + "n0", + "after", + ); + userA.editor.setTextCursorPosition("n1", "start"); + userA.editor.nestBlock(); + + // B: same shape with N2. + userB.editor.insertBlocks( + [{ id: "n2", type: "paragraph", content: "N2" }], + "n0", + "after", + ); + userB.editor.setTextCursorPosition("n2", "start"); + userB.editor.nestBlock(); + + await waitForSuggestion(userA.editor); + await waitForSuggestion(userB.editor); + + sync(); + // Wait until both inserts have actually rendered in the merged + // column. Waiting on just the PM state (or `waitForSuggestion`) + // races the React/DOM commit – the screenshot sometimes captures a + // 100px layout, sometimes 121px. + await expectVisible(screen.getByTestId("editor-merged").getByText("N1")); + await expectVisible(screen.getByTestId("editor-merged").getByText("N2")); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + N0 + + " + `); + expect(ydocXml(suggestionDocA)).toMatchInlineSnapshot(` + " + + N0 + + + N1 + + + + " + `); + expect(ydocXml(suggestionDocB)).toMatchInlineSnapshot(` + " + + N0 + + + N2 + + + + " + `); + expect(ydocXml(suggestionDocMerged)).toMatchInlineSnapshot(` + " + + N0 + + + N1 + + + + + N2 + + " + `); + // TODO: the merge is asymmetric – A's N1 lands nested under N0 (as + // intended), but B's N2 ends up as a *sibling* even though B's local + // suggestion doc had N2 nested under N0 too. The first-to-nest wins, + // the second user's nesting is silently lost. If both users see the + // exact same operation in their local view, we'd expect the merge to + // preserve both nestings (or at least surface the conflict). + expect(editorHtml(merged.editor)).toMatchInlineSnapshot(` + " + + + N0 + + + + N1 + + + + + + + N2 + + + + " + `); +}); diff --git a/tests/src/end-to-end/y-prosemirror/nesting.test.tsx b/tests/src/end-to-end/y-prosemirror/nesting.test.tsx new file mode 100644 index 0000000000..8230f693cb --- /dev/null +++ b/tests/src/end-to-end/y-prosemirror/nesting.test.tsx @@ -0,0 +1,208 @@ +/* eslint-disable testing-library/render-result-naming-convention */ +/** + * Vitest browser-mode tests for nesting-related suggestions: indent, + * unindent, and type-change on a block that already has children. + * Same shape as `propChanges.test.tsx`. + * + * The third test (`change parent type with children`) is marked + * `test.fails` because it hits the same known y-prosemirror + * `deltaToPSteps` bug that affects all type-changes-in-suggestion-mode + * (see `typeChanges.test.tsx`). + */ +import { SuggestionsExtension } from "@blocknote/core/y"; +import { expect, test } from "vite-plus/test"; +import { expectScreenshot, expectVisible } from "./fixtures/browserExpect.js"; + +import { + editorHtml, + setupSuggestionTest, + ydocXml, +} from "./fixtures/suggestionFixture.js"; + +// Indent: take two sibling paragraphs and nest the second under the +// first. +test("suggestion mode: indent a block", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "indent N1" }); + + editor.replaceBlocks(editor.document, [ + { id: "n0", type: "paragraph", content: "N0" }, + { id: "n1", type: "paragraph", content: "N1" }, + ]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("N0")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + // Place cursor in N1 and ask BlockNote to nest it under N0. + editor.setTextCursorPosition("n1", "start"); + editor.nestBlock(); + + await expect.poll(() => editor.document[0]?.children.length).toBe(1); + + await expectScreenshot(screen.getByTestId("editor-root"), "nesting-indent"); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + N0 + + + N1 + + " + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + N0 + + + N1 + + + + " + `); + // Structural move encoded as insert-at-new-location + node-level + // delete on the old location. The original N1 sibling at the bottom + // is wrapped in `` (block-level mark) and the + // new nested copy is wrapped in `` at several + // levels. So accept/reject UI does have the data to render this + // sensibly – the snapshot below is the source of truth. + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + N0 + + + + + + + N1 + + + + + + + + + + N1 + + + + " + `); +}); + +// Unindent: nested child becomes a sibling of its parent. +test("suggestion mode: unindent a block", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "unindent N1" }); + + editor.replaceBlocks(editor.document, [ + { + id: "n0", + type: "paragraph", + content: "N0", + children: [{ id: "n1", type: "paragraph", content: "N1" }], + }, + ]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("N0")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + editor.setTextCursorPosition("n1", "start"); + editor.unnestBlock(); + + await expect.poll(() => editor.document.length).toBe(2); + + await expectScreenshot(screen.getByTestId("editor-root"), "nesting-unindent"); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + N0 + + + N1 + + + + " + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + N0 + + + N1 + + " + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + N0 + + + + N1 + + + + + + + + + N1 + + + + + + " + `); +}); + +// Change parent block's type while keeping its children. Hits the +// known y-prosemirror type-change bug. +test.fails("suggestion mode: change block type of a block with children", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "parent → heading" }); + + editor.replaceBlocks(editor.document, [ + { + id: "n0", + type: "paragraph", + content: "N0", + children: [{ id: "n1", type: "paragraph", content: "N1" }], + }, + ]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("N0")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + const [parent] = editor.document; + editor.updateBlock(parent, { type: "heading", props: { level: 1 } }); + + await expect.poll(() => editor.document[0]?.type).toBe("heading"); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "nesting-change-parent-type", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(); + expect(editorHtml(editor)).toMatchInlineSnapshot(); +}); diff --git a/tests/src/end-to-end/y-prosemirror/propChanges.concurrent.test.tsx b/tests/src/end-to-end/y-prosemirror/propChanges.concurrent.test.tsx new file mode 100644 index 0000000000..c088118bd5 --- /dev/null +++ b/tests/src/end-to-end/y-prosemirror/propChanges.concurrent.test.tsx @@ -0,0 +1,127 @@ +/* eslint-disable testing-library/render-result-naming-convention */ +/** + * Vitest browser-mode tests for two-user concurrent prop-change + * suggestions. Same shape as `basicText.concurrent.test.tsx` but the + * edits are block-level prop changes rather than content edits. + * + * See `propChanges.test.tsx` for the TODO on prop changes producing no + * `y-attributed-*` mark – the same applies here. + */ +import { expect, test } from "vite-plus/test"; +import { expectScreenshot, expectVisible } from "./fixtures/browserExpect.js"; + +import { setupConcurrentSuggestionTest } from "./fixtures/concurrentSuggestionFixture.js"; +import { editorHtml, ydocXml } from "./fixtures/suggestionFixture.js"; + +// Two users edit independent props on the same block: A changes +// `textColor`, B changes `backgroundColor`. Neither edit touches the +// other's prop, so the CRDT merge should preserve both. +test("concurrent: A changes textColor, B changes backgroundColor", async () => { + const { + userA, + userB, + merged, + baseDoc, + suggestionDocA, + suggestionDocB, + suggestionDocMerged, + screen, + seed, + enableSuggestions, + sync, + } = await setupConcurrentSuggestionTest({ + userAAction: "red text", + userBAction: "yellow background", + }); + + // Seed: plain "hello world" with default colors. + userA.editor.replaceBlocks(userA.editor.document, [ + { id: "block-hello", type: "paragraph", content: "hello world" }, + ]); + seed(); + await expectVisible( + screen.getByTestId(userA.testId).getByText("hello world"), + ); + + enableSuggestions(); + + // A: change textColor to red. + const [blockA] = userA.editor.document; + userA.editor.updateBlock(blockA, { + type: "paragraph", + props: { textColor: "red" }, + }); + + // B: change backgroundColor to yellow. + const [blockB] = userB.editor.document; + userB.editor.updateBlock(blockB, { + type: "paragraph", + props: { backgroundColor: "yellow" }, + }); + + // Prop changes don't generate y-attributed marks, so we poll on the + // individual editor doc states instead. + type ColorProps = { textColor?: string; backgroundColor?: string }; + await expect + .poll(() => (userA.editor.document[0]?.props as ColorProps)?.textColor) + .toBe("red"); + await expect + .poll( + () => (userB.editor.document[0]?.props as ColorProps)?.backgroundColor, + ) + .toBe("yellow"); + + sync(); + + await expect + .poll(() => (merged.editor.document[0]?.props as ColorProps)?.textColor) + .toBe("red"); + await expect + .poll( + () => (merged.editor.document[0]?.props as ColorProps)?.backgroundColor, + ) + .toBe("yellow"); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "concurrent-textColor-vs-backgroundColor", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + hello world + + " + `); + expect(ydocXml(suggestionDocA)).toMatchInlineSnapshot(` + " + + hello world + + " + `); + expect(ydocXml(suggestionDocB)).toMatchInlineSnapshot(` + " + + hello world + + " + `); + expect(ydocXml(suggestionDocMerged)).toMatchInlineSnapshot(` + " + + hello world + + " + `); + expect(editorHtml(merged.editor)).toMatchInlineSnapshot(` + " + + + hello world + + + " + `); +}); diff --git a/tests/src/end-to-end/y-prosemirror/propChanges.test.tsx b/tests/src/end-to-end/y-prosemirror/propChanges.test.tsx new file mode 100644 index 0000000000..b0ffb6bb7f --- /dev/null +++ b/tests/src/end-to-end/y-prosemirror/propChanges.test.tsx @@ -0,0 +1,353 @@ +/* eslint-disable testing-library/render-result-naming-convention */ +/** + * Vitest browser-mode tests for prop-change suggestions: block-level + * attribute edits (text alignment, heading level, image width / source, + * etc.) rather than content/text edits. Each test follows the same + * shape as `basicText.test.tsx`: seed, enable suggestions, edit, then + * screenshot + inline snapshots of base/suggestion docs + PM doc. + */ +import { SuggestionsExtension } from "@blocknote/core/y"; +import { expect, test } from "vite-plus/test"; +import { expectScreenshot, expectVisible } from "./fixtures/browserExpect.js"; + +import { + editorHtml, + setupSuggestionTest, + ydocXml, +} from "./fixtures/suggestionFixture.js"; + +// Tiny inline SVG data URLs – avoids a network fetch (placehold.co +// occasionally returns after the screenshot is taken). +const IMG_SRC_BASE = + "data:image/svg+xml;utf8,"; +const IMG_SRC_NEW = + "data:image/svg+xml;utf8,"; + +// TODO: block-level prop changes generate NO `y-attributed-*` mark in +// the editor's PM doc – the suggestion doc carries the new value but +// the editor shows it as if it were already accepted. Compare with the +// inline-format case in `basicText.test.tsx` which at least produces a +// `y-attributed-format` mark (still no visual style, but at least +// detectable from the data). Decide whether block-prop suggestions +// should also be wrapped in a `y-attributed-format` (or similar) so +// reviewers / accept-reject UI can target them. +// +// Block-level prop change: paragraph's `textAlignment` flips from +// "left" to "center". Text content is unchanged. +test("suggestion mode: change text alignment to center", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "center align" }); + + editor.replaceBlocks(editor.document, [ + { id: "block-hello", type: "paragraph", content: "hello world" }, + ]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("hello world")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + const [block] = editor.document; + editor.updateBlock(block, { + type: "paragraph", + props: { textAlignment: "center" }, + }); + + // Prop changes don't generate `y-attributed-*` marks, so the + // `waitForSuggestion` helper used elsewhere is too narrow here. + // Poll on the editor's view of the prop instead. + await expect + .poll( + () => + (editor.document[0]?.props as { textAlignment?: string }) + ?.textAlignment, + ) + .toBe("center"); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "prop-change-text-alignment", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + hello world + + " + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + hello world + + " + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + hello world + + + " + `); +}); + +// Block-level prop change on a heading: bump `level` from 1 to 2. +// Same lack of attribution as the alignment case. +test("suggestion mode: change heading level from 1 to 2", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "demote heading" }); + + editor.replaceBlocks(editor.document, [ + { + id: "block-hello", + type: "heading", + props: { level: 1 }, + content: "hello world", + }, + ]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("hello world")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + const [block] = editor.document; + editor.updateBlock(block, { + type: "heading", + props: { level: 2 }, + }); + + await expect + .poll(() => (editor.document[0]?.props as { level?: number })?.level) + .toBe(2); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "prop-change-heading-level", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + hello world + + " + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + hello world + + " + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + hello world + + + " + `); +}); + +// Image block prop change: `previewWidth`. Resizes the image, no +// content/text change. +test("suggestion mode: resize image (previewWidth)", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "resize image" }); + + editor.replaceBlocks(editor.document, [ + { + id: "block-image", + type: "image", + props: { + url: IMG_SRC_BASE, + previewWidth: 200, + }, + }, + ]); + sync(); + // Default `alt=""` on the image makes it decorative, so + // `getByRole("img")` doesn't see it. Poll on the prop having + // landed in the editor instead. + await expect + .poll(() => (editor.document[0]?.props as { url?: string })?.url) + .toBe(IMG_SRC_BASE); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + const [block] = editor.document; + editor.updateBlock(block, { + type: "image", + props: { previewWidth: 400 }, + }); + + await expect + .poll( + () => + (editor.document[0]?.props as { previewWidth?: number })?.previewWidth, + ) + .toBe(400); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "prop-change-image-width", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + + + " + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + + + " + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + + + + " + `); +}); + +// Image block prop change: `url`. Swaps the image source. +test("suggestion mode: change image source", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "swap image src" }); + + editor.replaceBlocks(editor.document, [ + { + id: "block-image", + type: "image", + props: { + url: IMG_SRC_BASE, + previewWidth: 200, + }, + }, + ]); + sync(); + // Default `alt=""` on the image makes it decorative, so + // `getByRole("img")` doesn't see it. Poll on the prop having + // landed in the editor instead. + await expect + .poll(() => (editor.document[0]?.props as { url?: string })?.url) + .toBe(IMG_SRC_BASE); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + const [block] = editor.document; + editor.updateBlock(block, { + type: "image", + props: { url: IMG_SRC_NEW }, + }); + + await expect + .poll(() => (editor.document[0]?.props as { url?: string })?.url) + .toBe(IMG_SRC_NEW); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "prop-change-image-source", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + + + " + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + + + " + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + + + + " + `); +}); diff --git a/tests/src/end-to-end/y-prosemirror/tables.concurrent.test.tsx b/tests/src/end-to-end/y-prosemirror/tables.concurrent.test.tsx new file mode 100644 index 0000000000..08cf014b84 --- /dev/null +++ b/tests/src/end-to-end/y-prosemirror/tables.concurrent.test.tsx @@ -0,0 +1,1425 @@ +/* eslint-disable testing-library/render-result-naming-convention */ +/** + * Vitest browser-mode tests for two-user concurrent table edits. + * Same shape as the other `.concurrent.test.tsx` files. + */ +import { expect, test } from "vite-plus/test"; +import { expectScreenshot, expectVisible } from "./fixtures/browserExpect.js"; + +import { setupConcurrentSuggestionTest } from "./fixtures/concurrentSuggestionFixture.js"; +import { + editorHtml, + waitForSuggestion, + ydocXml, +} from "./fixtures/suggestionFixture.js"; + +// Shared 2x2 starting table. +const TABLE_2X2 = { + id: "table", + type: "table" as const, + content: { + type: "tableContent" as const, + rows: [{ cells: ["A1", "B1"] }, { cells: ["A2", "B2"] }], + }, +}; + +// A deletes the last row, B adds a third column. Two disjoint +// structural edits to the same table. +// The merged editor's afterTransaction throws +// `applyChangesetToDelta: Unexpected case` in y-prosemirror when +// these two suggestions sync, so this is marked `test.fails` until +// upstream supports this interleaving. +test.fails("concurrent: A deletes a row, B adds a column", async () => { + const { + userA, + userB, + merged, + baseDoc, + suggestionDocA, + suggestionDocB, + suggestionDocMerged, + screen, + seed, + enableSuggestions, + sync, + } = await setupConcurrentSuggestionTest({ + userAAction: "delete last row", + userBAction: "add column", + }); + + userA.editor.replaceBlocks(userA.editor.document, [TABLE_2X2]); + seed(); + await expectVisible(screen.getByTestId(userA.testId).getByText("A1")); + + enableSuggestions(); + + // A: drop row 2. + userA.editor.updateBlock("table", { + type: "table", + content: { + type: "tableContent", + rows: [{ cells: ["A1", "B1"] }], + }, + }); + + // B: add a third column. + userB.editor.updateBlock("table", { + type: "table", + content: { + type: "tableContent", + rows: [{ cells: ["A1", "B1", "C1"] }, { cells: ["A2", "B2", "C2"] }], + }, + }); + + await waitForSuggestion(userA.editor); + await waitForSuggestion(userB.editor); + + sync(); + await waitForSuggestion(merged.editor); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "table-concurrent-row-vs-column", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(); + expect(ydocXml(suggestionDocA)).toMatchInlineSnapshot(); + expect(ydocXml(suggestionDocB)).toMatchInlineSnapshot(); + expect(ydocXml(suggestionDocMerged)).toMatchInlineSnapshot(); + expect(editorHtml(merged.editor)).toMatchInlineSnapshot(); +}); + +// Both users grow the table in independent directions: A adds a +// third row, B adds a third column. +test("concurrent: A adds a row, B adds a column", async () => { + const { + userA, + userB, + merged, + baseDoc, + suggestionDocA, + suggestionDocB, + suggestionDocMerged, + screen, + seed, + enableSuggestions, + sync, + } = await setupConcurrentSuggestionTest({ + userAAction: "add row", + userBAction: "add column", + }); + + userA.editor.replaceBlocks(userA.editor.document, [TABLE_2X2]); + seed(); + await expectVisible(screen.getByTestId(userA.testId).getByText("A1")); + + enableSuggestions(); + + // A: add a third row. + userA.editor.updateBlock("table", { + type: "table", + content: { + type: "tableContent", + rows: [ + { cells: ["A1", "B1"] }, + { cells: ["A2", "B2"] }, + { cells: ["A3", "B3"] }, + ], + }, + }); + + // B: add a third column. + userB.editor.updateBlock("table", { + type: "table", + content: { + type: "tableContent", + rows: [{ cells: ["A1", "B1", "C1"] }, { cells: ["A2", "B2", "C2"] }], + }, + }); + + await waitForSuggestion(userA.editor); + await waitForSuggestion(userB.editor); + + sync(); + await waitForSuggestion(merged.editor); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "table-concurrent-row-and-column", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + + + + A2 + + + B2 + + +
+
+
" + `); + expect(ydocXml(suggestionDocA)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + + + + A2 + + + B2 + + + + + A3 + + + B3 + + +
+
+
" + `); + expect(ydocXml(suggestionDocB)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + + C1 + + + + + A2 + + + B2 + + + C2 + + +
+
+
" + `); + expect(ydocXml(suggestionDocMerged)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + + C1 + + + + + A2 + + + B2 + + + C2 + + + + + A3 + + + B3 + + + + + +
+
+
" + `); + expect(editorHtml(merged.editor)).toMatchInlineSnapshot(` + " + + + + + + A1 + + + B1 + + + + + + C1 + + + + + + + + A2 + + + B2 + + + + + + C2 + + + + + + + + + + + + A3 + + + + + + + + + B3 + + + + + + + + + +
+
+
+
" + `); +}); + +// A deletes the last column, B adds a third row. Mirrors the +// `delete-row vs add-column` case along the other axis. +// The merge converges with B's column deleted and the new row +// inserted, captured in the snapshots below. +test("concurrent: A deletes a column, B adds a row", async () => { + const { + userA, + userB, + merged, + baseDoc, + suggestionDocA, + suggestionDocB, + suggestionDocMerged, + screen, + seed, + enableSuggestions, + sync, + } = await setupConcurrentSuggestionTest({ + userAAction: "delete last column", + userBAction: "add row", + }); + + userA.editor.replaceBlocks(userA.editor.document, [TABLE_2X2]); + seed(); + await expectVisible(screen.getByTestId(userA.testId).getByText("A1")); + + enableSuggestions(); + + // A: drop column B. + userA.editor.updateBlock("table", { + type: "table", + content: { + type: "tableContent", + rows: [{ cells: ["A1"] }, { cells: ["A2"] }], + }, + }); + + // B: add a third row. + userB.editor.updateBlock("table", { + type: "table", + content: { + type: "tableContent", + rows: [ + { cells: ["A1", "B1"] }, + { cells: ["A2", "B2"] }, + { cells: ["A3", "B3"] }, + ], + }, + }); + + await waitForSuggestion(userA.editor); + await waitForSuggestion(userB.editor); + + sync(); + await waitForSuggestion(merged.editor); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "table-concurrent-delete-column-vs-add-row", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + + + + A2 + + + B2 + + +
+
+
" + `); + expect(ydocXml(suggestionDocA)).toMatchInlineSnapshot(` + " + + + + + A1 + + + + + A2 + + +
+
+
" + `); + expect(ydocXml(suggestionDocB)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + + + + A2 + + + B2 + + + + + A3 + + + B3 + + +
+
+
" + `); + expect(ydocXml(suggestionDocMerged)).toMatchInlineSnapshot(` + " + + + + + A1 + + + + + A2 + + + + + A3 + + + B3 + + +
+
+
" + `); + expect(editorHtml(merged.editor)).toMatchInlineSnapshot(` + " + + + + + + A1 + + + + B1 + + + + + + A2 + + + + B2 + + + + + + + + + + A3 + + + + + + + + + B3 + + + + + + +
+
+
+
" + `); +}); + +// A adds a column, B adds a row. Mirror of `add-row + add-column`, +// just swapped per-user – CRDT should converge to the same 3x3. +test("concurrent: A adds a column, B adds a row", async () => { + const { + userA, + userB, + merged, + baseDoc, + suggestionDocA, + suggestionDocB, + suggestionDocMerged, + screen, + seed, + enableSuggestions, + sync, + } = await setupConcurrentSuggestionTest({ + userAAction: "add column", + userBAction: "add row", + }); + + userA.editor.replaceBlocks(userA.editor.document, [TABLE_2X2]); + seed(); + await expectVisible(screen.getByTestId(userA.testId).getByText("A1")); + + enableSuggestions(); + + // A: add a third column. + userA.editor.updateBlock("table", { + type: "table", + content: { + type: "tableContent", + rows: [{ cells: ["A1", "B1", "C1"] }, { cells: ["A2", "B2", "C2"] }], + }, + }); + + // B: add a third row. + userB.editor.updateBlock("table", { + type: "table", + content: { + type: "tableContent", + rows: [ + { cells: ["A1", "B1"] }, + { cells: ["A2", "B2"] }, + { cells: ["A3", "B3"] }, + ], + }, + }); + + await waitForSuggestion(userA.editor); + await waitForSuggestion(userB.editor); + + sync(); + await waitForSuggestion(merged.editor); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "table-concurrent-add-column-and-add-row", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + + + + A2 + + + B2 + + +
+
+
" + `); + expect(ydocXml(suggestionDocA)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + + C1 + + + + + A2 + + + B2 + + + C2 + + +
+
+
" + `); + expect(ydocXml(suggestionDocB)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + + + + A2 + + + B2 + + + + + A3 + + + B3 + + +
+
+
" + `); + expect(ydocXml(suggestionDocMerged)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + + C1 + + + + + A2 + + + B2 + + + C2 + + + + + A3 + + + B3 + + + + + +
+
+
" + `); + expect(editorHtml(merged.editor)).toMatchInlineSnapshot(` + " + + + + + + A1 + + + B1 + + + + + + C1 + + + + + + + + A2 + + + B2 + + + + + + C2 + + + + + + + + + + + + A3 + + + + + + + + + B3 + + + + + + + + + +
+
+
+
" + `); +}); diff --git a/tests/src/end-to-end/y-prosemirror/tables.test.tsx b/tests/src/end-to-end/y-prosemirror/tables.test.tsx new file mode 100644 index 0000000000..2413e0ddb7 --- /dev/null +++ b/tests/src/end-to-end/y-prosemirror/tables.test.tsx @@ -0,0 +1,1612 @@ +/* eslint-disable testing-library/render-result-naming-convention */ +/** + * Vitest browser-mode tests for table suggestions: add / remove rows + * and columns, edit cell content, change cell color, merge / split. + * Same shape as the other categories. + * + * Table block is the one place in BlockNote where `y-attributed-*` + * marks are declared on the block content node (see Table/block.ts), + * so the suggestion infrastructure has the most schema support here. + */ +import { SuggestionsExtension } from "@blocknote/core/y"; +import { expect, test } from "vite-plus/test"; +import { expectScreenshot, expectVisible } from "./fixtures/browserExpect.js"; + +import { + editorHtml, + setupSuggestionTest, + ydocXml, +} from "./fixtures/suggestionFixture.js"; + +// Shared 2x2 table baseline used by most of the tests below. +const TABLE_2X2 = { + id: "table", + type: "table" as const, + content: { + type: "tableContent" as const, + rows: [{ cells: ["A1", "B1"] }, { cells: ["A2", "B2"] }], + }, +}; + +// Add a third row to a 2x2 table. +test("suggestion mode: add row", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "add row" }); + + editor.replaceBlocks(editor.document, [TABLE_2X2]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("A1")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + editor.updateBlock("table", { + type: "table", + content: { + type: "tableContent", + rows: [ + { cells: ["A1", "B1"] }, + { cells: ["A2", "B2"] }, + { cells: ["A3", "B3"] }, + ], + }, + }); + + await expect.poll(() => editor.document[0]?.children.length).toBe(0); + await expectVisible(screen.getByTestId("editor-A").getByText("A3")); + + await expectScreenshot(screen.getByTestId("editor-root"), "table-add-row"); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + + + + A2 + + + B2 + + +
+
+
" + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + + + + A2 + + + B2 + + + + + A3 + + + B3 + + +
+
+
" + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + + + + A1 + + + B1 + + + + + A2 + + + B2 + + + + + + + + + A3 + + + + + + + + + B3 + + + + + + +
+
+
+
" + `); +}); + +// Add a third column to a 2x2 table. +test("suggestion mode: add column", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "add column" }); + + editor.replaceBlocks(editor.document, [TABLE_2X2]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("A1")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + editor.updateBlock("table", { + type: "table", + content: { + type: "tableContent", + rows: [{ cells: ["A1", "B1", "C1"] }, { cells: ["A2", "B2", "C2"] }], + }, + }); + + await expectVisible(screen.getByTestId("editor-A").getByText("C1")); + + await expectScreenshot(screen.getByTestId("editor-root"), "table-add-column"); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + + + + A2 + + + B2 + + +
+
+
" + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + + C1 + + + + + A2 + + + B2 + + + C2 + + +
+
+
" + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + + + + A1 + + + B1 + + + + + + C1 + + + + + + + + A2 + + + B2 + + + + + + C2 + + + + + +
+
+
+
" + `); +}); + +// Remove the second row from a 2x2 table. +test("suggestion mode: remove row", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "remove last row" }); + + editor.replaceBlocks(editor.document, [TABLE_2X2]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("A2")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + editor.updateBlock("table", { + type: "table", + content: { + type: "tableContent", + rows: [{ cells: ["A1", "B1"] }], + }, + }); + + await expectScreenshot(screen.getByTestId("editor-root"), "table-remove-row"); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + + + + A2 + + + B2 + + +
+
+
" + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + +
+
+
" + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + + + + A1 + + + B1 + + + + + + A2 + + + B2 + + + +
+
+
+
" + `); +}); + +// Remove the second column from a 2x2 table. +test("suggestion mode: remove column", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "remove last column" }); + + editor.replaceBlocks(editor.document, [TABLE_2X2]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("B1")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + editor.updateBlock("table", { + type: "table", + content: { + type: "tableContent", + rows: [{ cells: ["A1"] }, { cells: ["A2"] }], + }, + }); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "table-remove-column", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + + + + A2 + + + B2 + + +
+
+
" + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + + + + A1 + + + + + A2 + + +
+
+
" + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + + + + A1 + + + + B1 + + + + + + A2 + + + + B2 + + + +
+
+
+
" + `); +}); + +// Change the text in cell (A1) -> (A1 edited). +test("suggestion mode: update text in cell", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "edit top-left cell" }); + + editor.replaceBlocks(editor.document, [TABLE_2X2]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("A1")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + editor.updateBlock("table", { + type: "table", + content: { + type: "tableContent", + rows: [{ cells: ["A1 edited", "B1"] }, { cells: ["A2", "B2"] }], + }, + }); + + await expectVisible(screen.getByTestId("editor-A").getByText("edited")); + + await expectScreenshot(screen.getByTestId("editor-root"), "table-edit-cell"); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + + + + A2 + + + B2 + + +
+
+
" + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + + + + A1 edited + + + B1 + + + + + A2 + + + B2 + + +
+
+
" + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + + + + + A1 + edited + + + + B1 + + + + + A2 + + + B2 + + +
+
+
+
" + `); +}); + +// Change `backgroundColor` of every cell in the first column. +test("suggestion mode: change column background color", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "highlight first column" }); + + editor.replaceBlocks(editor.document, [TABLE_2X2]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("A1")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + editor.updateBlock("table", { + type: "table", + content: { + type: "tableContent", + rows: [ + { + cells: [ + { + type: "tableCell", + props: { backgroundColor: "yellow" }, + content: ["A1"], + }, + { type: "tableCell", content: ["B1"] }, + ], + }, + { + cells: [ + { + type: "tableCell", + props: { backgroundColor: "yellow" }, + content: ["A2"], + }, + { type: "tableCell", content: ["B2"] }, + ], + }, + ], + }, + }); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "table-column-color", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + + + + A2 + + + B2 + + +
+
+
" + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + + + + A2 + + + B2 + + +
+
+
" + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + + + + A1 + + + B1 + + + + + A2 + + + B2 + + +
+
+
+
" + `); +}); + +// TODO: this is broken as it's an extra "deleted column" is shown + +// Merge two horizontally adjacent cells in the top row by setting +// colspan=2 on the first cell and dropping the second. +test("suggestion mode: merge two cells", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "merge top-row cells" }); + + editor.replaceBlocks(editor.document, [TABLE_2X2]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("A1")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + editor.updateBlock("table", { + type: "table", + content: { + type: "tableContent", + rows: [ + { + cells: [ + { + type: "tableCell", + props: { colspan: 2 }, + content: ["A1+B1"], + }, + ], + }, + { cells: ["A2", "B2"] }, + ], + }, + }); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "table-merge-cells", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + + + + A2 + + + B2 + + +
+
+
" + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + + + + A1+B1 + + + + + A2 + + + B2 + + + + + +
+
+
" + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + + + + + A1 + +B1 + + + + + B1 + + + + + + A2 + + + B2 + + + + + + + + + +
+
+
+
" + `); +}); + +// Start from a 2x2 table whose top-left cell has colspan=2, then +// split it back into two cells. +test("suggestion mode: split a merged cell", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "split top-row cell" }); + + editor.replaceBlocks(editor.document, [ + { + id: "table", + type: "table", + content: { + type: "tableContent", + rows: [ + { + cells: [ + { + type: "tableCell", + props: { colspan: 2 }, + content: ["A1+B1"], + }, + ], + }, + { cells: ["A2", "B2"] }, + ], + }, + }, + ]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("A1+B1")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + editor.updateBlock("table", { + type: "table", + content: { + type: "tableContent", + rows: [{ cells: ["A1", "B1"] }, { cells: ["A2", "B2"] }], + }, + }); + + await expectScreenshot(screen.getByTestId("editor-root"), "table-split-cell"); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(` + " + + + + + A1+B1 + + + + + A2 + + + B2 + + +
+
+
" + `); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(` + " + + + + + A1 + + + B1 + + + + + A2 + + + B2 + + +
+
+
" + `); + expect(editorHtml(editor)).toMatchInlineSnapshot(` + " + + + + + + + A1 + +B1 + + + + + + + B1 + + + + + + + + A2 + + + B2 + + +
+
+
+
" + `); +}); diff --git a/tests/src/end-to-end/y-prosemirror/typeChanges.concurrent.test.tsx b/tests/src/end-to-end/y-prosemirror/typeChanges.concurrent.test.tsx new file mode 100644 index 0000000000..f5d2810334 --- /dev/null +++ b/tests/src/end-to-end/y-prosemirror/typeChanges.concurrent.test.tsx @@ -0,0 +1,137 @@ +/* eslint-disable testing-library/render-result-naming-convention */ +/** + * Vitest browser-mode tests for two-user concurrent type-change + * suggestions. Same shape as `propChanges.concurrent.test.tsx`. + * + * KNOWN BUG: see `typeChanges.test.tsx` – block-type changes in + * suggestion mode currently throw in y-prosemirror's `deltaToPSteps`. + * Both tests below are marked `test.fails`; when the upstream bug is + * fixed they will flip red and we can capture proper snapshots. + */ +import { expect, test } from "vite-plus/test"; +import { expectScreenshot, expectVisible } from "./fixtures/browserExpect.js"; + +import { setupConcurrentSuggestionTest } from "./fixtures/concurrentSuggestionFixture.js"; +import { editorHtml, ydocXml } from "./fixtures/suggestionFixture.js"; + +// Two competing type changes on the same block: A wants a heading, B +// wants a list item. +test.fails("concurrent: A → heading, B → list item", async () => { + const { + userA, + userB, + merged, + baseDoc, + suggestionDocA, + suggestionDocB, + suggestionDocMerged, + screen, + seed, + enableSuggestions, + sync, + } = await setupConcurrentSuggestionTest({ + userAAction: "→ heading", + userBAction: "→ list item", + }); + + userA.editor.replaceBlocks(userA.editor.document, [ + { id: "block-hello", type: "paragraph", content: "hello world" }, + ]); + seed(); + await expectVisible( + screen.getByTestId(userA.testId).getByText("hello world"), + ); + + enableSuggestions(); + + const [blockA] = userA.editor.document; + userA.editor.updateBlock(blockA, { + type: "heading", + props: { level: 1 }, + }); + + const [blockB] = userB.editor.document; + userB.editor.updateBlock(blockB, { type: "bulletListItem" }); + + await expect.poll(() => userA.editor.document[0]?.type).toBe("heading"); + await expect + .poll(() => userB.editor.document[0]?.type) + .toBe("bulletListItem"); + + sync(); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "concurrent-heading-vs-list", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(); + expect(ydocXml(suggestionDocA)).toMatchInlineSnapshot(); + expect(ydocXml(suggestionDocB)).toMatchInlineSnapshot(); + expect(ydocXml(suggestionDocMerged)).toMatchInlineSnapshot(); + expect(editorHtml(merged.editor)).toMatchInlineSnapshot(); +}); + +// Mixed: A does a text edit (no type change), B changes the type. +// Exercises the path where one user's suggestion is a regular text +// diff and the other's is a block-type swap. +test.fails("concurrent: A edits text, B → heading", async () => { + const { + userA, + userB, + merged, + baseDoc, + suggestionDocA, + suggestionDocB, + suggestionDocMerged, + screen, + seed, + enableSuggestions, + sync, + } = await setupConcurrentSuggestionTest({ + userAAction: "world → universe", + userBAction: "→ heading", + }); + + userA.editor.replaceBlocks(userA.editor.document, [ + { id: "block-hello", type: "paragraph", content: "hello world" }, + ]); + seed(); + await expectVisible( + screen.getByTestId(userA.testId).getByText("hello world"), + ); + + enableSuggestions(); + + const [blockA] = userA.editor.document; + userA.editor.updateBlock(blockA, { + type: "paragraph", + content: "hello universe", + }); + + const [blockB] = userB.editor.document; + userB.editor.updateBlock(blockB, { + type: "heading", + props: { level: 1 }, + }); + + await expect + .poll(() => + userA.editor.prosemirrorState.doc.toString().includes("y-attributed"), + ) + .toBe(true); + await expect.poll(() => userB.editor.document[0]?.type).toBe("heading"); + + sync(); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "concurrent-text-edit-vs-heading", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(); + expect(ydocXml(suggestionDocA)).toMatchInlineSnapshot(); + expect(ydocXml(suggestionDocB)).toMatchInlineSnapshot(); + expect(ydocXml(suggestionDocMerged)).toMatchInlineSnapshot(); + expect(editorHtml(merged.editor)).toMatchInlineSnapshot(); +}); diff --git a/tests/src/end-to-end/y-prosemirror/typeChanges.test.tsx b/tests/src/end-to-end/y-prosemirror/typeChanges.test.tsx new file mode 100644 index 0000000000..b231c43251 --- /dev/null +++ b/tests/src/end-to-end/y-prosemirror/typeChanges.test.tsx @@ -0,0 +1,84 @@ +/* eslint-disable testing-library/render-result-naming-convention */ +/** + * Vitest browser-mode tests for type-change suggestions: swapping the + * block type (paragraph ↔ heading ↔ list item) while preserving its + * inline content. Same shape as `propChanges.test.tsx`. + * + * KNOWN BUG: `editor.updateBlock(block, { type: ... })` in suggestion + * mode currently throws `TransformError: No node at mark step's + * position` from y-prosemirror's `deltaToPSteps`. Tests are marked + * `test.fails` so they pass while the bug exists – when the + * underlying issue is fixed, the tests will start passing for real + * and `test.fails` will flip them red, signalling that snapshots need + * to be captured. + */ +import { SuggestionsExtension } from "@blocknote/core/y"; +import { expect, test } from "vite-plus/test"; +import { expectScreenshot, expectVisible } from "./fixtures/browserExpect.js"; + +import { + editorHtml, + setupSuggestionTest, + ydocXml, +} from "./fixtures/suggestionFixture.js"; + +// Demote a bullet-list item to a plain paragraph. Inline content +// "hello world" stays the same; only the wrapping node type changes. +test.fails("suggestion mode: change list item to paragraph", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "list → paragraph" }); + + editor.replaceBlocks(editor.document, [ + { + id: "block-hello", + type: "bulletListItem", + content: "hello world", + }, + ]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("hello world")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + const [block] = editor.document; + editor.updateBlock(block, { type: "paragraph" }); + + await expect.poll(() => editor.document[0]?.type).toBe("paragraph"); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "type-change-list-to-paragraph", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(); + expect(editorHtml(editor)).toMatchInlineSnapshot(); +}); + +// Promote a paragraph to a level-1 heading. Same inline content. +test.fails("suggestion mode: change paragraph to heading", async () => { + const { editor, screen, baseDoc, suggestionDoc, sync } = + await setupSuggestionTest({ userAction: "paragraph → heading" }); + + editor.replaceBlocks(editor.document, [ + { id: "block-hello", type: "paragraph", content: "hello world" }, + ]); + sync(); + await expectVisible(screen.getByTestId("editor-A").getByText("hello world")); + + editor.getExtension(SuggestionsExtension)!.enableSuggestions(); + + const [block] = editor.document; + editor.updateBlock(block, { type: "heading", props: { level: 1 } }); + + await expect.poll(() => editor.document[0]?.type).toBe("heading"); + + await expectScreenshot( + screen.getByTestId("editor-root"), + "type-change-paragraph-to-heading", + ); + + expect(ydocXml(baseDoc)).toMatchInlineSnapshot(); + expect(ydocXml(suggestionDoc)).toMatchInlineSnapshot(); + expect(editorHtml(editor)).toMatchInlineSnapshot(); +});