feat(rich-text): @bytelyst/rich-text@0.1.0 on Tiptap v3
RichTextEditor (toolbar + slash menu + async mentions, SSR-safe via immediatelyRender:false) + RichTextViewer (generateHTML, server-renderable) + standalone Toolbar. Pure filterSlashItems/filterUsers helpers. 12/12 vitest (incl. live editor mount + bold toggle in happy-dom); tsc clean; published to Gitea.
This commit is contained in:
parent
3224199894
commit
fc8502ac0c
48
packages/rich-text/package.json
Normal file
48
packages/rich-text/package.json
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"name": "@bytelyst/rich-text",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"type": "module",
|
||||||
|
"description": "Tiptap v3 rich-text editor + viewer with a token-themed toolbar, slash-menu and async mention extensions. SSR-safe for Next.",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc",
|
||||||
|
"test": "vitest run --pool forks",
|
||||||
|
"typecheck": "tsc --noEmit"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": ">=18.0.0",
|
||||||
|
"react-dom": ">=18.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@tiptap/core": "^3.23.6",
|
||||||
|
"@tiptap/extension-link": "^3.23.6",
|
||||||
|
"@tiptap/extension-mention": "^3.23.6",
|
||||||
|
"@tiptap/extension-placeholder": "^3.23.6",
|
||||||
|
"@tiptap/html": "^3.23.6",
|
||||||
|
"@tiptap/pm": "^3.23.6",
|
||||||
|
"@tiptap/react": "^3.23.6",
|
||||||
|
"@tiptap/starter-kit": "^3.23.6",
|
||||||
|
"@tiptap/suggestion": "^3.23.6",
|
||||||
|
"clsx": "^2.1.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@testing-library/react": "^16.3.2",
|
||||||
|
"@types/react": "^19.2.14",
|
||||||
|
"@types/react-dom": "^19.2.3",
|
||||||
|
"happy-dom": "^18.0.1",
|
||||||
|
"react": "^19.2.4",
|
||||||
|
"react-dom": "^19.2.4",
|
||||||
|
"typescript": "^5.7.3",
|
||||||
|
"vitest": "^4.0.18"
|
||||||
|
}
|
||||||
|
}
|
||||||
74
packages/rich-text/src/MentionList.tsx
Normal file
74
packages/rich-text/src/MentionList.tsx
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import type { SuggestionProps, SuggestionKeyDownProps } from '@tiptap/suggestion';
|
||||||
|
import type { MentionUser } from './mention.js';
|
||||||
|
|
||||||
|
export interface MentionListHandle {
|
||||||
|
onKeyDown: (props: SuggestionKeyDownProps) => boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Keyboard-navigable people picker shown while typing `@`. */
|
||||||
|
export const MentionList = React.forwardRef<MentionListHandle, SuggestionProps<MentionUser>>(
|
||||||
|
function MentionList(props, ref) {
|
||||||
|
const { items, command } = props;
|
||||||
|
const [selected, setSelected] = React.useState(0);
|
||||||
|
|
||||||
|
React.useEffect(() => setSelected(0), [items]);
|
||||||
|
|
||||||
|
const select = React.useCallback(
|
||||||
|
(index: number) => {
|
||||||
|
const item = items[index];
|
||||||
|
if (item) command({ id: item.id, label: item.label });
|
||||||
|
},
|
||||||
|
[items, command]
|
||||||
|
);
|
||||||
|
|
||||||
|
React.useImperativeHandle(ref, () => ({
|
||||||
|
onKeyDown: ({ event }) => {
|
||||||
|
if (event.key === 'ArrowUp') {
|
||||||
|
setSelected(s => (s + items.length - 1) % items.length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (event.key === 'ArrowDown') {
|
||||||
|
setSelected(s => (s + 1) % items.length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
select(selected);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
role="listbox"
|
||||||
|
aria-label="Mention people"
|
||||||
|
className="min-w-48 overflow-hidden rounded-lg border border-[var(--bl-border,rgba(0,0,0,0.12))] bg-[var(--bl-surface-card,#fff)] p-1 shadow-lg"
|
||||||
|
>
|
||||||
|
{items.length === 0 ? (
|
||||||
|
<div className="px-2.5 py-1.5 text-sm text-[var(--bl-text-tertiary,#999)]">No people</div>
|
||||||
|
) : (
|
||||||
|
items.map((item, index) => (
|
||||||
|
<button
|
||||||
|
key={item.id}
|
||||||
|
type="button"
|
||||||
|
role="option"
|
||||||
|
aria-selected={index === selected}
|
||||||
|
onMouseEnter={() => setSelected(index)}
|
||||||
|
onClick={() => select(index)}
|
||||||
|
className={
|
||||||
|
'flex w-full items-center rounded-md px-2.5 py-1.5 text-left text-sm ' +
|
||||||
|
(index === selected
|
||||||
|
? 'bg-[var(--bl-accent-muted,rgba(99,102,241,0.12))]'
|
||||||
|
: 'bg-transparent')
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{item.label}
|
||||||
|
</button>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
84
packages/rich-text/src/RichTextEditor.tsx
Normal file
84
packages/rich-text/src/RichTextEditor.tsx
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import * as React from 'react';
|
||||||
|
import { clsx } from 'clsx';
|
||||||
|
import { EditorContent, useEditor } from '@tiptap/react';
|
||||||
|
import type { AnyExtension, JSONContent } from '@tiptap/core';
|
||||||
|
|
||||||
|
import { buildExtensions } from './extensions.js';
|
||||||
|
import { SlashCommands } from './slashMenu.js';
|
||||||
|
import { createMention, type UserSearchFn } from './mention.js';
|
||||||
|
import { Toolbar } from './Toolbar.js';
|
||||||
|
|
||||||
|
export interface RichTextEditorProps {
|
||||||
|
/** Initial document — Tiptap JSON or an HTML string. */
|
||||||
|
content?: JSONContent | string;
|
||||||
|
/** Called with the latest JSON document on every change. */
|
||||||
|
onChange?: (doc: JSONContent) => void;
|
||||||
|
/** Placeholder shown when empty. */
|
||||||
|
placeholder?: string;
|
||||||
|
/** Enable the `/` slash command menu (default true). */
|
||||||
|
enableSlashMenu?: boolean;
|
||||||
|
/** Provide to enable `@`-mentions backed by this people search. */
|
||||||
|
mentionSearch?: UserSearchFn;
|
||||||
|
/** Read-only mode. */
|
||||||
|
editable?: boolean;
|
||||||
|
className?: string;
|
||||||
|
ariaLabel?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Full editor surface: token-themed toolbar + Tiptap editing area, with an
|
||||||
|
* optional slash menu and async mentions. SSR-safe (`immediatelyRender:
|
||||||
|
* false`) so it hydrates cleanly under Next.
|
||||||
|
*/
|
||||||
|
export function RichTextEditor({
|
||||||
|
content,
|
||||||
|
onChange,
|
||||||
|
placeholder,
|
||||||
|
enableSlashMenu = true,
|
||||||
|
mentionSearch,
|
||||||
|
editable = true,
|
||||||
|
className,
|
||||||
|
ariaLabel = 'Rich text editor',
|
||||||
|
}: RichTextEditorProps) {
|
||||||
|
const extra = React.useMemo<AnyExtension[]>(() => {
|
||||||
|
const list: AnyExtension[] = [];
|
||||||
|
if (enableSlashMenu) list.push(SlashCommands);
|
||||||
|
if (mentionSearch) list.push(createMention(mentionSearch));
|
||||||
|
// Extensions are fixed for a mount; deliberately not reactive.
|
||||||
|
return list;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const editor = useEditor({
|
||||||
|
immediatelyRender: false,
|
||||||
|
editable,
|
||||||
|
extensions: buildExtensions({ placeholder, extra }),
|
||||||
|
content,
|
||||||
|
editorProps: {
|
||||||
|
attributes: {
|
||||||
|
role: 'textbox',
|
||||||
|
'aria-multiline': 'true',
|
||||||
|
'aria-label': ariaLabel,
|
||||||
|
class: 'bl-rich-text-content min-h-40 p-3 outline-none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
onUpdate: ({ editor: e }) => onChange?.(e.getJSON()),
|
||||||
|
});
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
editor?.setEditable(editable);
|
||||||
|
}, [editor, editable]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={clsx(
|
||||||
|
'overflow-hidden rounded-xl border border-[var(--bl-border,rgba(0,0,0,0.12))] bg-[var(--bl-surface-card,#fff)]',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{editable && <Toolbar editor={editor} />}
|
||||||
|
<EditorContent editor={editor} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
29
packages/rich-text/src/RichTextViewer.tsx
Normal file
29
packages/rich-text/src/RichTextViewer.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { clsx } from 'clsx';
|
||||||
|
import { generateHTML } from '@tiptap/html';
|
||||||
|
import Mention from '@tiptap/extension-mention';
|
||||||
|
import type { JSONContent } from '@tiptap/core';
|
||||||
|
|
||||||
|
import { buildExtensions } from './extensions.js';
|
||||||
|
|
||||||
|
export interface RichTextViewerProps {
|
||||||
|
/** Tiptap JSON document to render read-only. */
|
||||||
|
doc: JSONContent;
|
||||||
|
className?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read-only renderer. Serialises a Tiptap JSON doc to HTML using the same
|
||||||
|
* extension schema as the editor (so output matches), with no editing surface
|
||||||
|
* and no client runtime — safe to render on the server.
|
||||||
|
*/
|
||||||
|
export function RichTextViewer({ doc, className }: RichTextViewerProps) {
|
||||||
|
const html = React.useMemo(() => generateHTML(doc, buildExtensions({ extra: [Mention] })), [doc]);
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={clsx('bl-rich-text-content', className)}
|
||||||
|
// Content is produced by Tiptap's own serializer from a trusted JSON doc.
|
||||||
|
dangerouslySetInnerHTML={{ __html: html }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
86
packages/rich-text/src/SlashMenuList.tsx
Normal file
86
packages/rich-text/src/SlashMenuList.tsx
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import type { SuggestionProps, SuggestionKeyDownProps } from '@tiptap/suggestion';
|
||||||
|
import type { SlashItem } from './slashMenu.js';
|
||||||
|
|
||||||
|
export interface SlashMenuListHandle {
|
||||||
|
onKeyDown: (props: SuggestionKeyDownProps) => boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keyboard-navigable list rendered inside the slash-menu popup. Exposes an
|
||||||
|
* imperative `onKeyDown` so the Suggestion plugin can route ↑/↓/Enter here.
|
||||||
|
*/
|
||||||
|
export const SlashMenuList = React.forwardRef<SlashMenuListHandle, SuggestionProps<SlashItem>>(
|
||||||
|
function SlashMenuList(props, ref) {
|
||||||
|
const { items, command } = props;
|
||||||
|
const [selected, setSelected] = React.useState(0);
|
||||||
|
|
||||||
|
React.useEffect(() => setSelected(0), [items]);
|
||||||
|
|
||||||
|
const select = React.useCallback(
|
||||||
|
(index: number) => {
|
||||||
|
const item = items[index];
|
||||||
|
if (item) command(item);
|
||||||
|
},
|
||||||
|
[items, command]
|
||||||
|
);
|
||||||
|
|
||||||
|
React.useImperativeHandle(ref, () => ({
|
||||||
|
onKeyDown: ({ event }) => {
|
||||||
|
if (event.key === 'ArrowUp') {
|
||||||
|
setSelected(s => (s + items.length - 1) % items.length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (event.key === 'ArrowDown') {
|
||||||
|
setSelected(s => (s + 1) % items.length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
select(selected);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
if (items.length === 0) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
role="listbox"
|
||||||
|
aria-label="Slash commands"
|
||||||
|
className="min-w-56 rounded-lg border border-[var(--bl-border,rgba(0,0,0,0.12))] bg-[var(--bl-surface-card,#fff)] p-2 text-sm text-[var(--bl-text-tertiary,#999)] shadow-lg"
|
||||||
|
>
|
||||||
|
No matches
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
role="listbox"
|
||||||
|
aria-label="Slash commands"
|
||||||
|
className="min-w-56 overflow-hidden rounded-lg border border-[var(--bl-border,rgba(0,0,0,0.12))] bg-[var(--bl-surface-card,#fff)] p-1 shadow-lg"
|
||||||
|
>
|
||||||
|
{items.map((item, index) => (
|
||||||
|
<button
|
||||||
|
key={item.title}
|
||||||
|
type="button"
|
||||||
|
role="option"
|
||||||
|
aria-selected={index === selected}
|
||||||
|
onMouseEnter={() => setSelected(index)}
|
||||||
|
onClick={() => select(index)}
|
||||||
|
className={
|
||||||
|
'flex w-full flex-col items-start rounded-md px-2.5 py-1.5 text-left text-sm ' +
|
||||||
|
(index === selected
|
||||||
|
? 'bg-[var(--bl-accent-muted,rgba(99,102,241,0.12))]'
|
||||||
|
: 'bg-transparent')
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<span className="font-medium text-[var(--bl-text-primary,#111)]">{item.title}</span>
|
||||||
|
<span className="text-xs text-[var(--bl-text-tertiary,#999)]">{item.description}</span>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
125
packages/rich-text/src/Toolbar.tsx
Normal file
125
packages/rich-text/src/Toolbar.tsx
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { clsx } from 'clsx';
|
||||||
|
import type { Editor } from '@tiptap/core';
|
||||||
|
|
||||||
|
export interface ToolbarProps {
|
||||||
|
editor: Editor | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ToolButton {
|
||||||
|
label: string;
|
||||||
|
/** aria-label / accessible name. */
|
||||||
|
name: string;
|
||||||
|
isActive?: (e: Editor) => boolean;
|
||||||
|
run: (e: Editor) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const BUTTONS: ToolButton[] = [
|
||||||
|
{
|
||||||
|
label: 'B',
|
||||||
|
name: 'Bold',
|
||||||
|
isActive: e => e.isActive('bold'),
|
||||||
|
run: e => e.chain().focus().toggleBold().run(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'I',
|
||||||
|
name: 'Italic',
|
||||||
|
isActive: e => e.isActive('italic'),
|
||||||
|
run: e => e.chain().focus().toggleItalic().run(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'H1',
|
||||||
|
name: 'Heading 1',
|
||||||
|
isActive: e => e.isActive('heading', { level: 1 }),
|
||||||
|
run: e => e.chain().focus().toggleHeading({ level: 1 }).run(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'H2',
|
||||||
|
name: 'Heading 2',
|
||||||
|
isActive: e => e.isActive('heading', { level: 2 }),
|
||||||
|
run: e => e.chain().focus().toggleHeading({ level: 2 }).run(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '• List',
|
||||||
|
name: 'Bullet list',
|
||||||
|
isActive: e => e.isActive('bulletList'),
|
||||||
|
run: e => e.chain().focus().toggleBulletList().run(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '1. List',
|
||||||
|
name: 'Numbered list',
|
||||||
|
isActive: e => e.isActive('orderedList'),
|
||||||
|
run: e => e.chain().focus().toggleOrderedList().run(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '❝',
|
||||||
|
name: 'Quote',
|
||||||
|
isActive: e => e.isActive('blockquote'),
|
||||||
|
run: e => e.chain().focus().toggleBlockquote().run(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '</>',
|
||||||
|
name: 'Code',
|
||||||
|
isActive: e => e.isActive('code'),
|
||||||
|
run: e => e.chain().focus().toggleCode().run(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Link',
|
||||||
|
name: 'Link',
|
||||||
|
isActive: e => e.isActive('link'),
|
||||||
|
run: e => {
|
||||||
|
const prev = (e.getAttributes('link').href as string) ?? '';
|
||||||
|
const url = typeof window !== 'undefined' ? window.prompt('Link URL', prev) : prev;
|
||||||
|
if (url === null) return;
|
||||||
|
if (url === '') {
|
||||||
|
e.chain().focus().extendMarkRange('link').unsetLink().run();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.chain().focus().extendMarkRange('link').setLink({ href: url }).run();
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
/** Token-themed formatting toolbar bound to a Tiptap editor instance. */
|
||||||
|
export function Toolbar({ editor }: ToolbarProps) {
|
||||||
|
// Re-render on selection/content changes so active states stay correct.
|
||||||
|
const [, force] = React.useReducer((x: number) => x + 1, 0);
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!editor) return;
|
||||||
|
editor.on('transaction', force);
|
||||||
|
return () => {
|
||||||
|
editor.off('transaction', force);
|
||||||
|
};
|
||||||
|
}, [editor]);
|
||||||
|
|
||||||
|
if (!editor) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
role="toolbar"
|
||||||
|
aria-label="Formatting"
|
||||||
|
className="flex flex-wrap items-center gap-1 border-b border-[var(--bl-border,rgba(0,0,0,0.12))] p-1.5"
|
||||||
|
>
|
||||||
|
{BUTTONS.map(b => {
|
||||||
|
const active = b.isActive?.(editor) ?? false;
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={b.name}
|
||||||
|
type="button"
|
||||||
|
aria-label={b.name}
|
||||||
|
aria-pressed={active}
|
||||||
|
onClick={() => b.run(editor)}
|
||||||
|
className={clsx(
|
||||||
|
'min-w-8 rounded-md px-2 py-1 text-sm font-medium',
|
||||||
|
active
|
||||||
|
? 'bg-[var(--bl-accent,#6366f1)] text-white'
|
||||||
|
: 'text-[var(--bl-text-secondary,#444)] hover:bg-[var(--bl-surface-hover,rgba(0,0,0,0.05))]'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{b.label}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
143
packages/rich-text/src/__tests__/rich-text.test.tsx
Normal file
143
packages/rich-text/src/__tests__/rich-text.test.tsx
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
||||||
|
import { cleanup, fireEvent, render, screen } from '@testing-library/react';
|
||||||
|
import * as React from 'react';
|
||||||
|
import { Editor } from '@tiptap/core';
|
||||||
|
import type { JSONContent } from '@tiptap/core';
|
||||||
|
import type { SuggestionProps } from '@tiptap/suggestion';
|
||||||
|
|
||||||
|
import { RichTextViewer } from '../RichTextViewer.js';
|
||||||
|
import { RichTextEditor } from '../RichTextEditor.js';
|
||||||
|
import { Toolbar } from '../Toolbar.js';
|
||||||
|
import { buildExtensions } from '../extensions.js';
|
||||||
|
import { defaultSlashItems, filterSlashItems, type SlashItem } from '../slashMenu.js';
|
||||||
|
import { filterUsers, type MentionUser } from '../mention.js';
|
||||||
|
import { SlashMenuList } from '../SlashMenuList.js';
|
||||||
|
import { MentionList } from '../MentionList.js';
|
||||||
|
|
||||||
|
beforeEach(() => cleanup());
|
||||||
|
|
||||||
|
/* ── 9.B.4 — slash filter (pure) ─────────────────────────────────────── */
|
||||||
|
describe('filterSlashItems', () => {
|
||||||
|
it('returns all items for an empty query', () => {
|
||||||
|
expect(filterSlashItems('')).toHaveLength(defaultSlashItems.length);
|
||||||
|
});
|
||||||
|
it('matches by title (case-insensitive)', () => {
|
||||||
|
const r = filterSlashItems('HEAD');
|
||||||
|
expect(r.length).toBeGreaterThan(0);
|
||||||
|
expect(r.every(i => /head/i.test(i.title))).toBe(true);
|
||||||
|
});
|
||||||
|
it('matches by alias', () => {
|
||||||
|
const r = filterSlashItems('ul');
|
||||||
|
expect(r.some(i => i.title === 'Bullet list')).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ── 9.B.5 — mention people search (pure) ────────────────────────────── */
|
||||||
|
describe('filterUsers', () => {
|
||||||
|
const people: MentionUser[] = [
|
||||||
|
{ id: '1', label: 'Ada Lovelace' },
|
||||||
|
{ id: '2', label: 'Alan Turing' },
|
||||||
|
{ id: '3', label: 'Grace Hopper' },
|
||||||
|
];
|
||||||
|
it('filters case-insensitively by label', () => {
|
||||||
|
expect(filterUsers('ada', people).map(u => u.id)).toEqual(['1']);
|
||||||
|
});
|
||||||
|
it('returns all (capped) for an empty query', () => {
|
||||||
|
expect(filterUsers('', people, 2)).toHaveLength(2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ── 9.B.2 — viewer renders HTML from JSON ───────────────────────────── */
|
||||||
|
describe('RichTextViewer', () => {
|
||||||
|
const doc: JSONContent = {
|
||||||
|
type: 'doc',
|
||||||
|
content: [
|
||||||
|
{ type: 'heading', attrs: { level: 1 }, content: [{ type: 'text', text: 'Title' }] },
|
||||||
|
{
|
||||||
|
type: 'paragraph',
|
||||||
|
content: [{ type: 'text', marks: [{ type: 'bold' }], text: 'bold' }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'bulletList',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
type: 'listItem',
|
||||||
|
content: [{ type: 'paragraph', content: [{ type: 'text', text: 'one' }] }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
it('serialises headings, marks and lists', () => {
|
||||||
|
const { container } = render(<RichTextViewer doc={doc} />);
|
||||||
|
expect(container.querySelector('h1')?.textContent).toBe('Title');
|
||||||
|
expect(container.querySelector('strong')?.textContent).toBe('bold');
|
||||||
|
expect(container.querySelector('ul li')?.textContent).toBe('one');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ── 9.B.3 — toolbar commands ────────────────────────────────────────── */
|
||||||
|
describe('Toolbar', () => {
|
||||||
|
it('toggles bold on the bound editor', () => {
|
||||||
|
const editor = new Editor({
|
||||||
|
element: document.createElement('div'),
|
||||||
|
extensions: buildExtensions(),
|
||||||
|
content: '<p>hello</p>',
|
||||||
|
});
|
||||||
|
editor.commands.selectAll();
|
||||||
|
render(<Toolbar editor={editor} />);
|
||||||
|
fireEvent.click(screen.getByLabelText('Bold'));
|
||||||
|
expect(editor.getHTML()).toContain('<strong>');
|
||||||
|
editor.destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders nothing without an editor', () => {
|
||||||
|
const { container } = render(<Toolbar editor={null} />);
|
||||||
|
expect(container.firstChild).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ── 9.B.2 — editor mounts (SSR-safe) ────────────────────────────────── */
|
||||||
|
describe('RichTextEditor', () => {
|
||||||
|
it('mounts a toolbar + editable textbox', async () => {
|
||||||
|
render(<RichTextEditor content="<p>hi</p>" />);
|
||||||
|
expect(await screen.findByRole('textbox')).toBeTruthy();
|
||||||
|
expect(screen.getByRole('toolbar', { name: 'Formatting' })).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/* ── 9.B.4 / 9.B.5 — suggestion list components ──────────────────────── */
|
||||||
|
function slashProps(
|
||||||
|
items: SlashItem[],
|
||||||
|
command: (i: SlashItem) => void
|
||||||
|
): SuggestionProps<SlashItem> {
|
||||||
|
return { items, command } as unknown as SuggestionProps<SlashItem>;
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('SlashMenuList', () => {
|
||||||
|
it('renders an option per item and invokes command on click', () => {
|
||||||
|
const command = vi.fn();
|
||||||
|
render(<SlashMenuList {...slashProps(defaultSlashItems, command)} />);
|
||||||
|
const options = screen.getAllByRole('option');
|
||||||
|
expect(options).toHaveLength(defaultSlashItems.length);
|
||||||
|
fireEvent.click(screen.getByText('Heading 1'));
|
||||||
|
expect(command).toHaveBeenCalledWith(defaultSlashItems[0]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows an empty state when there are no items', () => {
|
||||||
|
render(<SlashMenuList {...slashProps([], vi.fn())} />);
|
||||||
|
expect(screen.getByText('No matches')).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('MentionList', () => {
|
||||||
|
it('renders people and emits {id,label} on click', () => {
|
||||||
|
const command = vi.fn();
|
||||||
|
const people: MentionUser[] = [{ id: '7', label: 'Ada' }];
|
||||||
|
render(
|
||||||
|
<MentionList {...({ items: people, command } as unknown as SuggestionProps<MentionUser>)} />
|
||||||
|
);
|
||||||
|
fireEvent.click(screen.getByText('Ada'));
|
||||||
|
expect(command).toHaveBeenCalledWith({ id: '7', label: 'Ada' });
|
||||||
|
});
|
||||||
|
});
|
||||||
26
packages/rich-text/src/extensions.ts
Normal file
26
packages/rich-text/src/extensions.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import StarterKit from '@tiptap/starter-kit';
|
||||||
|
import Link from '@tiptap/extension-link';
|
||||||
|
import Placeholder from '@tiptap/extension-placeholder';
|
||||||
|
import type { AnyExtension } from '@tiptap/core';
|
||||||
|
|
||||||
|
export interface BuildExtensionsOptions {
|
||||||
|
/** Placeholder text shown when the doc is empty. */
|
||||||
|
placeholder?: string;
|
||||||
|
/** Extra extensions to append (e.g. a configured Mention or SlashCommands). */
|
||||||
|
extra?: AnyExtension[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The canonical extension set shared by `<RichTextEditor>` and
|
||||||
|
* `<RichTextViewer>` — keeping them in sync guarantees that serialised HTML
|
||||||
|
* matches what the editor produced.
|
||||||
|
*/
|
||||||
|
export function buildExtensions(options: BuildExtensionsOptions = {}): AnyExtension[] {
|
||||||
|
const { placeholder = 'Write something…', extra = [] } = options;
|
||||||
|
return [
|
||||||
|
StarterKit.configure({ link: false }),
|
||||||
|
Link.configure({ openOnClick: false, autolink: true }),
|
||||||
|
Placeholder.configure({ placeholder }),
|
||||||
|
...extra,
|
||||||
|
];
|
||||||
|
}
|
||||||
33
packages/rich-text/src/index.ts
Normal file
33
packages/rich-text/src/index.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
* @bytelyst/rich-text — Tiptap v3 editor + viewer for the ByteLyst ecosystem.
|
||||||
|
*
|
||||||
|
* Exports (0.1.0 — Wave 9.B):
|
||||||
|
* <RichTextEditor> toolbar + editing surface, slash menu, async mentions
|
||||||
|
* <RichTextViewer> SSR-safe read-only renderer (generateHTML)
|
||||||
|
* <Toolbar> standalone formatting toolbar bound to an Editor
|
||||||
|
* buildExtensions shared StarterKit + Link + Placeholder schema
|
||||||
|
* SlashCommands `/` command extension + defaultSlashItems / filterSlashItems
|
||||||
|
* createMention `@`-mention extension factory + filterUsers helper
|
||||||
|
*
|
||||||
|
* Built on Tiptap v3.23.x (current stable). SSR-safe for Next via
|
||||||
|
* `immediatelyRender: false`.
|
||||||
|
*/
|
||||||
|
export { RichTextEditor } from './RichTextEditor.js';
|
||||||
|
export type { RichTextEditorProps } from './RichTextEditor.js';
|
||||||
|
|
||||||
|
export { RichTextViewer } from './RichTextViewer.js';
|
||||||
|
export type { RichTextViewerProps } from './RichTextViewer.js';
|
||||||
|
|
||||||
|
export { Toolbar } from './Toolbar.js';
|
||||||
|
export type { ToolbarProps } from './Toolbar.js';
|
||||||
|
|
||||||
|
export { buildExtensions } from './extensions.js';
|
||||||
|
export type { BuildExtensionsOptions } from './extensions.js';
|
||||||
|
|
||||||
|
export { SlashCommands, defaultSlashItems, filterSlashItems } from './slashMenu.js';
|
||||||
|
export type { SlashItem } from './slashMenu.js';
|
||||||
|
|
||||||
|
export { createMention, filterUsers } from './mention.js';
|
||||||
|
export type { MentionUser, UserSearchFn } from './mention.js';
|
||||||
|
|
||||||
|
export type { JSONContent } from '@tiptap/core';
|
||||||
81
packages/rich-text/src/mention.ts
Normal file
81
packages/rich-text/src/mention.ts
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import Mention from '@tiptap/extension-mention';
|
||||||
|
import type { AnyExtension } from '@tiptap/core';
|
||||||
|
import type { SuggestionProps, SuggestionKeyDownProps } from '@tiptap/suggestion';
|
||||||
|
import { ReactRenderer } from '@tiptap/react';
|
||||||
|
|
||||||
|
import { MentionList } from './MentionList.js';
|
||||||
|
|
||||||
|
export interface MentionUser {
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Resolver that returns matching people for a query (sync or async). */
|
||||||
|
export type UserSearchFn = (query: string) => MentionUser[] | Promise<MentionUser[]>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pure, case-insensitive in-memory matcher — handy as a default `UserSearchFn`
|
||||||
|
* and directly unit-testable. Caps results at `limit`.
|
||||||
|
*/
|
||||||
|
export function filterUsers(query: string, users: MentionUser[], limit = 5): MentionUser[] {
|
||||||
|
const q = query.trim().toLowerCase();
|
||||||
|
const matches = q ? users.filter(u => u.label.toLowerCase().includes(q)) : users;
|
||||||
|
return matches.slice(0, limit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build a configured `@`-mention extension backed by an async people search.
|
||||||
|
* Renders a keyboard-navigable popup at the caret.
|
||||||
|
*/
|
||||||
|
export function createMention(search: UserSearchFn): AnyExtension {
|
||||||
|
return Mention.configure({
|
||||||
|
HTMLAttributes: { class: 'bl-mention' },
|
||||||
|
suggestion: {
|
||||||
|
char: '@',
|
||||||
|
items: async ({ query }) => await search(query),
|
||||||
|
render: () => {
|
||||||
|
let component: ReactRenderer<{ onKeyDown: (p: SuggestionKeyDownProps) => boolean }> | null =
|
||||||
|
null;
|
||||||
|
let popup: HTMLDivElement | null = null;
|
||||||
|
|
||||||
|
const position = (props: SuggestionProps<MentionUser>) => {
|
||||||
|
if (!popup) return;
|
||||||
|
const rect = props.clientRect?.();
|
||||||
|
if (!rect) return;
|
||||||
|
popup.style.left = `${rect.left}px`;
|
||||||
|
popup.style.top = `${rect.bottom + 4}px`;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
onStart: (props: SuggestionProps<MentionUser>) => {
|
||||||
|
component = new ReactRenderer(MentionList, { props, editor: props.editor });
|
||||||
|
popup = document.createElement('div');
|
||||||
|
popup.setAttribute('data-mention-menu', 'true');
|
||||||
|
popup.style.position = 'absolute';
|
||||||
|
popup.style.zIndex = '50';
|
||||||
|
popup.appendChild(component.element);
|
||||||
|
document.body.appendChild(popup);
|
||||||
|
position(props);
|
||||||
|
},
|
||||||
|
onUpdate: (props: SuggestionProps<MentionUser>) => {
|
||||||
|
component?.updateProps(props);
|
||||||
|
position(props);
|
||||||
|
},
|
||||||
|
onKeyDown: (props: SuggestionKeyDownProps) => {
|
||||||
|
if (props.event.key === 'Escape') {
|
||||||
|
popup?.remove();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return component?.ref?.onKeyDown(props) ?? false;
|
||||||
|
},
|
||||||
|
onExit: () => {
|
||||||
|
popup?.remove();
|
||||||
|
popup = null;
|
||||||
|
component?.destroy();
|
||||||
|
component = null;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
138
packages/rich-text/src/slashMenu.ts
Normal file
138
packages/rich-text/src/slashMenu.ts
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
import { Extension } from '@tiptap/core';
|
||||||
|
import type { Editor, Range } from '@tiptap/core';
|
||||||
|
import Suggestion, { type SuggestionProps, type SuggestionKeyDownProps } from '@tiptap/suggestion';
|
||||||
|
import { ReactRenderer } from '@tiptap/react';
|
||||||
|
|
||||||
|
import { SlashMenuList } from './SlashMenuList.js';
|
||||||
|
|
||||||
|
export interface SlashItem {
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
aliases?: string[];
|
||||||
|
command: (props: { editor: Editor; range: Range }) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The built-in block actions offered by the slash menu. */
|
||||||
|
export const defaultSlashItems: SlashItem[] = [
|
||||||
|
{
|
||||||
|
title: 'Heading 1',
|
||||||
|
description: 'Big section heading',
|
||||||
|
aliases: ['h1', 'title'],
|
||||||
|
command: ({ editor, range }) =>
|
||||||
|
editor.chain().focus().deleteRange(range).setNode('heading', { level: 1 }).run(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Heading 2',
|
||||||
|
description: 'Medium section heading',
|
||||||
|
aliases: ['h2', 'subtitle'],
|
||||||
|
command: ({ editor, range }) =>
|
||||||
|
editor.chain().focus().deleteRange(range).setNode('heading', { level: 2 }).run(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Bullet list',
|
||||||
|
description: 'Unordered list',
|
||||||
|
aliases: ['ul', 'unordered'],
|
||||||
|
command: ({ editor, range }) =>
|
||||||
|
editor.chain().focus().deleteRange(range).toggleBulletList().run(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Numbered list',
|
||||||
|
description: 'Ordered list',
|
||||||
|
aliases: ['ol', 'ordered'],
|
||||||
|
command: ({ editor, range }) =>
|
||||||
|
editor.chain().focus().deleteRange(range).toggleOrderedList().run(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Quote',
|
||||||
|
description: 'Blockquote',
|
||||||
|
aliases: ['blockquote'],
|
||||||
|
command: ({ editor, range }) =>
|
||||||
|
editor.chain().focus().deleteRange(range).toggleBlockquote().run(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Code block',
|
||||||
|
description: 'Monospaced code',
|
||||||
|
aliases: ['code', 'pre'],
|
||||||
|
command: ({ editor, range }) =>
|
||||||
|
editor.chain().focus().deleteRange(range).toggleCodeBlock().run(),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
/** Pure, case-insensitive filter over title + aliases — unit-testable. */
|
||||||
|
export function filterSlashItems(
|
||||||
|
query: string,
|
||||||
|
items: SlashItem[] = defaultSlashItems
|
||||||
|
): SlashItem[] {
|
||||||
|
const q = query.trim().toLowerCase();
|
||||||
|
if (!q) return items;
|
||||||
|
return items.filter(
|
||||||
|
item =>
|
||||||
|
item.title.toLowerCase().includes(q) ||
|
||||||
|
(item.aliases ?? []).some(a => a.toLowerCase().includes(q))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `/`-triggered command menu. Built on `@tiptap/suggestion`; the popup is a
|
||||||
|
* React component positioned at the caret. Only mounts while the user is
|
||||||
|
* typing a slash command, so it never appears on first render.
|
||||||
|
*/
|
||||||
|
export const SlashCommands = Extension.create({
|
||||||
|
name: 'slashCommands',
|
||||||
|
|
||||||
|
addProseMirrorPlugins() {
|
||||||
|
return [
|
||||||
|
Suggestion<SlashItem>({
|
||||||
|
editor: this.editor,
|
||||||
|
char: '/',
|
||||||
|
startOfLine: false,
|
||||||
|
items: ({ query }) => filterSlashItems(query),
|
||||||
|
command: ({ editor, range, props }) => props.command({ editor, range }),
|
||||||
|
render: () => {
|
||||||
|
let component: ReactRenderer<{
|
||||||
|
onKeyDown: (p: SuggestionKeyDownProps) => boolean;
|
||||||
|
}> | null = null;
|
||||||
|
let popup: HTMLDivElement | null = null;
|
||||||
|
|
||||||
|
const position = (props: SuggestionProps<SlashItem>) => {
|
||||||
|
if (!popup) return;
|
||||||
|
const rect = props.clientRect?.();
|
||||||
|
if (!rect) return;
|
||||||
|
popup.style.left = `${rect.left}px`;
|
||||||
|
popup.style.top = `${rect.bottom + 4}px`;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
onStart: (props: SuggestionProps<SlashItem>) => {
|
||||||
|
component = new ReactRenderer(SlashMenuList, { props, editor: props.editor });
|
||||||
|
popup = document.createElement('div');
|
||||||
|
popup.setAttribute('data-slash-menu', 'true');
|
||||||
|
popup.style.position = 'absolute';
|
||||||
|
popup.style.zIndex = '50';
|
||||||
|
popup.appendChild(component.element);
|
||||||
|
document.body.appendChild(popup);
|
||||||
|
position(props);
|
||||||
|
},
|
||||||
|
onUpdate: (props: SuggestionProps<SlashItem>) => {
|
||||||
|
component?.updateProps(props);
|
||||||
|
position(props);
|
||||||
|
},
|
||||||
|
onKeyDown: (props: SuggestionKeyDownProps) => {
|
||||||
|
if (props.event.key === 'Escape') {
|
||||||
|
popup?.remove();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return component?.ref?.onKeyDown(props) ?? false;
|
||||||
|
},
|
||||||
|
onExit: () => {
|
||||||
|
popup?.remove();
|
||||||
|
popup = null;
|
||||||
|
component?.destroy();
|
||||||
|
component = null;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
},
|
||||||
|
});
|
||||||
11
packages/rich-text/tsconfig.json
Normal file
11
packages/rich-text/tsconfig.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"extends": "../../tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "dist",
|
||||||
|
"rootDir": "src",
|
||||||
|
"lib": ["ES2022", "DOM"],
|
||||||
|
"jsx": "react-jsx"
|
||||||
|
},
|
||||||
|
"include": ["src"],
|
||||||
|
"exclude": ["src/**/*.test.ts", "src/**/*.test.tsx"]
|
||||||
|
}
|
||||||
2
packages/rich-text/vitest.config.ts
Normal file
2
packages/rich-text/vitest.config.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
import { defineConfig } from 'vitest/config';
|
||||||
|
export default defineConfig({ test: { environment: 'happy-dom', pool: 'forks' } });
|
||||||
706
pnpm-lock.yaml
generated
706
pnpm-lock.yaml
generated
@ -1106,6 +1106,64 @@ importers:
|
|||||||
specifier: ^5.7.3
|
specifier: ^5.7.3
|
||||||
version: 5.9.3
|
version: 5.9.3
|
||||||
|
|
||||||
|
packages/rich-text:
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core':
|
||||||
|
specifier: ^3.23.6
|
||||||
|
version: 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
'@tiptap/extension-link':
|
||||||
|
specifier: ^3.23.6
|
||||||
|
version: 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||||
|
'@tiptap/extension-mention':
|
||||||
|
specifier: ^3.23.6
|
||||||
|
version: 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)(@tiptap/suggestion@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))
|
||||||
|
'@tiptap/extension-placeholder':
|
||||||
|
specifier: ^3.23.6
|
||||||
|
version: 3.23.6(@tiptap/extensions@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))
|
||||||
|
'@tiptap/html':
|
||||||
|
specifier: ^3.23.6
|
||||||
|
version: 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)(happy-dom@18.0.1)
|
||||||
|
'@tiptap/pm':
|
||||||
|
specifier: ^3.23.6
|
||||||
|
version: 3.23.6
|
||||||
|
'@tiptap/react':
|
||||||
|
specifier: ^3.23.6
|
||||||
|
version: 3.23.6(@floating-ui/dom@1.7.5)(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||||
|
'@tiptap/starter-kit':
|
||||||
|
specifier: ^3.23.6
|
||||||
|
version: 3.23.6
|
||||||
|
'@tiptap/suggestion':
|
||||||
|
specifier: ^3.23.6
|
||||||
|
version: 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||||
|
clsx:
|
||||||
|
specifier: ^2.1.0
|
||||||
|
version: 2.1.1
|
||||||
|
devDependencies:
|
||||||
|
'@testing-library/react':
|
||||||
|
specifier: ^16.3.2
|
||||||
|
version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||||
|
'@types/react':
|
||||||
|
specifier: ^19.2.14
|
||||||
|
version: 19.2.14
|
||||||
|
'@types/react-dom':
|
||||||
|
specifier: ^19.2.3
|
||||||
|
version: 19.2.3(@types/react@19.2.14)
|
||||||
|
happy-dom:
|
||||||
|
specifier: ^18.0.1
|
||||||
|
version: 18.0.1
|
||||||
|
react:
|
||||||
|
specifier: ^19.2.4
|
||||||
|
version: 19.2.4
|
||||||
|
react-dom:
|
||||||
|
specifier: ^19.2.4
|
||||||
|
version: 19.2.4(react@19.2.4)
|
||||||
|
typescript:
|
||||||
|
specifier: ^5.7.3
|
||||||
|
version: 5.9.3
|
||||||
|
vitest:
|
||||||
|
specifier: ^4.0.18
|
||||||
|
version: 4.0.18(@opentelemetry/api@1.9.0)(@types/node@22.19.11)(happy-dom@18.0.1)(jiti@2.6.1)(jsdom@28.0.0(@noble/hashes@1.8.0))(lightningcss@1.31.1)(msw@2.12.10(@types/node@22.19.11)(typescript@5.9.3))(terser@5.46.0)(tsx@4.21.0)(yaml@2.8.2)
|
||||||
|
|
||||||
packages/secure-storage-web:
|
packages/secure-storage-web:
|
||||||
devDependencies:
|
devDependencies:
|
||||||
fake-indexeddb:
|
fake-indexeddb:
|
||||||
@ -6609,6 +6667,276 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@testing-library/dom': '>=7.21.4'
|
'@testing-library/dom': '>=7.21.4'
|
||||||
|
|
||||||
|
'@tiptap/core@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-MRB3pHz4Oxqmcawh0cQ5iOGdY5xtNYp/1CoK7hdTLzw5K0C6/gTC2VvanB1R4INaB6EpBkxG/GiWkVirDRnuXw==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-blockquote@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-2RmnqNqTltZ2k1F7IfjoDNs935Uq4rRDR7d98mqkg3OlDktcQIyBpv0t9dTay6H5bkQeZUuS8ogK2S1E8Edjug==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-bold@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-1LMhjnytdbbhWHSoOwnLxZAOQZWPkKyXVCNmaIk0Mhi4tLPUXptG4qKS5sVYTCveE5H6IBPFrbgBFi5dMI6krA==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-bubble-menu@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-Mwkyp9LkDHFbqmWRIkp63FinRxFu3ajC4qSb9t4mnHsb4kAdbNLLsGtbFg+le0SWk4CxGwAOwM7SzeJ+6UGqCA==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-bullet-list@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-RMRgfXZykr/13X8UBOwvpgysVOo9KchwqMoEbvqQSj4YFfU56iIn59C8sbxiQ1sKfeltUf0wH4fPc0I4iwKqAA==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/extension-list': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-code-block@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-4kccgcn5yHThxrzsIhJny3EwfEZYIk+BjUCL4uIuzOyWvExtGhZ6JMHVCZeMhI8D1/bX1LNkkAKN5DXPzH4lXQ==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-code@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-KG8KXFYyLrtYvT7AZ1WGV61ofx8pDe5g9pH658MERxqQGii+Pyfc6xkz04l7XeBts/7+571UQp/0O7i/z560TA==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-document@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-XDAIgG9KcKumFM9KJWUEUhXPbFIhhl47bfy5GknareWTRKke85rcoj/oxKKO9ihLZr8JfpbXjqnS4SCm5yhYPw==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-dropcursor@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-+XWEoRKf3lXxi7Le1aOM2xU1XHwxICGpXjT3m4QaYqUgIpsq8gQEuso6kVg8DnTD7biKQs6+oIQ0o2b/gTW9WA==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/extensions': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-floating-menu@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-2kjuDcEq69lEcECl75xqY5MyzUSh2zcC5aLrpwP1WwhJz5bxsIFHiaps5AP6h9R4A+ZBj5b2haay2Y1wDUU3VA==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@floating-ui/dom': ^1.0.0
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-gapcursor@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-wbKmxXsszxWacEkrHucRpSQbiKjz4fmOebD6OVyL9AcrmlbxNk8vcM3iyh/8cVeRy09XY+morM165t/u7/z4IQ==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/extensions': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-hard-break@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-KeUm+tkUfIVSX9QM9XOIhaay0Fn36sLKUo5NVYjN3uJaxFvaZXZmTlxdO85OTdgF2P5sqh9LomrIgliaFRGk4w==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-heading@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-A/0jPhxnUh9THSZymlu0OGPZe1wdFdwHAXnRCmqvYUCwJjrG7LCC/ahzmcj1tcNzI9hgHyuYPSfev8RXYrNu/w==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-horizontal-rule@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-hEUlz4H+I64r+TH6LCuNCRgO7JTHncXGmx9+WbU69EOfY8O0ZurcgeJc8HeiAKL+r9YuC1e5YHfFxgCaaC0jlg==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-italic@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-wol5KdwCPAvpiYhH9PLlvO8ZnJHwZtIboVevrfOGgBcKlXRA3dedR4OAMXHnUtkkzu9KtliLg1+TYzEx4JZG9Q==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-link@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-KNZz7z7P2/qbQsx5bPAbSPjrKDg1VHsedGlLHJCr8U2VRD5VgmDLkMpkouP1CsDg15qgyUKv/nDib5KgPpLNWA==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-list-item@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-3zzyhdkUWcHVpXuvy6KiIwjh29rbH6gEDEqPQqHLrl1XGnO9pnShC7pSHctlCDjmcx3O4n9cd4QMtVBlUerbiA==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/extension-list': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-list-keymap@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-x8bPcLViGzg/RAmQM/XtmfqIwQ/Pv9Q8mkd+OgfUiTqjeJqKwVQmiqbLFNa7zw81+H61M+HDU+qGAaQ3vRIMjw==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/extension-list': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-list@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-z6vj9+Qht2sjdQkyyHcUpsC/yCIZqTrQiyHDhs/HGKrfvoANyAZGpqdNeKf1wSyjIso+27tQuIH5NDfk8ygyNw==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-mention@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-rSjeAAtuMwMA1lj4nbxz3rbmM06yPFUc8TFzhrEpmA4/l5XNWOk/PQef6uiGN+Isv2Z2PrIhr8XrR7Me8OSCiA==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
'@tiptap/suggestion': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-ordered-list@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-1m/wWB/ZtXcmG2vNdiUkCqsOgqv5vBjCv/mVaHhF9OvV+zQS8YDjoWE7zEuT/GgELdT77Xq8lHrn4nCDudB3/A==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/extension-list': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-paragraph@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-+7m58LUSncodjrIyXks4RZ3tLNYrvgT77wRR4l3HnM5OABY3GDsDTqi7c1t1yI29NVOSk/DUacqy6UwYAj1DGg==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-placeholder@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-8I6b2aevF74aLgymKMxbDxSLxWA2y+2dh0zZDeI8sRZ2m6WHHes+Kyuuwkq1HIPcR+ZLpbec74cmf6lcL/yvqQ==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/extensions': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-strike@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-oF7FEZ37f15aCe5kPgzGDYf/m+hr7VdQ/Ko/Hds/UM9pX7AG1fdtmRrl6wqkRqDM/incZaC/AQR2/Dpo2VCNGQ==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-text@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-ipoC2TkIAIOTiF5ByiGgvQB1DqDyfP90wrUB3mohBcgvp7lQnwHszCDGv8dNnmcUek8uXV/uoLu2VXeVQlxjPA==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-underline@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-P55wGIZGYTVH92Fq0cgI4/O9AhLCaJC3hhxg15RSERP5/YegM9eJHDK/GQ1EE/DvYA+xpYGOV6agKwAUqfA/Iw==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extensions@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-X09/Db1teB+ifXzDGVVFmOeQRx7wTAayE9/280spxpsHkHZvJ5bHRvWIzUzviMIjbBz+NPDIKYPK7gMfh9iaig==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/html@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-cfQ8ijvkhkbt02x0tjtcahubWCqxkO7IJow0j2MgS6FHdXKv2QUrIvcpAqIqdv0lA4ozWmdmUpLFv+lA95kcPg==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
happy-dom: ^20.8.9
|
||||||
|
|
||||||
|
'@tiptap/pm@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-in5CaMaWlJcH2A1q6GJKFtrodE8WLS3M9tIi/f89jPmIVHJShpodC0KZDNyJkrVBQomYk0DEh86Utm6ASXzQww==,
|
||||||
|
}
|
||||||
|
|
||||||
|
'@tiptap/react@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-Tw9KZkYqFMk3vaJAEQKqEYIO/iq3cSJe7OUEGBul4k4GaMQeLItLf5EYhUd0GIPXci1WVVPNntKJsHfX25M37w==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
'@types/react': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
'@types/react-dom': ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
|
||||||
|
'@tiptap/starter-kit@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-gykwtGWrnWCmtql1hid3opac/KV8zQvOAnu3bTqIqcHrn1FusbUwKmNzavSbfGvcktHM3hFjb35W48JyVLyu/A==,
|
||||||
|
}
|
||||||
|
|
||||||
|
'@tiptap/suggestion@3.23.6':
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-YAoI2jctPClcyUhIcpxb1QlrUFG2a1Xsv1gS4tIfgh5KoOuEfGfCoeCq89TKgz/rHeP+ktRhzg1E2E4EY68HEA==,
|
||||||
|
}
|
||||||
|
peerDependencies:
|
||||||
|
'@tiptap/core': 3.23.6
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
|
||||||
'@ts-morph/common@0.27.0':
|
'@ts-morph/common@0.27.0':
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@ -9739,6 +10067,13 @@ packages:
|
|||||||
integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==,
|
integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fast-equals@5.4.0:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw==,
|
||||||
|
}
|
||||||
|
engines: { node: '>=6.0.0' }
|
||||||
|
|
||||||
fast-glob@3.3.1:
|
fast-glob@3.3.1:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@ -11624,6 +11959,12 @@ packages:
|
|||||||
integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==,
|
integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
linkifyjs@4.3.3:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-P8aEP5U/D1/IlTY2OeYsErdwh9bGuLE30NcXtKEjgdHcahveQoQwM2yZNsioQHsWFz0P7KKudisbrzCgR0sDHg==,
|
||||||
|
}
|
||||||
|
|
||||||
lint-staged@15.5.2:
|
lint-staged@15.5.2:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@ -12991,6 +13332,12 @@ packages:
|
|||||||
}
|
}
|
||||||
engines: { node: '>=18' }
|
engines: { node: '>=18' }
|
||||||
|
|
||||||
|
orderedmap@2.1.1:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g==,
|
||||||
|
}
|
||||||
|
|
||||||
outdent@0.5.0:
|
outdent@0.5.0:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@ -13533,6 +13880,78 @@ packages:
|
|||||||
integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==,
|
integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
prosemirror-changeset@2.4.1:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-96WBLhOaYhJ+kPhLg3uW359Tz6I/MfcrQfL4EGv4SrcqKEMC1gmoGrXHecPE8eOwTVCJ4IwgfzM8fFad25wNfw==,
|
||||||
|
}
|
||||||
|
|
||||||
|
prosemirror-commands@1.7.1:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w==,
|
||||||
|
}
|
||||||
|
|
||||||
|
prosemirror-dropcursor@1.8.2:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw==,
|
||||||
|
}
|
||||||
|
|
||||||
|
prosemirror-gapcursor@1.4.1:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-pMdYaEnjNMSwl11yjEGtgTmLkR08m/Vl+Jj443167p9eB3HVQKhYCc4gmHVDsLPODfZfjr/MmirsdyZziXbQKw==,
|
||||||
|
}
|
||||||
|
|
||||||
|
prosemirror-history@1.5.0:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg==,
|
||||||
|
}
|
||||||
|
|
||||||
|
prosemirror-keymap@1.2.3:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw==,
|
||||||
|
}
|
||||||
|
|
||||||
|
prosemirror-model@1.25.7:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-A79aN8QEFUwI6cax8Yq4Rpcx1TJZ3Kagn+ii7qLo4/V8H3mMiHrhFyhTyHHvpSnOgMPpWiDGSwM3etwrxE50ug==,
|
||||||
|
}
|
||||||
|
|
||||||
|
prosemirror-schema-list@1.5.1:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q==,
|
||||||
|
}
|
||||||
|
|
||||||
|
prosemirror-state@1.4.4:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw==,
|
||||||
|
}
|
||||||
|
|
||||||
|
prosemirror-tables@1.8.5:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw==,
|
||||||
|
}
|
||||||
|
|
||||||
|
prosemirror-transform@1.12.0:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-GxboyN4AMIsoHNtz5uf2r2Ru551i5hWeCMD6E2Ib4Eogqoub0NflniaBPVQ4MrGE5yZ8JV9tUHg9qcZTTrcN4w==,
|
||||||
|
}
|
||||||
|
|
||||||
|
prosemirror-view@1.41.8:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-TnKDdohEatgyZNGCDWIdccOHXhYloJwbwU+phw/a23KBvJIR9lWQWW7WHHK3vBdOLDNuF7TaX98GObUZOWkOnA==,
|
||||||
|
}
|
||||||
|
|
||||||
protobufjs@7.5.4:
|
protobufjs@7.5.4:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@ -14067,6 +14486,12 @@ packages:
|
|||||||
engines: { node: '>=18.0.0', npm: '>=8.0.0' }
|
engines: { node: '>=18.0.0', npm: '>=8.0.0' }
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
rope-sequence@1.3.4:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ==,
|
||||||
|
}
|
||||||
|
|
||||||
router@2.2.0:
|
router@2.2.0:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@ -15676,6 +16101,12 @@ packages:
|
|||||||
integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==,
|
integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
w3c-keyname@2.2.8:
|
||||||
|
resolution:
|
||||||
|
{
|
||||||
|
integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==,
|
||||||
|
}
|
||||||
|
|
||||||
w3c-xmlserializer@5.0.0:
|
w3c-xmlserializer@5.0.0:
|
||||||
resolution:
|
resolution:
|
||||||
{
|
{
|
||||||
@ -20185,6 +20616,198 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
'@testing-library/dom': 10.4.0
|
'@testing-library/dom': 10.4.0
|
||||||
|
|
||||||
|
'@tiptap/core@3.23.6(@tiptap/pm@3.23.6)':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-blockquote@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
|
||||||
|
'@tiptap/extension-bold@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
|
||||||
|
'@tiptap/extension-bubble-menu@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)':
|
||||||
|
dependencies:
|
||||||
|
'@floating-ui/dom': 1.7.5
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tiptap/extension-bullet-list@3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/extension-list': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||||
|
|
||||||
|
'@tiptap/extension-code-block@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-code@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
|
||||||
|
'@tiptap/extension-document@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
|
||||||
|
'@tiptap/extension-dropcursor@3.23.6(@tiptap/extensions@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/extensions': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||||
|
|
||||||
|
'@tiptap/extension-floating-menu@3.23.6(@floating-ui/dom@1.7.5)(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)':
|
||||||
|
dependencies:
|
||||||
|
'@floating-ui/dom': 1.7.5
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@tiptap/extension-gapcursor@3.23.6(@tiptap/extensions@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/extensions': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||||
|
|
||||||
|
'@tiptap/extension-hard-break@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
|
||||||
|
'@tiptap/extension-heading@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
|
||||||
|
'@tiptap/extension-horizontal-rule@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-italic@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
|
||||||
|
'@tiptap/extension-link@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
linkifyjs: 4.3.3
|
||||||
|
|
||||||
|
'@tiptap/extension-list-item@3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/extension-list': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||||
|
|
||||||
|
'@tiptap/extension-list-keymap@3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/extension-list': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||||
|
|
||||||
|
'@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/extension-mention@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)(@tiptap/suggestion@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
'@tiptap/suggestion': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||||
|
|
||||||
|
'@tiptap/extension-ordered-list@3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/extension-list': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||||
|
|
||||||
|
'@tiptap/extension-paragraph@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
|
||||||
|
'@tiptap/extension-placeholder@3.23.6(@tiptap/extensions@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/extensions': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||||
|
|
||||||
|
'@tiptap/extension-strike@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
|
||||||
|
'@tiptap/extension-text@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
|
||||||
|
'@tiptap/extension-underline@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
|
||||||
|
'@tiptap/extensions@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/html@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)(happy-dom@18.0.1)':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
happy-dom: 18.0.1
|
||||||
|
|
||||||
|
'@tiptap/pm@3.23.6':
|
||||||
|
dependencies:
|
||||||
|
prosemirror-changeset: 2.4.1
|
||||||
|
prosemirror-commands: 1.7.1
|
||||||
|
prosemirror-dropcursor: 1.8.2
|
||||||
|
prosemirror-gapcursor: 1.4.1
|
||||||
|
prosemirror-history: 1.5.0
|
||||||
|
prosemirror-keymap: 1.2.3
|
||||||
|
prosemirror-model: 1.25.7
|
||||||
|
prosemirror-schema-list: 1.5.1
|
||||||
|
prosemirror-state: 1.4.4
|
||||||
|
prosemirror-tables: 1.8.5
|
||||||
|
prosemirror-transform: 1.12.0
|
||||||
|
prosemirror-view: 1.41.8
|
||||||
|
|
||||||
|
'@tiptap/react@3.23.6(@floating-ui/dom@1.7.5)(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
'@types/react': 19.2.14
|
||||||
|
'@types/react-dom': 19.2.3(@types/react@19.2.14)
|
||||||
|
'@types/use-sync-external-store': 0.0.6
|
||||||
|
fast-equals: 5.4.0
|
||||||
|
react: 19.2.4
|
||||||
|
react-dom: 19.2.4(react@19.2.4)
|
||||||
|
use-sync-external-store: 1.6.0(react@19.2.4)
|
||||||
|
optionalDependencies:
|
||||||
|
'@tiptap/extension-bubble-menu': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||||
|
'@tiptap/extension-floating-menu': 3.23.6(@floating-ui/dom@1.7.5)(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- '@floating-ui/dom'
|
||||||
|
|
||||||
|
'@tiptap/starter-kit@3.23.6':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
'@tiptap/extension-blockquote': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||||
|
'@tiptap/extension-bold': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||||
|
'@tiptap/extension-bullet-list': 3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))
|
||||||
|
'@tiptap/extension-code': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||||
|
'@tiptap/extension-code-block': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||||
|
'@tiptap/extension-document': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||||
|
'@tiptap/extension-dropcursor': 3.23.6(@tiptap/extensions@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))
|
||||||
|
'@tiptap/extension-gapcursor': 3.23.6(@tiptap/extensions@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))
|
||||||
|
'@tiptap/extension-hard-break': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||||
|
'@tiptap/extension-heading': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||||
|
'@tiptap/extension-horizontal-rule': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||||
|
'@tiptap/extension-italic': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||||
|
'@tiptap/extension-link': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||||
|
'@tiptap/extension-list': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||||
|
'@tiptap/extension-list-item': 3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))
|
||||||
|
'@tiptap/extension-list-keymap': 3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))
|
||||||
|
'@tiptap/extension-ordered-list': 3.23.6(@tiptap/extension-list@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6))
|
||||||
|
'@tiptap/extension-paragraph': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||||
|
'@tiptap/extension-strike': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||||
|
'@tiptap/extension-text': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||||
|
'@tiptap/extension-underline': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))
|
||||||
|
'@tiptap/extensions': 3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
|
||||||
|
'@tiptap/suggestion@3.23.6(@tiptap/core@3.23.6(@tiptap/pm@3.23.6))(@tiptap/pm@3.23.6)':
|
||||||
|
dependencies:
|
||||||
|
'@tiptap/core': 3.23.6(@tiptap/pm@3.23.6)
|
||||||
|
'@tiptap/pm': 3.23.6
|
||||||
|
|
||||||
'@ts-morph/common@0.27.0':
|
'@ts-morph/common@0.27.0':
|
||||||
dependencies:
|
dependencies:
|
||||||
fast-glob: 3.3.3
|
fast-glob: 3.3.3
|
||||||
@ -22458,6 +23081,8 @@ snapshots:
|
|||||||
|
|
||||||
fast-deep-equal@3.1.3: {}
|
fast-deep-equal@3.1.3: {}
|
||||||
|
|
||||||
|
fast-equals@5.4.0: {}
|
||||||
|
|
||||||
fast-glob@3.3.1:
|
fast-glob@3.3.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@nodelib/fs.stat': 2.0.5
|
'@nodelib/fs.stat': 2.0.5
|
||||||
@ -23576,6 +24201,8 @@ snapshots:
|
|||||||
|
|
||||||
lines-and-columns@1.2.4: {}
|
lines-and-columns@1.2.4: {}
|
||||||
|
|
||||||
|
linkifyjs@4.3.3: {}
|
||||||
|
|
||||||
lint-staged@15.5.2:
|
lint-staged@15.5.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
chalk: 5.6.2
|
chalk: 5.6.2
|
||||||
@ -24801,6 +25428,8 @@ snapshots:
|
|||||||
string-width: 7.2.0
|
string-width: 7.2.0
|
||||||
strip-ansi: 7.1.2
|
strip-ansi: 7.1.2
|
||||||
|
|
||||||
|
orderedmap@2.1.1: {}
|
||||||
|
|
||||||
outdent@0.5.0: {}
|
outdent@0.5.0: {}
|
||||||
|
|
||||||
outvariant@1.4.3: {}
|
outvariant@1.4.3: {}
|
||||||
@ -25101,6 +25730,75 @@ snapshots:
|
|||||||
|
|
||||||
property-information@7.1.0: {}
|
property-information@7.1.0: {}
|
||||||
|
|
||||||
|
prosemirror-changeset@2.4.1:
|
||||||
|
dependencies:
|
||||||
|
prosemirror-transform: 1.12.0
|
||||||
|
|
||||||
|
prosemirror-commands@1.7.1:
|
||||||
|
dependencies:
|
||||||
|
prosemirror-model: 1.25.7
|
||||||
|
prosemirror-state: 1.4.4
|
||||||
|
prosemirror-transform: 1.12.0
|
||||||
|
|
||||||
|
prosemirror-dropcursor@1.8.2:
|
||||||
|
dependencies:
|
||||||
|
prosemirror-state: 1.4.4
|
||||||
|
prosemirror-transform: 1.12.0
|
||||||
|
prosemirror-view: 1.41.8
|
||||||
|
|
||||||
|
prosemirror-gapcursor@1.4.1:
|
||||||
|
dependencies:
|
||||||
|
prosemirror-keymap: 1.2.3
|
||||||
|
prosemirror-model: 1.25.7
|
||||||
|
prosemirror-state: 1.4.4
|
||||||
|
prosemirror-view: 1.41.8
|
||||||
|
|
||||||
|
prosemirror-history@1.5.0:
|
||||||
|
dependencies:
|
||||||
|
prosemirror-state: 1.4.4
|
||||||
|
prosemirror-transform: 1.12.0
|
||||||
|
prosemirror-view: 1.41.8
|
||||||
|
rope-sequence: 1.3.4
|
||||||
|
|
||||||
|
prosemirror-keymap@1.2.3:
|
||||||
|
dependencies:
|
||||||
|
prosemirror-state: 1.4.4
|
||||||
|
w3c-keyname: 2.2.8
|
||||||
|
|
||||||
|
prosemirror-model@1.25.7:
|
||||||
|
dependencies:
|
||||||
|
orderedmap: 2.1.1
|
||||||
|
|
||||||
|
prosemirror-schema-list@1.5.1:
|
||||||
|
dependencies:
|
||||||
|
prosemirror-model: 1.25.7
|
||||||
|
prosemirror-state: 1.4.4
|
||||||
|
prosemirror-transform: 1.12.0
|
||||||
|
|
||||||
|
prosemirror-state@1.4.4:
|
||||||
|
dependencies:
|
||||||
|
prosemirror-model: 1.25.7
|
||||||
|
prosemirror-transform: 1.12.0
|
||||||
|
prosemirror-view: 1.41.8
|
||||||
|
|
||||||
|
prosemirror-tables@1.8.5:
|
||||||
|
dependencies:
|
||||||
|
prosemirror-keymap: 1.2.3
|
||||||
|
prosemirror-model: 1.25.7
|
||||||
|
prosemirror-state: 1.4.4
|
||||||
|
prosemirror-transform: 1.12.0
|
||||||
|
prosemirror-view: 1.41.8
|
||||||
|
|
||||||
|
prosemirror-transform@1.12.0:
|
||||||
|
dependencies:
|
||||||
|
prosemirror-model: 1.25.7
|
||||||
|
|
||||||
|
prosemirror-view@1.41.8:
|
||||||
|
dependencies:
|
||||||
|
prosemirror-model: 1.25.7
|
||||||
|
prosemirror-state: 1.4.4
|
||||||
|
prosemirror-transform: 1.12.0
|
||||||
|
|
||||||
protobufjs@7.5.4:
|
protobufjs@7.5.4:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@protobufjs/aspromise': 1.1.2
|
'@protobufjs/aspromise': 1.1.2
|
||||||
@ -25637,6 +26335,8 @@ snapshots:
|
|||||||
'@rollup/rollup-win32-x64-msvc': 4.57.1
|
'@rollup/rollup-win32-x64-msvc': 4.57.1
|
||||||
fsevents: 2.3.3
|
fsevents: 2.3.3
|
||||||
|
|
||||||
|
rope-sequence@1.3.4: {}
|
||||||
|
|
||||||
router@2.2.0:
|
router@2.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
debug: 4.4.3
|
debug: 4.4.3
|
||||||
@ -26557,6 +27257,10 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
react: 19.2.3
|
react: 19.2.3
|
||||||
|
|
||||||
|
use-sync-external-store@1.6.0(react@19.2.4):
|
||||||
|
dependencies:
|
||||||
|
react: 19.2.4
|
||||||
|
|
||||||
util-deprecate@1.0.2: {}
|
util-deprecate@1.0.2: {}
|
||||||
|
|
||||||
util@0.12.5:
|
util@0.12.5:
|
||||||
@ -26888,6 +27592,8 @@ snapshots:
|
|||||||
|
|
||||||
vlq@1.0.1: {}
|
vlq@1.0.1: {}
|
||||||
|
|
||||||
|
w3c-keyname@2.2.8: {}
|
||||||
|
|
||||||
w3c-xmlserializer@5.0.0:
|
w3c-xmlserializer@5.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
xml-name-validator: 5.0.0
|
xml-name-validator: 5.0.0
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user