diff --git a/.github/workflows/ci-react.yml b/.github/workflows/ci-react.yml new file mode 100644 index 0000000000..d4f6f23fb0 --- /dev/null +++ b/.github/workflows/ci-react.yml @@ -0,0 +1,45 @@ +name: CI React + +permissions: + contents: read + +on: + pull_request: + paths: + - 'packages/react/**' + workflow_dispatch: + +concurrency: + group: ci-react-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + validate: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v4 + with: + node-version-file: .nvmrc + cache: pnpm + + - name: Install dependencies + run: pnpm install + + - name: Build superdoc (dependency) + run: pnpm run build:superdoc + + - name: Lint + run: pnpm --filter @superdoc-dev/react lint + + - name: Type check + run: pnpm --filter @superdoc-dev/react type-check + + - name: Build + run: pnpm --filter @superdoc-dev/react build + + - name: Test + run: pnpm --filter @superdoc-dev/react test diff --git a/.github/workflows/release-react.yml b/.github/workflows/release-react.yml new file mode 100644 index 0000000000..cd4f188b4b --- /dev/null +++ b/.github/workflows/release-react.yml @@ -0,0 +1,68 @@ +# Auto-releases on push to main (@next channel) +# For stable (@latest): cherry-pick commits to stable branch, then manually dispatch this workflow +name: 📦 Release react + +on: + push: + branches: + - main + - feat/react-wrapper + paths: + - 'packages/react/**' + - 'packages/superdoc/**' + - 'packages/layout-engine/**' + - 'packages/super-editor/**' + - 'packages/ai/**' + - 'packages/word-layout/**' + - 'packages/preset-geometry/**' + - '!**/*.md' + workflow_dispatch: + +permissions: + contents: write + packages: write + +concurrency: + group: release-react-${{ github.ref }} + cancel-in-progress: true + +jobs: + release: + runs-on: ubuntu-24.04 + steps: + - name: Generate token + id: generate_token + uses: actions/create-github-app-token@v2 + with: + app-id: ${{ secrets.APP_ID }} + private-key: ${{ secrets.APP_PRIVATE_KEY }} + + - uses: actions/checkout@v6 + with: + fetch-depth: 0 + token: ${{ steps.generate_token.outputs.token }} + + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v6 + with: + node-version-file: .nvmrc + cache: pnpm + registry-url: 'https://registry.npmjs.org' + + - uses: oven-sh/setup-bun@v2 + + - name: Install dependencies + run: pnpm install + + - name: Build packages + run: pnpm run build + + - name: Release + env: + GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + LINEAR_TOKEN: ${{ secrets.LINEAR_TOKEN }} + working-directory: packages/react + run: pnpx semantic-release diff --git a/CLAUDE.md b/CLAUDE.md index a1a50d7c2a..cdb6ba29a5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -25,6 +25,7 @@ State flows from super-editor → Layout Engine via: ``` packages/ superdoc/ Main entry point (npm: superdoc) + react/ React wrapper (@superdoc-dev/react) super-editor/ ProseMirror editor (@superdoc/super-editor) layout-engine/ Layout & pagination pipeline contracts/ - Shared type definitions @@ -43,11 +44,12 @@ e2e-tests/ Playwright tests | Task | Location | |------|----------| +| React integration | `packages/react/src/SuperDocEditor.tsx` | | Editing features | `super-editor/src/extensions/` | | Presentation mode visuals | `layout-engine/painters/dom/src/renderer.ts` | | DOCX import/export | `super-editor/src/core/super-converter/` | | Style resolution | `layout-engine/style-engine/` | -| Main entry point | `superdoc/src/SuperDoc.vue` | +| Main entry point (Vue) | `superdoc/src/SuperDoc.vue` | ## When to Modify Which System diff --git a/README.md b/README.md index d72d449c58..74c23b0943 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,30 @@ Or install with CDN ``` -### Basic usage +### React + +```bash +npm install @superdoc-dev/react +``` + +```tsx +import { SuperDocEditor } from '@superdoc-dev/react'; +import '@superdoc-dev/react/style.css'; + +function App() { + return ( + console.log('Ready!')} + /> + ); +} +``` + +See the [@superdoc-dev/react README](packages/react/README.md) for full documentation. + +### Vanilla JavaScript ```javascript import 'superdoc/style.css'; diff --git a/apps/docs/getting-started/frameworks/nextjs.mdx b/apps/docs/getting-started/frameworks/nextjs.mdx new file mode 100644 index 0000000000..08ae69d9a2 --- /dev/null +++ b/apps/docs/getting-started/frameworks/nextjs.mdx @@ -0,0 +1,98 @@ +--- +title: Next.js +keywords: "nextjs docx editor, next word editor, superdoc nextjs, ssr document editor, dynamic import docx" +--- + +SuperDoc works seamlessly with Next.js. The recommended approach is using `@superdoc-dev/react`, which handles SSR automatically. + +## Recommended: Using @superdoc-dev/react + +The React wrapper is the simplest way to integrate SuperDoc with Next.js: + +```bash +npm install @superdoc-dev/react +``` + +### App Router (Next.js 13+) + +```jsx +// app/editor/page.jsx +'use client'; + +import { SuperDocEditor } from '@superdoc-dev/react'; +import '@superdoc-dev/react/style.css'; + +export default function EditorPage() { + return ( + console.log('Editor ready!')} + style={{ height: '100vh' }} + /> + ); +} +``` + +### Pages Router + +```jsx +// pages/editor.jsx +import { SuperDocEditor } from '@superdoc-dev/react'; +import '@superdoc-dev/react/style.css'; + +export default function EditorPage() { + return ( + + ); +} +``` + + +The React wrapper is SSR-safe — it renders container divs on the server (hidden until initialized) and starts SuperDoc after hydration. Use `renderLoading` for custom loading UI, or Next.js dynamic imports if you prefer to skip SSR entirely. + + +--- + +## CSS Import + +Import styles in your layout or page: + +```jsx +// app/layout.jsx +import '@superdoc-dev/react/style.css'; + +export default function RootLayout({ children }) { + return ( + + {children} + + ); +} +``` + +--- + +## Next Steps + + + + Full React wrapper documentation + + + Configuration options + + + Real-time collaboration + + + React + TypeScript example + + + Next.js SSR integration + + diff --git a/apps/docs/getting-started/frameworks/react.mdx b/apps/docs/getting-started/frameworks/react.mdx index 0f415a2e46..193c2fe370 100644 --- a/apps/docs/getting-started/frameworks/react.mdx +++ b/apps/docs/getting-started/frameworks/react.mdx @@ -1,272 +1,584 @@ --- title: React Integration sidebarTitle: React -keywords: "react docx editor, react word component, superdoc react, microsoft word react, document editor react hooks" +keywords: "react docx editor, react word component, superdoc react, microsoft word react, document editor react hooks, @superdoc-dev/react" --- -SuperDoc works with React 16.8+ (hooks) and React 18+ (concurrent features). -## Install +SuperDoc provides `@superdoc-dev/react` - a first-party wrapper with proper lifecycle management, SSR safety, and React Strict Mode compatibility. + +## Installation ```bash -npm install superdoc +npm install @superdoc-dev/react ``` -## Basic setup + +`superdoc` is included as a dependency - you don't need to install it separately. + -```jsx -import { useEffect, useRef } from 'react'; -import { SuperDoc } from 'superdoc'; -import 'superdoc/style.css'; - -function DocEditor({ document }) { - const containerRef = useRef(null); - const superdocRef = useRef(null); - - useEffect(() => { - if (!containerRef.current) return; - - superdocRef.current = new SuperDoc({ - selector: containerRef.current, - document - }); +## Quick Start - return () => { - superdocRef.current?.destroy(); - superdocRef.current = null; - }; - }, [document]); +```jsx +import { SuperDocEditor } from '@superdoc-dev/react'; +import '@superdoc-dev/react/style.css'; - return
; +function App() { + return ( + console.log('Editor ready!')} + /> + ); } ``` -## Full component +That's it! You now have a fully functional DOCX editor in your React app. + +--- + +## Core Concepts + +### The Component -Build a reusable editor with controls: +`` handles everything for you: + +- **Mounting** - Creates a SuperDoc instance when the component mounts +- **Updates** - Rebuilds automatically when the `document` prop changes +- **Cleanup** - Properly destroys the instance on unmount +- **SSR-Safe** - Renders container structure on server, initializes SuperDoc after hydration + +### Document Modes + +SuperDoc supports three editing modes: + +| Mode | Description | Use Case | +|------|-------------|----------| +| `editing` | Full editing capabilities | Default editing experience | +| `viewing` | Read-only presentation | Document preview | +| `suggesting` | Track changes mode | Collaborative review | ```jsx -import { useEffect, useRef, forwardRef, useImperativeHandle } from 'react'; -import { SuperDoc } from 'superdoc'; -import 'superdoc/style.css'; - -const DocEditor = forwardRef(({ document, user, onReady }, ref) => { - const containerRef = useRef(null); - const superdocRef = useRef(null); - - useImperativeHandle(ref, () => ({ - export: (options) => superdocRef.current?.export(options), - setMode: (mode) => superdocRef.current?.setDocumentMode(mode), - getHTML: () => superdocRef.current?.getHTML() - })); - - useEffect(() => { - if (!containerRef.current) return; - - superdocRef.current = new SuperDoc({ - selector: containerRef.current, - document, - user, - onReady: () => onReady?.(superdocRef.current) - }); + +``` + + +Changing `documentMode` via props is efficient - the component calls `setDocumentMode()` internally without rebuilding. You can also use `getInstance()?.setDocumentMode()` directly if preferred. + + +### User Roles + +Roles control what actions a user can perform: + +| Role | Can Edit | Can Suggest | Can View | +|------|----------|-------------|----------| +| `editor` | Yes | Yes | Yes | +| `suggester` | No | Yes | Yes | +| `viewer` | No | No | Yes | + +```jsx + +``` + +--- + +## Working with Refs - return () => { - superdocRef.current?.destroy(); - superdocRef.current = null; - }; - }, [document, user, onReady]); +For programmatic control, use a ref to access the SuperDoc instance: - return
; -}); +```jsx +import { useRef } from 'react'; +import { SuperDocEditor } from '@superdoc-dev/react'; +import '@superdoc-dev/react/style.css'; -// Usage function App() { - const editorRef = useRef(); - + const editorRef = useRef(null); + const handleExport = async () => { - await editorRef.current.export({ isFinalDoc: true }); + // Export as DOCX and trigger download + await editorRef.current?.getInstance()?.export({ triggerDownload: true }); + }; + + const handleModeSwitch = () => { + // Switch mode without rebuilding + editorRef.current?.getInstance()?.setDocumentMode('suggesting'); }; - + return ( <> - - - Download DOCX + + console.log('Ready', editor)} + onReady={({ superdoc }) => console.log('Ready', superdoc)} /> ); } ``` -## File upload +### Ref API + +The ref exposes a single method: + +| Method | Returns | Description | +|--------|---------|-------------| +| `getInstance()` | `SuperDoc \| null` | Access the underlying SuperDoc instance | + + +`getInstance()` returns `null` before the editor is ready. Use optional chaining (`?.`) for safe access. + + +### Available Instance Methods + +Once you have the SuperDoc instance via `getInstance()`, you can call any SuperDoc method: + +| Method | Returns | Description | +|--------|---------|-------------| +| `setDocumentMode(mode)` | `void` | Change mode without rebuild | +| `export(options?)` | `Promise` | Export document as DOCX | +| `getHTML(options?)` | `string[]` | Get document as HTML | +| `focus()` | `void` | Focus the editor | +| `search(text)` | `SearchResult[]` | Search document content | +| `goToSearchResult(match)` | `void` | Navigate to a search result | +| `setLocked(locked)` | `void` | Lock/unlock editing | +| `toggleRuler()` | `void` | Toggle ruler visibility | +| `save()` | `Promise` | Save (in collaboration mode) | + +--- + +## Common Patterns + +### File Upload ```jsx +import { useState, useRef } from 'react'; +import { SuperDocEditor } from '@superdoc-dev/react'; +import '@superdoc-dev/react/style.css'; + function FileEditor() { const [file, setFile] = useState(null); - const editorRef = useRef(); + const editorRef = useRef(null); - const handleFile = (e) => { - setFile(e.target.files[0]); + const handleFileChange = (e) => { + const selected = e.target.files?.[0]; + if (selected) setFile(selected); }; const handleExport = async () => { - const blob = await editorRef.current?.export({ - isFinalDoc: true - }); - // Download blob... + const blob = await editorRef.current?.getInstance()?.export({ triggerDownload: false }); + // Use blob for custom handling... }; return ( - <> - +
+ {file && ( <> - )} - +
+ ); +} +``` + +### Loading State + +Show a custom loading indicator while SuperDoc initializes: + +```jsx + ( +
+ Loading document... +
+ )} + onReady={() => console.log('Ready!')} +/> +``` + +### Document Switching + +The editor automatically rebuilds when the `document` prop changes: + +```jsx +function MultiDocEditor() { + const [currentDoc, setCurrentDoc] = useState(doc1); + + return ( +
+ + + +
); } ``` -## TypeScript +### View-Only Mode + +```jsx + +``` + +### With User Information + +```jsx + +``` + +--- + +## TypeScript Support + +The wrapper includes full TypeScript support: ```tsx -import { useEffect, useRef, forwardRef } from 'react'; -import { SuperDoc } from 'superdoc'; -import type { SuperDocConfig } from 'superdoc'; +import { useRef } from 'react'; +import { SuperDocEditor } from '@superdoc-dev/react'; +import type { SuperDocRef } from '@superdoc-dev/react'; +import '@superdoc-dev/react/style.css'; interface EditorProps { document: string | File | Blob; userId: string; - onReady?: (editor: SuperDoc) => void; } -interface EditorRef { - export: (options?: ExportOptions) => Promise; - setMode: (mode: 'editing' | 'viewing' | 'suggesting') => void; - getHTML: () => string[]; +function DocEditor({ document, userId }: EditorProps) { + const editorRef = useRef(null); + + const handleReady = ({ superdoc }: { superdoc: any }) => { + console.log('SuperDoc ready'); + }; + + const handleExport = async () => { + const blob = await editorRef.current?.getInstance()?.export({ + triggerDownload: true + }); + return blob; + }; + + return ( + + ); } +``` -const DocEditor = forwardRef( - ({ document, userId, onReady }, ref) => { - const containerRef = useRef(null); - const superdocRef = useRef(null); - - useImperativeHandle(ref, () => ({ - export: async (options) => { - if (!superdocRef.current) throw new Error('Editor not ready'); - return await superdocRef.current.export(options); - }, - setMode: (mode) => { - superdocRef.current?.setDocumentMode(mode); - }, - getHTML: () => { - return superdocRef.current?.getHTML() || []; - } - })); - - useEffect(() => { - if (!containerRef.current) return; - - const config: SuperDocConfig = { - selector: containerRef.current, - document, - user: { - name: userId, - email: `${userId}@company.com` - }, - onReady: () => onReady?.(superdocRef.current!) - }; - - superdocRef.current = new SuperDoc(config); - - return () => { - superdocRef.current?.destroy(); - superdocRef.current = null; - }; - }, [document, userId, onReady]); - - return
; - } -); +### Exported Types + +```tsx +import type { + SuperDocEditorProps, + SuperDocRef, + DocumentMode, + UserRole, + SuperDocUser, + SuperDocModules, + SuperDocConfig, + SuperDocInstance, +} from '@superdoc-dev/react'; ``` -## SSR support +--- + +## Framework Integration -For Next.js or other SSR frameworks: +### Next.js (App Router) + +The wrapper handles SSR automatically. For additional control: ```jsx +'use client'; + import dynamic from 'next/dynamic'; -const DocEditor = dynamic( - () => import('./DocEditor'), - { +const SuperDocEditor = dynamic( + () => import('@superdoc-dev/react').then(mod => mod.SuperDocEditor), + { ssr: false, loading: () =>
Loading editor...
} ); -// Or manually check for client-side -function SafeEditor(props) { - const [mounted, setMounted] = useState(false); - - useEffect(() => { - setMounted(true); - }, []); - - if (!mounted) return
Loading...
; - - return ; +export default function EditorPage() { + return ; } ``` -## Custom hook +### Next.js (Pages Router) ```jsx -function useSuperDoc(config) { - const [ready, setReady] = useState(false); - const superdocRef = useRef(null); - - useEffect(() => { - if (!config.selector) return; - - superdocRef.current = new SuperDoc({ - ...config, - onReady: () => { - setReady(true); - config.onReady?.(); - } - }); - - return () => { - superdocRef.current?.destroy(); - superdocRef.current = null; - setReady(false); - }; - }, [config.selector, config.document]); - - return { - editor: superdocRef.current, - ready, - export: (options) => superdocRef.current?.export(options), - setMode: (mode) => superdocRef.current?.setDocumentMode(mode) - }; +import dynamic from 'next/dynamic'; + +const SuperDocEditor = dynamic( + () => import('@superdoc-dev/react').then(mod => mod.SuperDocEditor), + { ssr: false } +); + +export default function EditorPage() { + return ; +} +``` + +### Vite / Create React App + +Works out of the box - just import and use: + +```jsx +import { SuperDocEditor } from '@superdoc-dev/react'; +import '@superdoc-dev/react/style.css'; + +function App() { + return ; +} +``` + +--- + +## Advanced Features + +### Real-time Collaboration + +```jsx +import * as Y from 'yjs'; +import { WebsocketProvider } from 'y-websocket'; + +function CollaborativeEditor() { + const ydoc = useMemo(() => new Y.Doc(), []); + const provider = useMemo( + () => new WebsocketProvider('wss://your-server.com', 'doc-id', ydoc), + [ydoc] + ); + + return ( + + ); } ``` -## Next steps + + + Learn more about setting up real-time collaboration + + + +### AI Features + +```jsx + +``` + +### Search and Navigate + +```jsx +const editorRef = useRef(null); + +const handleSearch = (query) => { + const instance = editorRef.current?.getInstance(); + const results = instance?.search(query); + if (results?.length) { + instance?.goToSearchResult(results[0]); + } +}; +``` + +### Export to HTML + +```jsx +const editorRef = useRef(null); + +const getHtmlContent = () => { + const htmlArray = editorRef.current?.getInstance()?.getHTML(); + console.log(htmlArray); // Array of HTML strings per section +}; +``` + +--- + +## Props Reference + +### Document Props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `document` | `File \| Blob \| string \| object` | required | Document to load | +| `documentMode` | `'editing' \| 'viewing' \| 'suggesting'` | `'editing'` | Initial editing mode | +| `role` | `'editor' \| 'viewer' \| 'suggester'` | `'editor'` | User's permission level | + +### User Props + +| Prop | Type | Description | +|------|------|-------------| +| `user` | `{ name, email?, image? }` | Current user info | +| `users` | `Array<{ name, email, image? }>` | All users (for @-mentions) | + +### UI Props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `id` | `string` | auto-generated | Custom container ID | +| `hideToolbar` | `boolean` | `false` | Hide the toolbar | +| `rulers` | `boolean` | - | Show/hide rulers (SuperDoc default) | +| `className` | `string` | - | CSS class for wrapper | +| `style` | `CSSProperties` | - | Inline styles | +| `renderLoading` | `() => ReactNode` | - | Custom loading UI | + +### Event Callbacks + +| Prop | Type | Description | +|------|------|-------------| +| `onReady` | `({ superdoc }) => void` | Editor initialized | +| `onEditorCreate` | `({ editor }) => void` | ProseMirror editor created | +| `onEditorDestroy` | `() => void` | Editor destroyed | +| `onEditorUpdate` | `({ editor }) => void` | Content changed | +| `onContentError` | `(event) => void` | Document parsing error | +| `onException` | `({ error }) => void` | Runtime error | + +### Advanced Props + +| Prop | Type | Description | +|------|------|-------------| +| `modules` | `object` | Configure collaboration, AI, comments | + + +All SuperDoc config options are available as props. The component extends `SuperDocConfig`, so any option from the core package can be passed directly. + + +### Props That Trigger Rebuild + +These props trigger a full instance rebuild when changed: + +| Prop | Reason | +|------|--------| +| `document` | New document to load | +| `user` | User identity changed | +| `users` | Users list changed | +| `modules` | Module configuration changed | +| `role` | Permission level changed | +| `hideToolbar` | Toolbar visibility changed | + +Other props like `documentMode` and callbacks are handled efficiently without rebuild. + +--- + +## Troubleshooting + +### "document is not defined" (SSR) + +The component handles SSR internally, but if you still see errors: + +```jsx +// Use dynamic import in Next.js +const SuperDocEditor = dynamic( + () => import('@superdoc-dev/react').then(mod => mod.SuperDocEditor), + { ssr: false } +); +``` + +### React Strict Mode Double-Mount + +The component handles React 18 Strict Mode correctly. The internal cleanup flag prevents issues from double-invocation during development. + +### Document Not Loading + +1. Verify the file is a valid `.docx` document +2. Check that `document` prop is a `File`, `Blob`, URL string, or config object +3. Listen for `onContentError` events for parsing errors + +### Changing Document Mode + +The component handles `documentMode` prop changes efficiently without rebuilding: + +```jsx +const [mode, setMode] = useState('editing'); + +// Just update state - no rebuild, no flicker + + +``` + +You can also use the imperative API if preferred: + +```jsx +editorRef.current?.getInstance()?.setDocumentMode('viewing'); +``` + +--- -- [Vue Integration](/getting-started/frameworks/vue) - Vue setup -- [API Reference](/core/superdoc/configuration) - Configuration options -- [Examples](https://github.com/superdoc-dev/superdoc/tree/main/examples/getting-started/react) - Working examples +## Requirements + +| Requirement | Version | +|-------------|---------| +| React | 16.8.0+ | +| Node.js | 16+ | + +## Next Steps + + + + Full configuration options + + + All available methods + + + Real-time collaboration setup + + + React + TypeScript example + + + Next.js SSR integration + + diff --git a/apps/docs/scripts/validate-code-imports.ts b/apps/docs/scripts/validate-code-imports.ts index 1e0ef2c13e..5587dd0a29 100644 --- a/apps/docs/scripts/validate-code-imports.ts +++ b/apps/docs/scripts/validate-code-imports.ts @@ -25,6 +25,8 @@ const EXACT_SUPERDOC_IMPORTS = new Set([ '@superdoc-dev/ai', '@superdoc-dev/esign', '@superdoc-dev/esign/styles.css', + '@superdoc-dev/react', + '@superdoc-dev/react/style.css', '@superdoc-dev/template-builder', '@superdoc-dev/template-builder/defaults', '@superdoc-dev/superdoc-yjs-collaboration', @@ -37,6 +39,7 @@ const EXACT_EXTERNAL_IMPORTS = new Set([ 'vue', 'yjs', 'y-prosemirror', + 'y-websocket', 'openai', 'bun:test', 'hocuspocus', diff --git a/examples/getting-started/nextjs/.gitignore b/examples/getting-started/nextjs/.gitignore new file mode 100644 index 0000000000..ce6281ea81 --- /dev/null +++ b/examples/getting-started/nextjs/.gitignore @@ -0,0 +1,6 @@ +node_modules +/.next/ +/out/ +next-env.d.ts +*.tsbuildinfo +.DS_Store diff --git a/examples/getting-started/nextjs/eslint.config.mjs b/examples/getting-started/nextjs/eslint.config.mjs new file mode 100644 index 0000000000..05e726d1b4 --- /dev/null +++ b/examples/getting-started/nextjs/eslint.config.mjs @@ -0,0 +1,18 @@ +import { defineConfig, globalIgnores } from "eslint/config"; +import nextVitals from "eslint-config-next/core-web-vitals"; +import nextTs from "eslint-config-next/typescript"; + +const eslintConfig = defineConfig([ + ...nextVitals, + ...nextTs, + // Override default ignores of eslint-config-next. + globalIgnores([ + // Default ignores of eslint-config-next: + ".next/**", + "out/**", + "build/**", + "next-env.d.ts", + ]), +]); + +export default eslintConfig; diff --git a/examples/getting-started/nextjs/next.config.ts b/examples/getting-started/nextjs/next.config.ts new file mode 100644 index 0000000000..e9ffa3083a --- /dev/null +++ b/examples/getting-started/nextjs/next.config.ts @@ -0,0 +1,7 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + /* config options here */ +}; + +export default nextConfig; diff --git a/examples/getting-started/nextjs/package.json b/examples/getting-started/nextjs/package.json new file mode 100644 index 0000000000..616e6af383 --- /dev/null +++ b/examples/getting-started/nextjs/package.json @@ -0,0 +1,27 @@ +{ + "name": "nextjs-superdoc", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "eslint" + }, + "dependencies": { + "@superdoc-dev/react": "^1.0.0-rc.1", + "next": "16.1.6", + "react": "^19.2.0", + "react-dom": "^19.2.0" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4", + "@types/node": "^20", + "@types/react": "^19", + "@types/react-dom": "^19", + "eslint": "^9", + "eslint-config-next": "16.1.6", + "tailwindcss": "^4", + "typescript": "^5" + } +} diff --git a/examples/getting-started/nextjs/postcss.config.mjs b/examples/getting-started/nextjs/postcss.config.mjs new file mode 100644 index 0000000000..61e36849cf --- /dev/null +++ b/examples/getting-started/nextjs/postcss.config.mjs @@ -0,0 +1,7 @@ +const config = { + plugins: { + "@tailwindcss/postcss": {}, + }, +}; + +export default config; diff --git a/examples/getting-started/nextjs/public/file.svg b/examples/getting-started/nextjs/public/file.svg new file mode 100644 index 0000000000..004145cddf --- /dev/null +++ b/examples/getting-started/nextjs/public/file.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/getting-started/nextjs/public/globe.svg b/examples/getting-started/nextjs/public/globe.svg new file mode 100644 index 0000000000..567f17b0d7 --- /dev/null +++ b/examples/getting-started/nextjs/public/globe.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/getting-started/nextjs/public/next.svg b/examples/getting-started/nextjs/public/next.svg new file mode 100644 index 0000000000..5174b28c56 --- /dev/null +++ b/examples/getting-started/nextjs/public/next.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/getting-started/nextjs/public/vercel.svg b/examples/getting-started/nextjs/public/vercel.svg new file mode 100644 index 0000000000..7705396033 --- /dev/null +++ b/examples/getting-started/nextjs/public/vercel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/getting-started/nextjs/public/window.svg b/examples/getting-started/nextjs/public/window.svg new file mode 100644 index 0000000000..b2b2a44f6e --- /dev/null +++ b/examples/getting-started/nextjs/public/window.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/examples/getting-started/nextjs/src/app/favicon.ico b/examples/getting-started/nextjs/src/app/favicon.ico new file mode 100644 index 0000000000..718d6fea48 Binary files /dev/null and b/examples/getting-started/nextjs/src/app/favicon.ico differ diff --git a/examples/getting-started/nextjs/src/app/globals.css b/examples/getting-started/nextjs/src/app/globals.css new file mode 100644 index 0000000000..a2dc41ecee --- /dev/null +++ b/examples/getting-started/nextjs/src/app/globals.css @@ -0,0 +1,26 @@ +@import "tailwindcss"; + +:root { + --background: #ffffff; + --foreground: #171717; +} + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --font-sans: var(--font-geist-sans); + --font-mono: var(--font-geist-mono); +} + +@media (prefers-color-scheme: dark) { + :root { + --background: #0a0a0a; + --foreground: #ededed; + } +} + +body { + background: var(--background); + color: var(--foreground); + font-family: Arial, Helvetica, sans-serif; +} diff --git a/examples/getting-started/nextjs/src/app/layout.tsx b/examples/getting-started/nextjs/src/app/layout.tsx new file mode 100644 index 0000000000..eab146199b --- /dev/null +++ b/examples/getting-started/nextjs/src/app/layout.tsx @@ -0,0 +1,34 @@ +import type { Metadata } from "next"; +import { Geist, Geist_Mono } from "next/font/google"; +import "./globals.css"; + +const geistSans = Geist({ + variable: "--font-geist-sans", + subsets: ["latin"], +}); + +const geistMono = Geist_Mono({ + variable: "--font-geist-mono", + subsets: ["latin"], +}); + +export const metadata: Metadata = { + title: "SuperDoc + Next.js", + description: "Document editor powered by SuperDoc", +}; + +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + + {children} + + + ); +} diff --git a/examples/getting-started/nextjs/src/app/page.tsx b/examples/getting-started/nextjs/src/app/page.tsx new file mode 100644 index 0000000000..f0a972148b --- /dev/null +++ b/examples/getting-started/nextjs/src/app/page.tsx @@ -0,0 +1,127 @@ +'use client'; + +import { useState, useRef } from 'react'; +import { SuperDocEditor, SuperDocRef, DocumentMode } from '@superdoc-dev/react'; +import '@superdoc-dev/react/style.css'; + +export default function Home() { + const [file, setFile] = useState(null); + const [mode, setMode] = useState('editing'); + const editorRef = useRef(null); + + const handleFileChange = (e: React.ChangeEvent) => { + const selectedFile = e.target.files?.[0]; + if (selectedFile) { + setFile(selectedFile); + } + }; + + const handleExport = async () => { + await editorRef.current?.getInstance()?.export({ triggerDownload: true }); + }; + + return ( +
+ {/* Header */} +
+

+ SuperDoc + Next.js +

+ +
+ {/* Mode Toggle */} + {file && ( + <> +
+ + +
+ + + + )} +
+
+ + {/* Main Content */} +
+ {!file ? ( + /* File Upload UI */ +
+ +
+ ) : ( + /* SuperDoc Editor */ +
+ console.log('SuperDoc is ready!')} + onEditorUpdate={() => console.log('Document updated')} + renderLoading={() => ( +
+
Loading document...
+
+ )} + style={{ height: 'calc(100vh - 73px)' }} + /> +
+ )} +
+
+ ); +} diff --git a/examples/getting-started/nextjs/tsconfig.json b/examples/getting-started/nextjs/tsconfig.json new file mode 100644 index 0000000000..cf9c65d3e0 --- /dev/null +++ b/examples/getting-started/nextjs/tsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts", + "**/*.mts" + ], + "exclude": ["node_modules"] +} diff --git a/examples/getting-started/react/.gitignore b/examples/getting-started/react/.gitignore new file mode 100644 index 0000000000..a547bf36d8 --- /dev/null +++ b/examples/getting-started/react/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/examples/getting-started/react/README.md b/examples/getting-started/react/README.md index e9e747fc1d..5f0de5b164 100644 --- a/examples/getting-started/react/README.md +++ b/examples/getting-started/react/README.md @@ -1,15 +1,47 @@ -# SuperDoc — React +# SuperDoc React + TypeScript Example -Minimal React + TypeScript example. +A TypeScript example demonstrating `@superdoc-dev/react` integration with full type safety. + +## Features Demonstrated + +- **File Upload** - Load `.docx` files with type-safe event handlers +- **Mode Switching** - Toggle between editing, suggesting, and viewing modes +- **Ref API** - Access SuperDoc instance methods with proper typing +- **Export** - Download documents as DOCX +- **User Info** - Pass typed user information to the editor +- **Loading States** - Custom loading UI with `renderLoading` +- **Event Callbacks** - Typed callbacks for editor events ## Run ```bash -npm install -npm run dev +# From repo root +pnpm install +pnpm -C examples/getting-started/react dev +``` + +## Key Types Used + +```typescript +import type { SuperDocRef, DocumentMode } from '@superdoc-dev/react'; + +// Ref for accessing instance methods +const editorRef = useRef(null); + +// Typed document mode state +const [mode, setMode] = useState('editing'); + +// Access instance with proper types +const instance = editorRef.current?.getInstance(); +await instance?.export({ triggerDownload: true }); ``` -## Learn more +## Project Structure -- [React Integration Guide](https://docs.superdoc.dev/getting-started/frameworks/react) -- [Configuration Reference](https://docs.superdoc.dev/core/superdoc/configuration) +``` +src/ +├── App.tsx # Main component with SuperDoc integration +├── App.css # Styles +├── main.tsx # Entry point +└── index.css # Global styles +``` diff --git a/examples/getting-started/react/index.html b/examples/getting-started/react/index.html index 094d07e62a..fa31e5e69d 100644 --- a/examples/getting-started/react/index.html +++ b/examples/getting-started/react/index.html @@ -1,9 +1,9 @@ - + - SuperDoc — React + SuperDoc React + TypeScript Example
diff --git a/examples/getting-started/react/package.json b/examples/getting-started/react/package.json index af64b5c329..45aad26e23 100644 --- a/examples/getting-started/react/package.json +++ b/examples/getting-started/react/package.json @@ -1,20 +1,23 @@ { - "name": "superdoc-react-example", + "name": "react-with-typescript-example", "private": true, + "version": "0.0.1", "type": "module", "scripts": { - "dev": "vite" + "dev": "vite", + "build": "tsc -b && vite build", + "preview": "vite preview" }, "dependencies": { - "react": "^19.0.0", - "react-dom": "^19.0.0", - "superdoc": "latest" + "@superdoc-dev/react": "^1.0.0-rc.1", + "react": "^19.2.0", + "react-dom": "^19.2.0" }, "devDependencies": { - "@types/react": "^19.0.0", - "@types/react-dom": "^19.0.0", - "@vitejs/plugin-react": "^4.3.4", - "typescript": "^5.7.0", - "vite": "^6.2.0" + "@types/react": "^18.3.0", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.3.0", + "typescript": "~5.5.0", + "vite": "^5.4.0" } } diff --git a/examples/getting-started/react/src/App.css b/examples/getting-started/react/src/App.css new file mode 100644 index 0000000000..c9fb3dbd23 --- /dev/null +++ b/examples/getting-started/react/src/App.css @@ -0,0 +1,218 @@ +/* Layout */ +.app { + height: 100vh; + display: flex; + flex-direction: column; + background: #f5f5f5; +} + +/* Header */ +.header { + padding: 1rem 1.5rem; + background: #1a1a2e; + color: white; + display: flex; + align-items: center; + gap: 1.5rem; + flex-wrap: wrap; +} + +.header h1 { + font-size: 1.25rem; + font-weight: 600; + margin-right: auto; +} + +/* Controls */ +.controls { + display: flex; + align-items: center; + gap: 1rem; + flex-wrap: wrap; +} + +/* Buttons */ +.btn { + padding: 0.5rem 1rem; + font-size: 0.875rem; + font-weight: 500; + border: 1px solid rgba(255, 255, 255, 0.2); + border-radius: 6px; + background: transparent; + color: white; + cursor: pointer; + transition: all 0.15s; +} + +.btn:hover { + background: rgba(255, 255, 255, 0.1); +} + +.btn.primary { + background: #3b82f6; + border-color: #3b82f6; +} + +.btn.primary:hover { + background: #2563eb; + border-color: #2563eb; +} + +.btn.large { + padding: 0.75rem 1.5rem; + font-size: 1rem; +} + +.btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +/* Mode Switcher */ +.mode-switcher { + display: flex; + background: rgba(255, 255, 255, 0.1); + border-radius: 6px; + padding: 2px; +} + +.mode-btn { + padding: 0.4rem 0.75rem; + font-size: 0.8rem; + font-weight: 500; + border: none; + border-radius: 4px; + background: transparent; + color: rgba(255, 255, 255, 0.7); + cursor: pointer; + transition: all 0.15s; +} + +.mode-btn:hover:not(:disabled) { + color: white; +} + +.mode-btn.active { + background: white; + color: #1a1a2e; +} + +.mode-btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +/* Actions */ +.actions { + display: flex; + gap: 0.5rem; +} + +/* Status */ +.status { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 0.8rem; + color: rgba(255, 255, 255, 0.7); +} + +.status-dot { + width: 8px; + height: 8px; + border-radius: 50%; + background: #fbbf24; +} + +.status-dot.ready { + background: #22c55e; +} + +.status-dot.loading { + animation: pulse 1s infinite; +} + +@keyframes pulse { + 0%, + 100% { + opacity: 1; + } + 50% { + opacity: 0.5; + } +} + +/* Editor Area */ +.editor-area { + flex: 1; + min-height: 0; + background: white; +} + +/* Empty State */ +.empty-state { + height: 100%; + display: flex; + align-items: center; + justify-content: center; + background: #fafafa; +} + +.empty-content { + text-align: center; + color: #666; +} + +.empty-content h2 { + font-size: 1.5rem; + font-weight: 600; + color: #333; + margin-bottom: 0.5rem; +} + +.empty-content p { + margin-bottom: 1.5rem; +} + +/* Loading State */ +.loading-state { + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 1rem; + color: #666; +} + +.spinner { + width: 32px; + height: 32px; + border: 3px solid #e5e7eb; + border-top-color: #3b82f6; + border-radius: 50%; + animation: spin 0.8s linear infinite; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +/* Responsive */ +@media (max-width: 768px) { + .header { + padding: 1rem; + } + + .header h1 { + width: 100%; + margin-bottom: 0.5rem; + } + + .controls { + width: 100%; + justify-content: flex-start; + } +} diff --git a/examples/getting-started/react/src/App.tsx b/examples/getting-started/react/src/App.tsx index f0fd1f687d..2f1ce76b59 100644 --- a/examples/getting-started/react/src/App.tsx +++ b/examples/getting-started/react/src/App.tsx @@ -1,37 +1,181 @@ -import { useEffect, useRef, useState, type ChangeEvent } from 'react'; -import { SuperDoc } from 'superdoc'; -import 'superdoc/style.css'; - -export default function App() { - const [file, setFile] = useState(null); - const containerRef = useRef(null); - const superdocRef = useRef(null); - - const handleFile = (e: ChangeEvent) => { - const selected = e.target.files?.[0]; - if (selected) setFile(selected); +import { useRef, useState } from 'react'; +import { SuperDocEditor } from '@superdoc-dev/react'; +import type { SuperDocRef, DocumentMode } from '@superdoc-dev/react'; +import '@superdoc-dev/react/style.css'; +import './App.css'; + +/** + * SuperDoc React + TypeScript Example + * + * Demonstrates: + * - File upload with type safety + * - Document mode switching (editing/viewing/suggesting) + * - Export functionality via ref API + * - User information + * - Loading states + * - Event callbacks + */ +function App() { + // Document state + const [document, setDocument] = useState(null); + const [mode, setMode] = useState('editing'); + const [isReady, setIsReady] = useState(false); + + // Ref for accessing SuperDoc instance methods + const editorRef = useRef(null); + const fileInputRef = useRef(null); + + // Current user (typed) + const currentUser = { + name: 'John Doe', + email: 'john@example.com', }; - useEffect(() => { - if (!containerRef.current) return; + // Handle file selection + const handleFileSelect = (event: React.ChangeEvent) => { + const file = event.target.files?.[0]; + if (file && file.name.endsWith('.docx')) { + setDocument(file); + setIsReady(false); + } + }; - superdocRef.current = new SuperDoc({ - selector: containerRef.current, - document: file, - }); + // Export document as DOCX + const handleExport = async () => { + const instance = editorRef.current?.getInstance(); + if (instance) { + await instance.export({ triggerDownload: true }); + } + }; + + // Get document as HTML + const handleGetHTML = () => { + const instance = editorRef.current?.getInstance(); + if (instance) { + const html = instance.getHTML(); + console.log('Document HTML:', html); + alert(`Document has ${html.length} section(s). Check console for HTML.`); + } + }; - return () => { - superdocRef.current?.destroy(); - superdocRef.current = null; - }; - }, [file]); + // Mode button component for cleaner JSX + const ModeButton = ({ + targetMode, + label, + }: { + targetMode: DocumentMode; + label: string; + }) => ( + + ); return ( - <> -
- -
-
- +
+ {/* Header with controls */} +
+

SuperDoc React + TypeScript

+ +
+ {/* File upload */} + + + + {/* Mode switcher */} + {document && ( +
+ + + +
+ )} + + {/* Actions */} + {document && isReady && ( +
+ + +
+ )} +
+ + {/* Status indicator */} + {document && ( +
+ + {isReady ? `Ready - ${mode} mode` : 'Loading...'} +
+ )} +
+ + {/* Editor area */} +
+ {document ? ( + { + console.log('SuperDoc ready:', superdoc); + setIsReady(true); + }} + onEditorCreate={({ editor }) => { + console.log('ProseMirror editor created:', editor); + }} + onEditorUpdate={() => { + console.log('Document updated'); + }} + onContentError={(event) => { + console.error('Content error:', event); + }} + renderLoading={() => ( +
+
+

Loading document...

+
+ )} + style={{ height: '100%' }} + /> + ) : ( +
+
+

No Document Loaded

+

Click "Open Document" to load a .docx file

+ +
+
+ )} +
+
); } + +export default App; diff --git a/examples/getting-started/react/src/index.css b/examples/getting-started/react/src/index.css new file mode 100644 index 0000000000..558e2a6f6f --- /dev/null +++ b/examples/getting-started/react/src/index.css @@ -0,0 +1,20 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +html, +body, +#root { + height: 100%; +} + +body { + font-family: + -apple-system, + BlinkMacSystemFont, + 'Segoe UI', + Roboto, + sans-serif; +} diff --git a/examples/getting-started/react/src/main.tsx b/examples/getting-started/react/src/main.tsx index e0138a10cc..a46835a4fc 100644 --- a/examples/getting-started/react/src/main.tsx +++ b/examples/getting-started/react/src/main.tsx @@ -1,4 +1,10 @@ +import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import App from './App'; +import './index.css'; -createRoot(document.getElementById('root')!).render(); +createRoot(document.getElementById('root')!).render( + + + +); diff --git a/examples/getting-started/react/src/vite-env.d.ts b/examples/getting-started/react/src/vite-env.d.ts new file mode 100644 index 0000000000..11f02fe2a0 --- /dev/null +++ b/examples/getting-started/react/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/examples/getting-started/react/tsconfig.json b/examples/getting-started/react/tsconfig.json index 4f344fd6f2..109f0ac280 100644 --- a/examples/getting-started/react/tsconfig.json +++ b/examples/getting-started/react/tsconfig.json @@ -1,12 +1,20 @@ { "compilerOptions": { "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], "module": "ESNext", + "skipLibCheck": true, "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, "jsx": "react-jsx", "strict": true, - "esModuleInterop": true, - "skipLibCheck": true + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true }, "include": ["src"] } diff --git a/examples/getting-started/react/vite.config.ts b/examples/getting-started/react/vite.config.ts index 0466183af6..8b0f57b91a 100644 --- a/examples/getting-started/react/vite.config.ts +++ b/examples/getting-started/react/vite.config.ts @@ -1,6 +1,7 @@ -import { defineConfig } from 'vite'; -import react from '@vitejs/plugin-react'; +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +// https://vite.dev/config/ export default defineConfig({ plugins: [react()], -}); +}) diff --git a/packages/react/.releaserc.cjs b/packages/react/.releaserc.cjs new file mode 100644 index 0000000000..4c2ddf2d64 --- /dev/null +++ b/packages/react/.releaserc.cjs @@ -0,0 +1,43 @@ +/* eslint-env node */ +const branch = process.env.GITHUB_REF_NAME || process.env.CI_COMMIT_BRANCH; + +const config = { + branches: [ + { name: 'stable', channel: 'latest' }, + { name: 'main', prerelease: 'next', channel: 'next' }, + { name: 'feat/react-wrapper', prerelease: 'rc', channel: 'rc' }, + ], + tagFormat: 'react-v${version}', + plugins: [ + '@semantic-release/commit-analyzer', + '@semantic-release/release-notes-generator', + ['@semantic-release/npm', { npmPublish: true }], + ], +}; + +const isPrerelease = config.branches.some( + (b) => typeof b === 'object' && b.name === branch && b.prerelease +); + +if (!isPrerelease) { + config.plugins.push([ + '@semantic-release/git', + { + assets: ['package.json'], + message: + 'chore(react): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}', + }, + ]); +} + +// Linear integration - labels issues with version on release +config.plugins.push(['semantic-release-linear-app', { teamKeys: ['SD'], addComment: true, packageName: 'react' }]); + +config.plugins.push([ + '@semantic-release/github', + { + successComment: ':tada: This ${issue.pull_request ? "PR" : "issue"} is included in **@superdoc-dev/react** v${nextRelease.version}\n\nThe release is available on [GitHub release]()', + } +]); + +module.exports = config; diff --git a/packages/react/CLAUDE.md b/packages/react/CLAUDE.md new file mode 100644 index 0000000000..349a079033 --- /dev/null +++ b/packages/react/CLAUDE.md @@ -0,0 +1,86 @@ +# @superdoc-dev/react + +React wrapper for SuperDoc. + +## Files + +| File | Purpose | +|------|---------| +| `src/SuperDocEditor.tsx` | Main component | +| `src/types.ts` | TypeScript types (extracted from superdoc) | +| `src/utils.ts` | ID generation | +| `src/index.ts` | Public exports | + +## Type System + +Types are extracted from `superdoc` constructor to avoid duplication: + +```typescript +type SuperDocConstructorConfig = ConstructorParameters[0]; + +export type DocumentMode = NonNullable; +export type UserRole = NonNullable; +export type SuperDocUser = NonNullable; +export type SuperDocModules = NonNullable; +export type SuperDocConfig = SuperDocConstructorConfig; +export type SuperDocInstance = InstanceType; + +// Props = SuperDocConfig (minus internal) + React-specific +type InternalProps = 'selector'; // managed by component +type OptionalInReact = 'documentMode'; // defaults to 'editing' + +export interface SuperDocEditorProps + extends Omit, + Partial>, + ReactProps {} +``` + +## React-Specific Props + +| Prop | Type | Default | Description | +|------|------|---------|-------------| +| `id` | `string` | auto-generated | Custom container ID | +| `renderLoading` | `() => ReactNode` | - | Loading UI during init | +| `hideToolbar` | `boolean` | `false` | Hide the toolbar | +| `className` | `string` | - | Wrapper CSS class | +| `style` | `CSSProperties` | - | Wrapper inline styles | + +## SSR Behavior + +- Container divs are always rendered (hidden with `display: none` until initialized) +- No `isClient` state or extra rerender — containers exist from first render +- SuperDoc initializes in `useEffect` (client-side only) and mounts into the existing containers +- `renderLoading()` shown alongside hidden containers until initialization completes + +## Ref API + +```typescript +const editorRef = useRef(null); + +// Access SuperDoc instance +const instance = editorRef.current?.getInstance(); + +// Call methods +instance?.setDocumentMode('viewing'); +instance?.export({ triggerDownload: true }); +instance?.getHTML(); +``` + +## Props That Trigger Rebuild + +These props cause the SuperDoc instance to be destroyed and recreated: +- `document` - new document to load +- `user` - user identity changed +- `users` - users list changed +- `modules` - module config changed +- `role` - permission level changed +- `hideToolbar` - toolbar visibility changed + +Other props like `documentMode` and callbacks are handled without rebuild. + +## Commands + +```bash +pnpm --filter @superdoc-dev/react build +pnpm --filter @superdoc-dev/react test +``` diff --git a/packages/react/README.md b/packages/react/README.md new file mode 100644 index 0000000000..4ef78e63d1 --- /dev/null +++ b/packages/react/README.md @@ -0,0 +1,184 @@ +# @superdoc-dev/react + +Official React wrapper for [SuperDoc](https://www.superdoc.dev). + +## Installation + +```bash +npm install @superdoc-dev/react +``` + +> `superdoc` is included as a dependency - no need to install it separately. + +## Quick Start + +```tsx +import { SuperDocEditor } from '@superdoc-dev/react'; +import '@superdoc-dev/react/style.css'; + +function App() { + return ; +} +``` + +## Changing Mode + +Just update the `documentMode` prop - the component handles it efficiently (no rebuild): + +```tsx +function App() { + const [mode, setMode] = useState('editing'); + + return ( + <> + + + + + ); +} +``` + +## Using the Ref + +Access SuperDoc methods via `getInstance()`: + +```tsx +import { useRef } from 'react'; +import { SuperDocEditor, SuperDocRef } from '@superdoc-dev/react'; + +function App() { + const ref = useRef(null); + + const handleExport = async () => { + await ref.current?.getInstance()?.export({ triggerDownload: true }); + }; + + return ( + <> + + + + ); +} +``` + +## Props + +All [SuperDoc config options](https://docs.superdoc.dev) are available as props, plus: + +| Prop | Type | Description | +|------|------|-------------| +| `id` | `string` | Custom container ID (auto-generated if not provided) | +| `renderLoading` | `() => ReactNode` | Loading UI | +| `hideToolbar` | `boolean` | Hide toolbar (default: false) | +| `className` | `string` | Wrapper CSS class | +| `style` | `CSSProperties` | Wrapper inline styles | + +### Props That Trigger Rebuilds + +These props cause the SuperDoc instance to be destroyed and recreated when changed: + +- `document` - The document to load +- `user` - Current user identity +- `users` - List of users +- `modules` - Module configuration (collaboration, comments, etc.) +- `role` - User permission level +- `hideToolbar` - Toolbar visibility + +### Props Handled Efficiently + +These props are applied without rebuilding: + +- `documentMode` - Calls `setDocumentMode()` internally + +### Initial-Only Props + +Other SuperDoc options (`rulers`, `pagination`, etc.) are applied only on initialization. To change them at runtime, use `getInstance()`: + +```tsx +ref.current?.getInstance()?.toggleRuler(); +``` + +### Common Props + +```tsx + console.log('Ready!')} + onEditorCreate={({ editor }) => console.log('Editor created')} +/> +``` + +## Examples + +### View-Only Mode + +```tsx + +``` + +### File Upload + +```tsx +function Editor() { + const [file, setFile] = useState(null); + + return ( + <> + setFile(e.target.files?.[0] || null)} /> + {file && } + + ); +} +``` + +### With Collaboration + +```tsx + +``` + +## Next.js + +```tsx +'use client'; + +import dynamic from 'next/dynamic'; + +const SuperDocEditor = dynamic( + () => import('@superdoc-dev/react').then((m) => m.SuperDocEditor), + { ssr: false } +); +``` + +## TypeScript + +```tsx +import type { + SuperDocEditorProps, + SuperDocRef, + DocumentMode, + UserRole, + SuperDocUser, +} from '@superdoc-dev/react'; +``` + +Types are extracted from the `superdoc` package, ensuring they stay in sync. + +## License + +AGPL-3.0 + diff --git a/packages/react/package.json b/packages/react/package.json new file mode 100644 index 0000000000..aa4651bf18 --- /dev/null +++ b/packages/react/package.json @@ -0,0 +1,78 @@ +{ + "name": "@superdoc-dev/react", + "version": "0.1.0", + "description": "Official React wrapper for the SuperDoc document editor", + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "require": "./dist/index.cjs", + "import": "./dist/index.js" + }, + "./style.css": { + "import": "./style.css", + "require": "./style.css" + } + }, + "scripts": { + "build": "vite build", + "dev": "vite build --watch", + "test": "vitest run", + "type-check": "tsc --noEmit", + "lint": "eslint src --ext .ts,.tsx", + "prepublishOnly": "pnpm run build" + }, + "keywords": [ + "superdoc", + "react", + "document", + "editor", + "docx", + "word" + ], + "license": "AGPL-3.0", + "dependencies": { + "superdoc": ">=1.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + }, + "devDependencies": { + "@testing-library/react": "catalog:", + "@types/node": "catalog:", + "@types/react": "catalog:", + "@types/react-dom": "catalog:", + "@typescript-eslint/eslint-plugin": "catalog:", + "@typescript-eslint/parser": "catalog:", + "eslint": "catalog:", + "happy-dom": "catalog:", + "react": "catalog:", + "react-dom": "catalog:", + "typescript": "catalog:", + "vite": "catalog:", + "vite-plugin-dts": "catalog:", + "@vitejs/plugin-react": "catalog:", + "vitest": "catalog:" + }, + "files": [ + "dist", + "style.css", + "README.md" + ], + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/superdoc-dev/superdoc.git", + "directory": "packages/react" + }, + "bugs": { + "url": "https://github.com/superdoc-dev/superdoc/issues" + }, + "homepage": "https://github.com/superdoc-dev/superdoc/tree/main/packages/react#readme" +} diff --git a/packages/react/src/SuperDocEditor.test.tsx b/packages/react/src/SuperDocEditor.test.tsx new file mode 100644 index 0000000000..6c469273ea --- /dev/null +++ b/packages/react/src/SuperDocEditor.test.tsx @@ -0,0 +1,227 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest'; +import { render, cleanup, waitFor } from '@testing-library/react'; +import { createRef, StrictMode } from 'react'; +import { SuperDocEditor } from './SuperDocEditor'; +import type { SuperDocRef } from './types'; + +describe('SuperDocEditor', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + afterEach(() => { + cleanup(); + }); + + describe('mounting and unmounting', () => { + it('should render container elements', () => { + const { container } = render(); + + expect(container.querySelector('.superdoc-wrapper')).toBeTruthy(); + expect(container.querySelector('.superdoc-editor-container')).toBeTruthy(); + expect(container.querySelector('.superdoc-toolbar-container')).toBeTruthy(); + }); + + it('should hide toolbar when hideToolbar={true}', () => { + const { container } = render(); + + expect(container.querySelector('.superdoc-toolbar-container')).toBeFalsy(); + }); + + it('should apply className and style props', () => { + const { container } = render(); + + const wrapper = container.querySelector('.superdoc-wrapper'); + expect(wrapper?.classList.contains('custom-class')).toBe(true); + expect((wrapper as HTMLElement)?.style.backgroundColor).toBe('red'); + }); + + it('should handle unmount without throwing', async () => { + const onReady = vi.fn(); + const { unmount } = render(); + + // Wait for initialization to complete + await waitFor( + () => { + expect(onReady).toHaveBeenCalled(); + }, + { timeout: 5000 }, + ); + + // Unmount should not throw + expect(() => unmount()).not.toThrow(); + }); + }); + + describe('ref methods', () => { + it('should expose getInstance method only', () => { + const ref = createRef(); + render(); + + // Ref should be available immediately with getInstance + expect(ref.current).not.toBeNull(); + expect(typeof ref.current?.getInstance).toBe('function'); + }); + + it('should return null from getInstance before ready', () => { + const ref = createRef(); + render(); + + // Before async init completes, getInstance returns null + const instance = ref.current?.getInstance(); + expect(instance).toBeNull(); + }); + + it('should safely handle calls through getInstance before ready', () => { + const ref = createRef(); + render(); + + // Using optional chaining through getInstance is safe + expect(() => ref.current?.getInstance()?.focus()).not.toThrow(); + expect(() => ref.current?.getInstance()?.setDocumentMode('viewing')).not.toThrow(); + expect(() => ref.current?.getInstance()?.toggleRuler()).not.toThrow(); + }); + }); + + describe('loading state', () => { + it('should show loading content initially', () => { + const { container } = render( +
Loading...
} />, + ); + + expect(container.querySelector('[data-testid="loading"]')).toBeTruthy(); + }); + }); + + describe('callbacks', () => { + it('should call onReady when SuperDoc is ready', async () => { + const onReady = vi.fn(); + render(); + + await waitFor( + () => { + expect(onReady).toHaveBeenCalled(); + }, + { timeout: 5000 }, + ); + }); + + it('should call onEditorCreate when editor is created', async () => { + const onEditorCreate = vi.fn(); + render(); + + await waitFor( + () => { + expect(onEditorCreate).toHaveBeenCalled(); + }, + { timeout: 5000 }, + ); + }); + }); + + describe('onEditorDestroy', () => { + it('should call onEditorDestroy when component unmounts', async () => { + const onReady = vi.fn(); + const onEditorDestroy = vi.fn(); + const { unmount } = render(); + + await waitFor( + () => { + expect(onReady).toHaveBeenCalled(); + }, + { timeout: 5000 }, + ); + + unmount(); + + await waitFor( + () => { + expect(onEditorDestroy).toHaveBeenCalled(); + }, + { timeout: 5000 }, + ); + }); + }); + + describe('error states', () => { + it('should show error container when initialization fails', async () => { + // Force an error by providing an invalid document + const onException = vi.fn(); + const { container } = render( + , + ); + + await waitFor( + () => { + const errorContainer = container.querySelector('.superdoc-error-container'); + // If SuperDoc throws on invalid input, error UI shows + // If SuperDoc handles it gracefully, onException may be called instead + expect(errorContainer || onException.mock.calls.length > 0).toBeTruthy(); + }, + { timeout: 5000 }, + ); + }); + }); + + describe('Strict Mode compatibility', () => { + it('should not throw in Strict Mode', () => { + expect(() => { + render( + + + , + ); + }).not.toThrow(); + }); + }); + + describe('unique IDs', () => { + it('should generate unique container IDs for multiple instances', () => { + const { container: container1 } = render(); + const { container: container2 } = render(); + + const id1 = container1.querySelector('.superdoc-editor-container')?.id; + const id2 = container2.querySelector('.superdoc-editor-container')?.id; + + expect(id1).toBeTruthy(); + expect(id2).toBeTruthy(); + expect(id1).not.toBe(id2); + }); + }); + + describe('with real superdoc', () => { + it('should initialize superdoc instance', async () => { + const ref = createRef(); + const onReady = vi.fn(); + + render(); + + await waitFor( + () => { + expect(onReady).toHaveBeenCalled(); + expect(ref.current?.getInstance()).not.toBeNull(); + }, + { timeout: 5000 }, + ); + }); + + it('should provide access to superdoc methods after ready', async () => { + const ref = createRef(); + const onReady = vi.fn(); + + render(); + + await waitFor( + () => { + expect(onReady).toHaveBeenCalled(); + }, + { timeout: 5000 }, + ); + + const instance = ref.current?.getInstance(); + expect(instance).toBeTruthy(); + expect(typeof instance?.destroy).toBe('function'); + expect(typeof instance?.setDocumentMode).toBe('function'); + }); + }); +}); diff --git a/packages/react/src/SuperDocEditor.tsx b/packages/react/src/SuperDocEditor.tsx new file mode 100644 index 0000000000..158162d8f3 --- /dev/null +++ b/packages/react/src/SuperDocEditor.tsx @@ -0,0 +1,251 @@ +import { + forwardRef, + useEffect, + useImperativeHandle, + useRef, + useState, + type CSSProperties, + type ForwardedRef, +} from 'react'; +import { useStableId } from './utils'; +import type { + CallbackProps, + DocumentMode, + SuperDocEditorProps, + SuperDocInstance, + SuperDocRef, + SuperDocReadyEvent, + SuperDocEditorCreateEvent, + SuperDocEditorUpdateEvent, + SuperDocContentErrorEvent, + SuperDocExceptionEvent, +} from './types'; + +/** + * SuperDocEditor - React wrapper component for SuperDoc + * + * Provides a component-based API with proper lifecycle management + * and React Strict Mode compatibility. Container divs are always + * rendered (hidden until initialized) so SuperDoc can mount into + * them on the first client-side effect. + */ +function SuperDocEditorInner(props: SuperDocEditorProps, ref: ForwardedRef) { + const [hasError, setHasError] = useState(false); + + // Destructure React-specific props and key rebuild triggers + const { + // React-specific + id, + renderLoading, + hideToolbar = false, + className, + style, + // Callbacks (stored in ref to avoid triggering rebuilds) + onReady, + onEditorCreate, + onEditorDestroy, + onEditorUpdate, + onContentError, + onException, + // Key props that trigger rebuild when changed + document: documentProp, + user, + users, + modules, + // All other props passed through + ...restProps + } = props; + + // Apply defaults + const documentMode = props.documentMode ?? 'editing'; + const role = props.role ?? 'editor'; + + const instanceRef = useRef(null); + const toolbarContainerRef = useRef(null); + + // Generate stable IDs (useStableId returns the same value across re-renders) + const generatedId = useStableId(); + const baseId = id ?? `superdoc${generatedId}`; + const containerId = baseId; + const toolbarId = `${baseId}-toolbar`; + + const [isLoading, setIsLoading] = useState(true); + + // Store callbacks in refs to avoid triggering effect on callback changes + const callbacksRef = useRef({ + onReady, + onEditorCreate, + onEditorDestroy, + onEditorUpdate, + onContentError, + onException, + }); + + // Update callback refs when props change + useEffect(() => { + callbacksRef.current = { + onReady, + onEditorCreate, + onEditorDestroy, + onEditorUpdate, + onContentError, + onException, + }; + }, [onReady, onEditorCreate, onEditorDestroy, onEditorUpdate, onContentError, onException]); + + // Queue mode changes that happen during init + const pendingModeRef = useRef(null); + const isInitializingRef = useRef(false); + + // Track documentMode changes and apply imperatively + const prevDocumentModeRef = useRef(documentMode); + useEffect(() => { + if (prevDocumentModeRef.current !== documentMode) { + if (instanceRef.current) { + // Instance exists, apply immediately + instanceRef.current.setDocumentMode(documentMode); + } else if (isInitializingRef.current) { + // Instance is initializing, queue the mode change + pendingModeRef.current = documentMode; + } + } + prevDocumentModeRef.current = documentMode; + }, [documentMode]); + + // Expose ref methods - simplified API with just getInstance() + useImperativeHandle( + ref, + () => ({ + getInstance: () => instanceRef.current, + }), + [], + ); + + // Main effect: create and destroy SuperDoc instance + useEffect(() => { + // Reset states when document changes + setIsLoading(true); + setHasError(false); + isInitializingRef.current = true; + + let destroyed = false; + let instance: SuperDocInstance | null = null; + + const initSuperDoc = async () => { + try { + // Dynamic import for SSR safety + const modulePath = 'superdoc'; + const superdocModule = await import(/* @vite-ignore */ modulePath); + const SuperDoc = superdocModule.SuperDoc as new (config: Record) => SuperDocInstance; + + // Check if we were destroyed while loading + if (destroyed) return; + + // Build configuration - pass through all props + const superdocConfig = { + ...restProps, + selector: `#${CSS.escape(containerId)}`, + // Use internal toolbar container unless hideToolbar is true + ...(!hideToolbar && toolbarContainerRef.current ? { toolbar: `#${CSS.escape(toolbarId)}` } : {}), + documentMode, + role, + ...(documentProp != null ? { document: documentProp } : {}), + ...(user ? { user } : {}), + ...(users ? { users } : {}), + ...(modules ? { modules } : {}), + // Wire up callbacks with lifecycle guards + onReady: (event: SuperDocReadyEvent) => { + if (!destroyed) { + setIsLoading(false); + isInitializingRef.current = false; + + // Apply any pending mode changes + if (pendingModeRef.current && pendingModeRef.current !== documentMode) { + event.superdoc.setDocumentMode(pendingModeRef.current); + pendingModeRef.current = null; + } + + callbacksRef.current.onReady?.(event); + } + }, + onEditorCreate: (event: SuperDocEditorCreateEvent) => { + if (!destroyed) { + callbacksRef.current.onEditorCreate?.(event); + } + }, + onEditorDestroy: () => { + if (!destroyed) { + callbacksRef.current.onEditorDestroy?.(); + } + }, + onEditorUpdate: (event: SuperDocEditorUpdateEvent) => { + if (!destroyed) { + callbacksRef.current.onEditorUpdate?.(event); + } + }, + onContentError: (event: SuperDocContentErrorEvent) => { + if (!destroyed) { + callbacksRef.current.onContentError?.(event); + } + }, + onException: (event: SuperDocExceptionEvent) => { + if (!destroyed) { + callbacksRef.current.onException?.(event); + } + }, + }; + + instance = new SuperDoc(superdocConfig) as SuperDocInstance; + instanceRef.current = instance; + } catch (error) { + if (!destroyed) { + isInitializingRef.current = false; + setIsLoading(false); + setHasError(true); + console.error('[SuperDocEditor] Failed to initialize SuperDoc:', error); + callbacksRef.current.onException?.({ error: error as Error }); + } + } + }; + + initSuperDoc(); + + // Cleanup function + return () => { + isInitializingRef.current = false; + pendingModeRef.current = null; + if (instance) { + instance.destroy(); + instanceRef.current = null; + } + destroyed = true; + }; + // Only these props trigger a full rebuild. Other props (rulers, etc.) are + // initial values - use getInstance() methods to change them at runtime. + // Note: restProps is intentionally excluded to avoid rebuilds on every render. + // documentMode is handled separately via setDocumentMode() for efficiency. + }, [documentProp, user, users, modules, role, hideToolbar, containerId, toolbarId]); + + const wrapperClassName = ['superdoc-wrapper', className].filter(Boolean).join(' '); + const hideWhenLoading: CSSProperties | undefined = isLoading ? { display: 'none' } : undefined; + + return ( +
+ {!hideToolbar && ( +
+ )} +
+ {isLoading && !hasError && renderLoading &&
{renderLoading()}
} + {hasError &&
Failed to load editor. Check console for details.
} +
+ ); +} + +/** + * SuperDocEditor component with forwardRef - Initializes SuperDoc instance and handles cleanup. + */ +export const SuperDocEditor = forwardRef(SuperDocEditorInner); + +SuperDocEditor.displayName = 'SuperDocEditor'; + +export default SuperDocEditor; diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts new file mode 100644 index 0000000000..5806eb8d50 --- /dev/null +++ b/packages/react/src/index.ts @@ -0,0 +1,28 @@ +// Main component +export { SuperDocEditor, default } from './SuperDocEditor'; + +// Types - extracted from superdoc package for convenience +export type { + // Component props and ref + SuperDocEditorProps, + SuperDocRef, + + // Core types (extracted from superdoc constructor) + DocumentMode, + UserRole, + SuperDocUser, + SuperDocModules, + SuperDocConfig, + SuperDocInstance, + + // Callback props + CallbackProps, + + // Callback event types + Editor, + SuperDocReadyEvent, + SuperDocEditorCreateEvent, + SuperDocEditorUpdateEvent, + SuperDocContentErrorEvent, + SuperDocExceptionEvent, +} from './types'; diff --git a/packages/react/src/types.ts b/packages/react/src/types.ts new file mode 100644 index 0000000000..4374ef4878 --- /dev/null +++ b/packages/react/src/types.ts @@ -0,0 +1,163 @@ +import type { CSSProperties, ReactNode } from 'react'; +import type { SuperDoc, Editor } from 'superdoc'; + +/** + * Types for @superdoc-dev/react + * + * Core types are extracted from the SuperDoc constructor parameter type, + * ensuring they stay in sync with the superdoc package. + */ + +// ============================================================================= +// Extract types from SuperDoc constructor (single source of truth) +// ============================================================================= + +/** SuperDoc constructor config - extracted from superdoc package */ +type SuperDocConstructorConfig = ConstructorParameters[0]; + +/** SuperDoc instance type - from superdoc package */ +export type SuperDocInstance = InstanceType; + +/** Document mode - extracted from Config.documentMode */ +export type DocumentMode = NonNullable; + +/** User role - extracted from Config.role */ +export type UserRole = NonNullable; + +/** User object - extracted from Config.user */ +export type SuperDocUser = NonNullable; + +/** Modules configuration - extracted from Config.modules */ +export type SuperDocModules = NonNullable; + +/** Full SuperDoc config - extracted from constructor */ +export type SuperDocConfig = SuperDocConstructorConfig; + +// ============================================================================= +// Callback Event Types +// ============================================================================= + +// Re-export Editor type from superdoc +export type { Editor } from 'superdoc'; + +/** Event passed to onReady callback */ +export interface SuperDocReadyEvent { + superdoc: SuperDocInstance; +} + +/** Event passed to onEditorCreate callback */ +export interface SuperDocEditorCreateEvent { + editor: Editor; +} + +/** Event passed to onEditorUpdate callback */ +export interface SuperDocEditorUpdateEvent { + editor: Editor; +} + +/** Event passed to onContentError callback */ +export interface SuperDocContentErrorEvent { + error: Error; + editor: Editor; + documentId: string; + file: File; +} + +/** Event passed to onException callback */ +export interface SuperDocExceptionEvent { + error: Error; +} + +// ============================================================================= +// React Component Types +// ============================================================================= + +/** + * Props managed internally by the React component (not exposed to users). + * - selector: managed by component (creates internal container) + */ +type InternalProps = 'selector'; + +/** + * Props that are required in core but should be optional in React. + * - documentMode: defaults to 'editing' if not provided + */ +type OptionalInReact = 'documentMode'; + +/** + * Callback props that are explicitly typed in CallbackProps. + * These are excluded from SuperDocConfig to avoid type conflicts. + */ +type ExplicitCallbackProps = + | 'onReady' + | 'onEditorCreate' + | 'onEditorDestroy' + | 'onEditorUpdate' + | 'onContentError' + | 'onException'; + +/** + * Explicitly typed callback props to ensure proper TypeScript inference. + * These override any loosely-typed callbacks from SuperDocConfig. + */ +export interface CallbackProps { + /** Callback when SuperDoc is ready */ + onReady?: (event: SuperDocReadyEvent) => void; + + /** Callback after an editor is created */ + onEditorCreate?: (event: SuperDocEditorCreateEvent) => void; + + /** Callback when editor is destroyed */ + onEditorDestroy?: () => void; + + /** Callback when document content is updated */ + onEditorUpdate?: (event: SuperDocEditorUpdateEvent) => void; + + /** Callback when there is a content parsing error */ + onContentError?: (event: SuperDocContentErrorEvent) => void; + + /** Callback when an exception is thrown */ + onException?: (event: SuperDocExceptionEvent) => void; +} + +/** + * React-specific props added on top of SuperDocConfig. + */ +interface ReactProps { + /** Optional ID for the editor container. Auto-generated if not provided. */ + id?: string; + + /** Render function for loading state */ + renderLoading?: () => ReactNode; + + /** Hide the toolbar container. When true, no toolbar is rendered. @default false */ + hideToolbar?: boolean; + + /** Additional CSS class name for the wrapper element */ + className?: string; + + /** Additional inline styles for the wrapper element */ + style?: CSSProperties; +} + +/** + * Props for SuperDocEditor component. + * + * Extends SuperDocConfig (minus internal props) with React-specific additions. + * When new props are added to SuperDoc core, they're automatically available here. + * + * Callback props are explicitly typed to ensure proper TypeScript inference. + */ +export interface SuperDocEditorProps + extends Omit, + Partial>, + CallbackProps, + ReactProps {} + +/** + * Ref interface for SuperDocEditor component + */ +export interface SuperDocRef { + /** Get the underlying SuperDoc instance. Returns null if not yet initialized. */ + getInstance(): SuperDocInstance | null; +} diff --git a/packages/react/src/utils.ts b/packages/react/src/utils.ts new file mode 100644 index 0000000000..6162d2b8f1 --- /dev/null +++ b/packages/react/src/utils.ts @@ -0,0 +1,27 @@ +/** @module utils */ + +import * as React from 'react'; + +/** + * Polyfill for React.useId() for React versions < 18. + * Uses useRef to generate a stable random ID once per component instance. + */ +function useIdPolyfill(): string { + const ref = React.useRef(null); + if (ref.current === null) { + ref.current = `-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`; + } + return ref.current; +} + +/** + * Hook that returns a stable unique ID for the component instance. + * Uses React.useId() when available (React 18+), falls back to + * useRef-based polyfill for React 16.8+/17. + * + * The returned value is used as: `superdoc${useStableId()}` + * - React 18+: useId() returns ":r0:" → "superdoc:r0:" + * - Polyfill: returns "-1707345123456-abc1d2e" → "superdoc-1707345123456-abc1d2e" + */ +export const useStableId: () => string = + typeof (React as any).useId === 'function' ? (React as any).useId : useIdPolyfill; diff --git a/packages/react/style.css b/packages/react/style.css new file mode 100644 index 0000000000..7242c28bd0 --- /dev/null +++ b/packages/react/style.css @@ -0,0 +1,2 @@ +/* @superdoc-dev/react styles - re-exports superdoc styles */ +@import 'superdoc/style.css'; diff --git a/packages/react/tsconfig.json b/packages/react/tsconfig.json new file mode 100644 index 0000000000..309d389c06 --- /dev/null +++ b/packages/react/tsconfig.json @@ -0,0 +1,13 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "outDir": "./dist", + "rootDir": "./src", + "jsx": "react-jsx", + "forceConsistentCasingInFileNames": true, + "allowSyntheticDefaultImports": true + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "**/*.test.ts", "**/*.test.tsx"] +} diff --git a/packages/react/vite.config.ts b/packages/react/vite.config.ts new file mode 100644 index 0000000000..bd48e2cb0e --- /dev/null +++ b/packages/react/vite.config.ts @@ -0,0 +1,38 @@ +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; +import dts from 'vite-plugin-dts'; + +export default defineConfig({ + plugins: [ + react(), + dts({ + include: ['src/**/*'], + exclude: ['src/**/*.test.ts', 'src/**/*.test.tsx'], + outDir: 'dist', + rollupTypes: true, + }), + ], + build: { + target: 'es2020', + lib: { + entry: 'src/index.ts', + name: 'SuperDocReact', + formats: ['es', 'cjs'], + fileName: (format) => (format === 'es' ? 'index.js' : 'index.cjs'), + }, + minify: true, + sourcemap: false, + rollupOptions: { + external: ['react', 'react-dom', 'react/jsx-runtime', 'superdoc'], + output: { + exports: 'named', + globals: { + react: 'React', + 'react-dom': 'ReactDOM', + 'react/jsx-runtime': 'jsxRuntime', + superdoc: 'SuperDoc', + }, + }, + }, + }, +}); diff --git a/packages/react/vitest.config.ts b/packages/react/vitest.config.ts new file mode 100644 index 0000000000..e223796487 --- /dev/null +++ b/packages/react/vitest.config.ts @@ -0,0 +1,18 @@ +import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + globals: true, + environment: 'happy-dom', + include: ['src/**/*.test.{ts,tsx}'], + coverage: { + provider: 'v8', + reporter: ['text', 'json', 'html'], + include: ['src/**/*.{ts,tsx}'], + exclude: ['src/**/*.d.ts', 'src/**/*.test.{ts,tsx}'], + }, + }, + esbuild: { + jsx: 'automatic', + }, +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a44228b885..9ec92b8636 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -208,11 +208,11 @@ catalogs: specifier: ^1.33.8 version: 1.41.5 react: - specifier: 19.2.0 - version: 19.2.0 + specifier: 19.2.4 + version: 19.2.4 react-dom: - specifier: 19.2.0 - version: 19.2.0 + specifier: 19.2.4 + version: 19.2.4 rehype-parse: specifier: ^9.0.1 version: 9.0.1 @@ -422,7 +422,7 @@ importers: version: 14.0.3 mintlify: specifier: ^4.2.331 - version: 4.2.331(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/node@22.19.8)(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(typescript@5.9.3) + version: 4.2.331(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.8)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(typescript@5.9.3) remark-mdx: specifier: ^3.1.1 version: 3.1.1 @@ -523,6 +523,15 @@ importers: specifier: 'catalog:' version: 7.3.1(@types/node@22.19.8)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + examples/__tests__: + devDependencies: + '@playwright/test': + specifier: ^1.50.0 + version: 1.58.1 + serve: + specifier: ^14.2.0 + version: 14.2.5 + packages/ai: devDependencies: '@types/node': @@ -618,7 +627,7 @@ importers: version: 6.9.1 '@testing-library/react': specifier: 'catalog:' - version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@testing-library/user-event': specifier: 'catalog:' version: 14.6.1(@testing-library/dom@10.4.1) @@ -642,10 +651,10 @@ importers: version: 27.3.0(canvas@3.2.0) react: specifier: 'catalog:' - version: 19.2.0 + version: 19.2.4 react-dom: specifier: 'catalog:' - version: 19.2.0(react@19.2.0) + version: 19.2.4(react@19.2.4) superdoc: specifier: workspace:* version: link:../superdoc @@ -669,10 +678,10 @@ importers: version: link:.. react: specifier: 'catalog:' - version: 19.2.0 + version: 19.2.4 react-dom: specifier: 'catalog:' - version: 19.2.0(react@19.2.0) + version: 19.2.4(react@19.2.4) signature_pad: specifier: ^5.1.1 version: 5.1.3 @@ -896,6 +905,58 @@ importers: packages/preset-geometry: {} + packages/react: + dependencies: + superdoc: + specifier: '>=1.0.0' + version: 1.11.0(@hocuspocus/provider@2.15.3(y-protocols@1.0.7(yjs@13.6.19))(yjs@13.6.19))(canvas@3.2.0)(pdfjs-dist@4.3.136)(typescript@5.9.3)(y-prosemirror@1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(y-protocols@1.0.7(yjs@13.6.19))(yjs@13.6.19))(yjs@13.6.19) + devDependencies: + '@testing-library/react': + specifier: 'catalog:' + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) + '@types/node': + specifier: 'catalog:' + version: 22.19.2 + '@types/react': + specifier: 'catalog:' + version: 19.2.11 + '@types/react-dom': + specifier: 'catalog:' + version: 19.2.3(@types/react@19.2.11) + '@typescript-eslint/eslint-plugin': + specifier: 'catalog:' + version: 8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': + specifier: 'catalog:' + version: 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@vitejs/plugin-react': + specifier: 'catalog:' + version: 5.1.3(vite@7.3.1(@types/node@22.19.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + eslint: + specifier: 'catalog:' + version: 9.39.2(jiti@2.6.1) + happy-dom: + specifier: 20.4.0 + version: 20.4.0 + react: + specifier: 'catalog:' + version: 19.2.4 + react-dom: + specifier: 'catalog:' + version: 19.2.4(react@19.2.4) + typescript: + specifier: 'catalog:' + version: 5.9.3 + vite: + specifier: 'catalog:' + version: 7.3.1(@types/node@22.19.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + vite-plugin-dts: + specifier: 'catalog:' + version: 4.5.4(@types/node@22.19.2)(rollup@4.57.1)(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)) + vitest: + specifier: 'catalog:' + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.19.2)(happy-dom@20.4.0)(jiti@2.6.1)(jsdom@27.3.0(canvas@3.2.0))(tsx@4.21.0)(yaml@2.8.2) + packages/super-editor: dependencies: buffer-crc32: @@ -1172,7 +1233,7 @@ importers: version: 6.9.1 '@testing-library/react': specifier: 'catalog:' - version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4) '@testing-library/user-event': specifier: 'catalog:' version: 14.6.1(@testing-library/dom@10.4.1) @@ -1196,10 +1257,10 @@ importers: version: 27.3.0(canvas@3.2.0) react: specifier: 'catalog:' - version: 19.2.0 + version: 19.2.4 react-dom: specifier: 'catalog:' - version: 19.2.0(react@19.2.0) + version: 19.2.4(react@19.2.4) superdoc: specifier: workspace:* version: link:../superdoc @@ -1223,10 +1284,10 @@ importers: version: link:.. react: specifier: 'catalog:' - version: 19.2.0 + version: 19.2.4 react-dom: specifier: 'catalog:' - version: 19.2.0(react@19.2.0) + version: 19.2.4(react@19.2.4) superdoc: specifier: workspace:* version: link:../../superdoc @@ -3759,6 +3820,9 @@ packages: '@yarnpkg/lockfile@1.1.0': resolution: {integrity: sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==} + '@zeit/schemas@2.36.0': + resolution: {integrity: sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg==} + JSONStream@1.3.5: resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} hasBin: true @@ -3862,6 +3926,9 @@ packages: alien-signals@0.4.14: resolution: {integrity: sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==} + ansi-align@3.0.1: + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} @@ -3908,6 +3975,9 @@ packages: resolution: {integrity: sha512-FCAJojipPn0bXjuEpjOOOMN8FZDkxfWWp4JGN9mifU2IhxvKyXZYqpzPHdnTSUpmPDy+tsslB6Z1g+Vg6nVbYA==} engines: {node: '>=8'} + arch@2.2.0: + resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==} + are-docs-informative@0.0.2: resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} engines: {node: '>=14'} @@ -4180,6 +4250,10 @@ packages: bottleneck@2.19.5: resolution: {integrity: sha512-VHiNCbI1lKdl44tGrhNfU3lup0Tj/ZBMJB5/2ZbNXRCPuRCO7ed2mgcK4r17y+KB2EfuYuRaVlwNbAeaWGSpbw==} + boxen@7.0.0: + resolution: {integrity: sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==} + engines: {node: '>=14.16'} + brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -4262,6 +4336,10 @@ packages: peerDependencies: esbuild: '>=0.18' + bytes@3.0.0: + resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} + engines: {node: '>= 0.8'} + bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -4306,6 +4384,10 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} + camelcase@7.0.1: + resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} + engines: {node: '>=14.16'} + caniuse-lite@1.0.30001767: resolution: {integrity: sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ==} @@ -4323,6 +4405,10 @@ packages: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} engines: {node: '>=18'} + chalk-template@0.4.0: + resolution: {integrity: sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==} + engines: {node: '>=12'} + chalk@2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -4331,6 +4417,10 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chalk@5.0.1: + resolution: {integrity: sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + chalk@5.2.0: resolution: {integrity: sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} @@ -4451,6 +4541,10 @@ packages: peerDependencies: typanion: '*' + clipboardy@3.0.0: + resolution: {integrity: sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + cliui@7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} @@ -4577,6 +4671,10 @@ packages: constants-browserify@1.0.0: resolution: {integrity: sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==} + content-disposition@0.5.2: + resolution: {integrity: sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA==} + engines: {node: '>= 0.6'} + content-disposition@0.5.4: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} @@ -6333,6 +6431,10 @@ packages: resolution: {integrity: sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==} engines: {node: '>=0.10.0'} + is-port-reachable@4.0.0: + resolution: {integrity: sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} @@ -7282,6 +7384,10 @@ packages: resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} hasBin: true + mime-db@1.33.0: + resolution: {integrity: sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==} + engines: {node: '>= 0.6'} + mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -7290,6 +7396,10 @@ packages: resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} engines: {node: '>= 0.6'} + mime-types@2.1.18: + resolution: {integrity: sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==} + engines: {node: '>= 0.6'} + mime-types@2.1.35: resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} engines: {node: '>= 0.6'} @@ -8042,6 +8152,9 @@ packages: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} + path-is-inside@1.0.2: + resolution: {integrity: sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -8071,6 +8184,9 @@ packages: path-to-regexp@0.1.7: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} + path-to-regexp@3.3.0: + resolution: {integrity: sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw==} + path-type@4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} @@ -8457,6 +8573,10 @@ packages: randomfill@1.0.4: resolution: {integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==} + range-parser@1.2.0: + resolution: {integrity: sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A==} + engines: {node: '>= 0.6'} + range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} @@ -8473,10 +8593,10 @@ packages: resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} hasBin: true - react-dom@19.2.0: - resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==} + react-dom@19.2.4: + resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==} peerDependencies: - react: ^19.2.0 + react: ^19.2.4 react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -8524,14 +8644,14 @@ packages: '@types/react': optional: true - react@19.2.0: - resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} - engines: {node: '>=0.10.0'} - react@19.2.3: resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} engines: {node: '>=0.10.0'} + react@19.2.4: + resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==} + engines: {node: '>=0.10.0'} + read-cache@1.0.0: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} @@ -8621,6 +8741,9 @@ packages: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} + registry-auth-token@3.3.2: + resolution: {integrity: sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ==} + registry-auth-token@4.2.2: resolution: {integrity: sha512-PC5ZysNb42zpFME6D/XlIgtNGdTl8bBOCw90xQLVMpzuuubJKYDWFAEuUNc+Cn8Z8724tg2SDhDRrkVEsqfDMg==} engines: {node: '>=6.0.0'} @@ -8629,6 +8752,10 @@ packages: resolution: {integrity: sha512-P7B4+jq8DeD2nMsAcdfaqHbssgHtZ7Z5+++a5ask90fvmJ8p5je4mOa+wzu+DB4vQ5tdJV/xywY+UnVFeQLV5Q==} engines: {node: '>=14'} + registry-url@3.1.0: + resolution: {integrity: sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA==} + engines: {node: '>=0.10.0'} + rehype-katex@7.0.1: resolution: {integrity: sha512-OiM2wrZ/wuhKkigASodFoo8wimG3H12LWQaH8qSPVJn9apWKFSH3YOCtbKpBorTVw/eI7cuT21XBbvwEswbIOA==} @@ -8929,6 +9056,9 @@ packages: resolution: {integrity: sha512-ZYkZLAvKTKQXWuh5XpBw7CdbSzagarX39WyZ2H07CDLC5/KfsRGlIXV8d4+tfqX1M7916mRqR1QfNHSij+c9Pw==} engines: {node: '>=18'} + serve-handler@6.1.6: + resolution: {integrity: sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ==} + serve-static@1.15.0: resolution: {integrity: sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==} engines: {node: '>= 0.8.0'} @@ -8937,6 +9067,11 @@ packages: resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} engines: {node: '>= 0.8.0'} + serve@14.2.5: + resolution: {integrity: sha512-Qn/qMkzCcMFVPb60E/hQy+iRLpiU8PamOfOSYoAHmmF+fFFmpPpqa6Oci2iWYpTdOUM3VF+TINud7CfbQnsZbA==} + engines: {node: '>= 14'} + hasBin: true + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -9283,6 +9418,14 @@ packages: resolution: {integrity: sha512-WHkws2ZflZe41zj6AolvvmaTrWds/VuyeYr9iPVv/oQeaIoVxMKaushfFWpOGDT+GuBrM/sVqF8KUCYQlSSTdQ==} engines: {node: '>=18'} + superdoc@1.11.0: + resolution: {integrity: sha512-DY5uObI50Itfxjjog9h8FQKGWLx0o0au2H0h9hbNtBrNXvg8mAeQvekSgYgwmL7xIW+juo/ZMSGY035eLDMmnw==} + peerDependencies: + '@hocuspocus/provider': ^2.13.6 + pdfjs-dist: '>=4.3.136 <=4.6.82' + y-prosemirror: ^1.3.7 + yjs: 13.6.19 + supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -9780,6 +9923,9 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + update-check@1.5.4: + resolution: {integrity: sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ==} + uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -10119,6 +10265,10 @@ packages: engines: {node: '>=8'} hasBin: true + widest-line@4.0.1: + resolution: {integrity: sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==} + engines: {node: '>=12'} + widest-line@5.0.0: resolution: {integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==} engines: {node: '>=18'} @@ -11007,11 +11157,11 @@ snapshots: '@floating-ui/core': 1.7.4 '@floating-ui/utils': 0.2.10 - '@floating-ui/react-dom@2.1.7(react-dom@19.2.0(react@19.2.3))(react@19.2.3)': + '@floating-ui/react-dom@2.1.7(react-dom@19.2.4(react@19.2.3))(react@19.2.3)': dependencies: '@floating-ui/dom': 1.7.5 react: 19.2.3 - react-dom: 19.2.0(react@19.2.3) + react-dom: 19.2.4(react@19.2.3) '@floating-ui/utils@0.2.10': {} @@ -11556,7 +11706,6 @@ snapshots: '@rushstack/node-core-library': 5.19.1(@types/node@22.19.2) transitivePeerDependencies: - '@types/node' - optional: true '@microsoft/api-extractor-model@7.32.2(@types/node@22.19.8)': dependencies: @@ -11584,7 +11733,6 @@ snapshots: typescript: 5.8.2 transitivePeerDependencies: - '@types/node' - optional: true '@microsoft/api-extractor@7.56.1(@types/node@22.19.8)': dependencies: @@ -11614,15 +11762,15 @@ snapshots: '@microsoft/tsdoc@0.16.0': {} - '@mintlify/cli@4.0.935(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/node@22.19.8)(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(typescript@5.9.3)': + '@mintlify/cli@4.0.935(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.8)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(typescript@5.9.3)': dependencies: '@inquirer/prompts': 7.9.0(@types/node@22.19.8) - '@mintlify/common': 1.0.713(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@mintlify/link-rot': 3.0.872(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/common': 1.0.713(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/link-rot': 3.0.872(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) '@mintlify/models': 0.0.268 - '@mintlify/prebuild': 1.0.849(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@mintlify/previewing': 4.0.905(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(typescript@5.9.3) - '@mintlify/validation': 0.1.585(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/prebuild': 1.0.849(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/previewing': 4.0.905(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(typescript@5.9.3) + '@mintlify/validation': 0.1.585(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) adm-zip: 0.5.16 chalk: 5.2.0 color: 4.2.3 @@ -11654,13 +11802,13 @@ snapshots: - typescript - utf-8-validate - '@mintlify/common@1.0.661(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@mintlify/common@1.0.661(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': dependencies: '@asyncapi/parser': 3.4.0 - '@mintlify/mdx': 3.0.4(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/mdx': 3.0.4(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) '@mintlify/models': 0.0.255 '@mintlify/openapi-parser': 0.0.8 - '@mintlify/validation': 0.1.555(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/validation': 0.1.555(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) '@sindresorhus/slugify': 2.2.0 '@types/mdast': 4.0.4 acorn: 8.11.2 @@ -11714,14 +11862,14 @@ snapshots: - ts-node - typescript - '@mintlify/common@1.0.713(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@mintlify/common@1.0.713(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': dependencies: '@asyncapi/parser': 3.4.0 '@asyncapi/specs': 6.8.1 - '@mintlify/mdx': 3.0.4(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/mdx': 3.0.4(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) '@mintlify/models': 0.0.268 '@mintlify/openapi-parser': 0.0.8 - '@mintlify/validation': 0.1.585(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/validation': 0.1.585(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) '@sindresorhus/slugify': 2.2.0 '@types/mdast': 4.0.4 acorn: 8.11.2 @@ -11775,13 +11923,13 @@ snapshots: - ts-node - typescript - '@mintlify/link-rot@3.0.872(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@mintlify/link-rot@3.0.872(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': dependencies: - '@mintlify/common': 1.0.713(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@mintlify/prebuild': 1.0.849(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@mintlify/previewing': 4.0.905(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(typescript@5.9.3) - '@mintlify/scraping': 4.0.522(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@mintlify/validation': 0.1.585(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/common': 1.0.713(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/prebuild': 1.0.849(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/previewing': 4.0.905(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(typescript@5.9.3) + '@mintlify/scraping': 4.0.522(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/validation': 0.1.585(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) fs-extra: 11.1.0 unist-util-visit: 4.1.2 transitivePeerDependencies: @@ -11801,9 +11949,9 @@ snapshots: - typescript - utf-8-validate - '@mintlify/mdx@3.0.4(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@mintlify/mdx@3.0.4(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': dependencies: - '@radix-ui/react-popover': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3) + '@radix-ui/react-popover': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3) '@shikijs/transformers': 3.22.0 '@shikijs/twoslash': 3.22.0(typescript@5.9.3) arktype: 2.1.29 @@ -11812,9 +11960,9 @@ snapshots: mdast-util-gfm: 3.1.0 mdast-util-mdx-jsx: 3.2.0 mdast-util-to-hast: 13.2.1 - next-mdx-remote-client: 1.1.4(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(unified@11.0.5) + next-mdx-remote-client: 1.1.4(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(unified@11.0.5) react: 19.2.3 - react-dom: 19.2.0(react@19.2.3) + react-dom: 19.2.4(react@19.2.3) rehype-katex: 7.0.1 remark-gfm: 4.0.1 remark-math: 6.0.0 @@ -11850,12 +11998,12 @@ snapshots: leven: 4.1.0 yaml: 2.8.2 - '@mintlify/prebuild@1.0.849(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@mintlify/prebuild@1.0.849(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': dependencies: - '@mintlify/common': 1.0.713(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/common': 1.0.713(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) '@mintlify/openapi-parser': 0.0.8 - '@mintlify/scraping': 4.0.574(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@mintlify/validation': 0.1.585(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/scraping': 4.0.574(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/validation': 0.1.585(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) chalk: 5.3.0 favicons: 7.2.0 front-matter: 4.0.2 @@ -11882,11 +12030,11 @@ snapshots: - typescript - utf-8-validate - '@mintlify/previewing@4.0.905(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(typescript@5.9.3)': + '@mintlify/previewing@4.0.905(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(typescript@5.9.3)': dependencies: - '@mintlify/common': 1.0.713(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@mintlify/prebuild': 1.0.849(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) - '@mintlify/validation': 0.1.585(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/common': 1.0.713(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/prebuild': 1.0.849(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/validation': 0.1.585(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) better-opn: 3.0.2 chalk: 5.2.0 chokidar: 3.5.3 @@ -11920,9 +12068,9 @@ snapshots: - typescript - utf-8-validate - '@mintlify/scraping@4.0.522(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@mintlify/scraping@4.0.522(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': dependencies: - '@mintlify/common': 1.0.661(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/common': 1.0.661(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) '@mintlify/openapi-parser': 0.0.8 fs-extra: 11.1.1 hast-util-to-mdast: 10.1.0 @@ -11955,9 +12103,9 @@ snapshots: - typescript - utf-8-validate - '@mintlify/scraping@4.0.574(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@mintlify/scraping@4.0.574(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': dependencies: - '@mintlify/common': 1.0.713(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/common': 1.0.713(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) '@mintlify/openapi-parser': 0.0.8 fs-extra: 11.1.1 hast-util-to-mdast: 10.1.0 @@ -11990,9 +12138,9 @@ snapshots: - typescript - utf-8-validate - '@mintlify/validation@0.1.555(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@mintlify/validation@0.1.555(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': dependencies: - '@mintlify/mdx': 3.0.4(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/mdx': 3.0.4(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) '@mintlify/models': 0.0.255 arktype: 2.1.27 js-yaml: 4.1.0 @@ -12012,9 +12160,9 @@ snapshots: - supports-color - typescript - '@mintlify/validation@0.1.585(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': + '@mintlify/validation@0.1.585(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3)': dependencies: - '@mintlify/mdx': 3.0.4(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(typescript@5.9.3) + '@mintlify/mdx': 3.0.4(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(typescript@5.9.3) '@mintlify/models': 0.0.268 arktype: 2.1.27 js-yaml: 4.1.0 @@ -12165,11 +12313,11 @@ snapshots: '@radix-ui/primitive@1.1.3': {} - '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)': + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3) react: 19.2.3 - react-dom: 19.2.0(react@19.2.3) + react-dom: 19.2.4(react@19.2.3) optionalDependencies: '@types/react': 19.2.11 '@types/react-dom': 19.2.3(@types/react@19.2.11) @@ -12186,15 +12334,15 @@ snapshots: optionalDependencies: '@types/react': 19.2.11 - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)': + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)': dependencies: '@radix-ui/primitive': 1.1.3 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.11)(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.11)(react@19.2.3) '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.11)(react@19.2.3) react: 19.2.3 - react-dom: 19.2.0(react@19.2.3) + react-dom: 19.2.4(react@19.2.3) optionalDependencies: '@types/react': 19.2.11 '@types/react-dom': 19.2.3(@types/react@19.2.11) @@ -12205,13 +12353,13 @@ snapshots: optionalDependencies: '@types/react': 19.2.11 - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)': + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.11)(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.11)(react@19.2.3) react: 19.2.3 - react-dom: 19.2.0(react@19.2.3) + react-dom: 19.2.4(react@19.2.3) optionalDependencies: '@types/react': 19.2.11 '@types/react-dom': 19.2.3(@types/react@19.2.11) @@ -12223,72 +12371,72 @@ snapshots: optionalDependencies: '@types/react': 19.2.11 - '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)': + '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)': dependencies: '@radix-ui/primitive': 1.1.3 '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.11)(react@19.2.3) '@radix-ui/react-context': 1.1.2(@types/react@19.2.11)(react@19.2.3) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3) '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.11)(react@19.2.3) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3) '@radix-ui/react-id': 1.1.1(@types/react@19.2.11)(react@19.2.3) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3) '@radix-ui/react-slot': 1.2.3(@types/react@19.2.11)(react@19.2.3) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.11)(react@19.2.3) aria-hidden: 1.2.6 react: 19.2.3 - react-dom: 19.2.0(react@19.2.3) + react-dom: 19.2.4(react@19.2.3) react-remove-scroll: 2.7.2(@types/react@19.2.11)(react@19.2.3) optionalDependencies: '@types/react': 19.2.11 '@types/react-dom': 19.2.3(@types/react@19.2.11) - '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)': + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)': dependencies: - '@floating-ui/react-dom': 2.1.7(react-dom@19.2.0(react@19.2.3))(react@19.2.3) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3) + '@floating-ui/react-dom': 2.1.7(react-dom@19.2.4(react@19.2.3))(react@19.2.3) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.11)(react@19.2.3) '@radix-ui/react-context': 1.1.2(@types/react@19.2.11)(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3) '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.11)(react@19.2.3) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.11)(react@19.2.3) '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.11)(react@19.2.3) '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.11)(react@19.2.3) '@radix-ui/rect': 1.1.1 react: 19.2.3 - react-dom: 19.2.0(react@19.2.3) + react-dom: 19.2.4(react@19.2.3) optionalDependencies: '@types/react': 19.2.11 '@types/react-dom': 19.2.3(@types/react@19.2.11) - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)': + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.11)(react@19.2.3) react: 19.2.3 - react-dom: 19.2.0(react@19.2.3) + react-dom: 19.2.4(react@19.2.3) optionalDependencies: '@types/react': 19.2.11 '@types/react-dom': 19.2.3(@types/react@19.2.11) - '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)': + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.11)(react@19.2.3) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.11)(react@19.2.3) react: 19.2.3 - react-dom: 19.2.0(react@19.2.3) + react-dom: 19.2.4(react@19.2.3) optionalDependencies: '@types/react': 19.2.11 '@types/react-dom': 19.2.3(@types/react@19.2.11) - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)': + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)': dependencies: '@radix-ui/react-slot': 1.2.3(@types/react@19.2.11)(react@19.2.3) react: 19.2.3 - react-dom: 19.2.0(react@19.2.3) + react-dom: 19.2.4(react@19.2.3) optionalDependencies: '@types/react': 19.2.11 '@types/react-dom': 19.2.3(@types/react@19.2.11) @@ -12457,7 +12605,6 @@ snapshots: semver: 7.5.4 optionalDependencies: '@types/node': 22.19.2 - optional: true '@rushstack/node-core-library@5.19.1(@types/node@22.19.8)': dependencies: @@ -12475,7 +12622,6 @@ snapshots: '@rushstack/problem-matcher@0.1.1(@types/node@22.19.2)': optionalDependencies: '@types/node': 22.19.2 - optional: true '@rushstack/problem-matcher@0.1.1(@types/node@22.19.8)': optionalDependencies: @@ -12493,7 +12639,6 @@ snapshots: supports-color: 8.1.1 optionalDependencies: '@types/node': 22.19.2 - optional: true '@rushstack/terminal@0.21.0(@types/node@22.19.8)': dependencies: @@ -12511,7 +12656,6 @@ snapshots: string-argv: 0.3.2 transitivePeerDependencies: - '@types/node' - optional: true '@rushstack/ts-command-line@5.2.0(@types/node@22.19.8)': dependencies: @@ -12866,12 +13010,12 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)': dependencies: '@babel/runtime': 7.28.6 '@testing-library/dom': 10.4.1 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) optionalDependencies: '@types/react': 19.2.11 '@types/react-dom': 19.2.3(@types/react@19.2.11) @@ -13375,6 +13519,18 @@ snapshots: lodash: 4.17.21 minimatch: 7.4.6 + '@vitejs/plugin-react@5.1.3(vite@7.3.1(@types/node@22.19.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))': + dependencies: + '@babel/core': 7.29.0 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.0) + '@rolldown/pluginutils': 1.0.0-rc.2 + '@types/babel__core': 7.20.5 + react-refresh: 0.18.0 + vite: 7.3.1(@types/node@22.19.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + transitivePeerDependencies: + - supports-color + '@vitejs/plugin-react@5.1.3(vite@7.3.1(@types/node@22.19.8)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2))': dependencies: '@babel/core': 7.29.0 @@ -13631,6 +13787,8 @@ snapshots: '@yarnpkg/lockfile@1.1.0': {} + '@zeit/schemas@2.36.0': {} + JSONStream@1.3.5: dependencies: jsonparse: 1.3.1 @@ -13740,6 +13898,10 @@ snapshots: alien-signals@0.4.14: {} + ansi-align@3.0.1: + dependencies: + string-width: 4.2.3 + ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 @@ -13775,6 +13937,8 @@ snapshots: apache-md5@1.1.8: {} + arch@2.2.0: {} + are-docs-informative@0.0.2: {} arg@5.0.2: {} @@ -14082,6 +14246,17 @@ snapshots: bottleneck@2.19.5: {} + boxen@7.0.0: + dependencies: + ansi-align: 3.0.1 + camelcase: 7.0.1 + chalk: 5.6.2 + cli-boxes: 3.0.0 + string-width: 5.1.2 + type-fest: 2.19.0 + widest-line: 4.0.1 + wrap-ansi: 8.1.0 + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -14192,6 +14367,8 @@ snapshots: esbuild: 0.27.2 load-tsconfig: 0.2.5 + bytes@3.0.0: {} + bytes@3.1.2: {} cac@6.7.14: {} @@ -14241,6 +14418,8 @@ snapshots: camelcase-css@2.0.1: {} + camelcase@7.0.1: {} + caniuse-lite@1.0.30001767: {} canvas@3.2.0: @@ -14260,6 +14439,10 @@ snapshots: loupe: 3.2.1 pathval: 2.0.1 + chalk-template@0.4.0: + dependencies: + chalk: 4.1.2 + chalk@2.4.2: dependencies: ansi-styles: 3.2.1 @@ -14271,6 +14454,8 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + chalk@5.0.1: {} + chalk@5.2.0: {} chalk@5.3.0: {} @@ -14405,6 +14590,12 @@ snapshots: dependencies: typanion: 3.14.0 + clipboardy@3.0.0: + dependencies: + arch: 2.2.0 + execa: 5.1.1 + is-wsl: 2.2.0 + cliui@7.0.4: dependencies: string-width: 4.2.3 @@ -14526,6 +14717,8 @@ snapshots: constants-browserify@1.0.0: {} + content-disposition@0.5.2: {} + content-disposition@0.5.4: dependencies: safe-buffer: 5.2.1 @@ -16837,6 +17030,8 @@ snapshots: is-plain-object@3.0.1: {} + is-port-reachable@4.0.0: {} + is-potential-custom-element-name@1.0.1: {} is-promise@2.2.2: {} @@ -18295,10 +18490,16 @@ snapshots: bn.js: 4.12.2 brorand: 1.1.0 + mime-db@1.33.0: {} + mime-db@1.52.0: {} mime-db@1.54.0: {} + mime-types@2.1.18: + dependencies: + mime-db: 1.33.0 + mime-types@2.1.35: dependencies: mime-db: 1.52.0 @@ -18368,9 +18569,9 @@ snapshots: minipass: 3.3.6 yallist: 4.0.0 - mintlify@4.2.331(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/node@22.19.8)(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(typescript@5.9.3): + mintlify@4.2.331(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.8)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(typescript@5.9.3): dependencies: - '@mintlify/cli': 4.0.935(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3))(@types/node@22.19.8)(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(typescript@5.9.3) + '@mintlify/cli': 4.0.935(@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.11))(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3))(@types/node@22.19.8)(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(typescript@5.9.3) transitivePeerDependencies: - '@radix-ui/react-popover' - '@types/node' @@ -18462,13 +18663,13 @@ snapshots: netmask@2.0.2: {} - next-mdx-remote-client@1.1.4(@types/react@19.2.11)(react-dom@19.2.0(react@19.2.3))(react@19.2.3)(unified@11.0.5): + next-mdx-remote-client@1.1.4(@types/react@19.2.11)(react-dom@19.2.4(react@19.2.3))(react@19.2.3)(unified@11.0.5): dependencies: '@babel/code-frame': 7.29.0 '@mdx-js/mdx': 3.1.1 '@mdx-js/react': 3.1.1(@types/react@19.2.11)(react@19.2.3) react: 19.2.3 - react-dom: 19.2.0(react@19.2.3) + react-dom: 19.2.4(react@19.2.3) remark-mdx-remove-esm: 1.2.2(unified@11.0.5) serialize-error: 12.0.0 vfile: 6.0.3 @@ -18962,6 +19163,8 @@ snapshots: path-is-absolute@1.0.1: {} + path-is-inside@1.0.2: {} + path-key@3.1.1: {} path-key@4.0.0: {} @@ -18983,6 +19186,8 @@ snapshots: path-to-regexp@0.1.7: {} + path-to-regexp@3.3.0: {} + path-type@4.0.0: {} path2d@0.2.2: @@ -19420,6 +19625,8 @@ snapshots: randombytes: 2.1.0 safe-buffer: 5.2.1 + range-parser@1.2.0: {} + range-parser@1.2.1: {} raw-body@2.5.1: @@ -19443,14 +19650,14 @@ snapshots: minimist: 1.2.8 strip-json-comments: 2.0.1 - react-dom@19.2.0(react@19.2.0): + react-dom@19.2.4(react@19.2.3): dependencies: - react: 19.2.0 + react: 19.2.3 scheduler: 0.27.0 - react-dom@19.2.0(react@19.2.3): + react-dom@19.2.4(react@19.2.4): dependencies: - react: 19.2.3 + react: 19.2.4 scheduler: 0.27.0 react-is@16.13.1: {} @@ -19491,10 +19698,10 @@ snapshots: optionalDependencies: '@types/react': 19.2.11 - react@19.2.0: {} - react@19.2.3: {} + react@19.2.4: {} + read-cache@1.0.0: dependencies: pify: 2.3.0 @@ -19637,6 +19844,11 @@ snapshots: gopd: 1.2.0 set-function-name: 2.0.2 + registry-auth-token@3.3.2: + dependencies: + rc: 1.2.8 + safe-buffer: 5.2.1 + registry-auth-token@4.2.2: dependencies: rc: 1.2.8 @@ -19645,6 +19857,10 @@ snapshots: dependencies: '@pnpm/npm-conf': 3.0.2 + registry-url@3.1.0: + dependencies: + rc: 1.2.8 + rehype-katex@7.0.1: dependencies: '@types/hast': 3.0.4 @@ -20147,6 +20363,16 @@ snapshots: dependencies: type-fest: 4.41.0 + serve-handler@6.1.6: + dependencies: + bytes: 3.0.0 + content-disposition: 0.5.2 + mime-types: 2.1.18 + minimatch: 3.1.2 + path-is-inside: 1.0.2 + path-to-regexp: 3.3.0 + range-parser: 1.2.0 + serve-static@1.15.0: dependencies: encodeurl: 1.0.2 @@ -20165,6 +20391,22 @@ snapshots: transitivePeerDependencies: - supports-color + serve@14.2.5: + dependencies: + '@zeit/schemas': 2.36.0 + ajv: 8.12.0 + arg: 5.0.2 + boxen: 7.0.0 + chalk: 5.0.1 + chalk-template: 0.4.0 + clipboardy: 3.0.0 + compression: 1.8.1 + is-port-reachable: 4.0.0 + serve-handler: 6.1.6 + update-check: 1.5.4 + transitivePeerDependencies: + - supports-color + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -20619,6 +20861,29 @@ snapshots: make-asynchronous: 1.0.1 time-span: 5.1.0 + superdoc@1.11.0(@hocuspocus/provider@2.15.3(y-protocols@1.0.7(yjs@13.6.19))(yjs@13.6.19))(canvas@3.2.0)(pdfjs-dist@4.3.136)(typescript@5.9.3)(y-prosemirror@1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(y-protocols@1.0.7(yjs@13.6.19))(yjs@13.6.19))(yjs@13.6.19): + dependencies: + '@hocuspocus/provider': 2.15.3(y-protocols@1.0.7(yjs@13.6.19))(yjs@13.6.19) + buffer-crc32: 1.0.0 + eventemitter3: 5.0.4 + jsdom: 27.3.0(canvas@3.2.0) + naive-ui: 2.43.2(vue@3.5.25(typescript@5.9.3)) + pdfjs-dist: 4.3.136 + pinia: 2.3.1(typescript@5.9.3)(vue@3.5.25(typescript@5.9.3)) + rollup-plugin-copy: 3.5.0 + uuid: 9.0.1 + vue: 3.5.25(typescript@5.9.3) + y-prosemirror: 1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.5)(y-protocols@1.0.7(yjs@13.6.19))(yjs@13.6.19) + y-websocket: 3.0.0(yjs@13.6.19) + yjs: 13.6.19 + transitivePeerDependencies: + - '@vue/composition-api' + - bufferutil + - canvas + - supports-color + - typescript + - utf-8-validate + supports-color@5.5.0: dependencies: has-flag: 3.0.0 @@ -21206,6 +21471,11 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 + update-check@1.5.4: + dependencies: + registry-auth-token: 3.3.2 + registry-url: 3.1.0 + uri-js@4.4.1: dependencies: punycode: 2.3.1 @@ -21451,6 +21721,25 @@ snapshots: - tsx - yaml + vite-plugin-dts@4.5.4(@types/node@22.19.2)(rollup@4.57.1)(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)): + dependencies: + '@microsoft/api-extractor': 7.56.1(@types/node@22.19.2) + '@rollup/pluginutils': 5.3.0(rollup@4.57.1) + '@volar/typescript': 2.4.28 + '@vue/language-core': 2.2.0(typescript@5.9.3) + compare-versions: 6.1.1 + debug: 4.4.3(supports-color@5.5.0) + kolorist: 1.8.0 + local-pkg: 1.1.2 + magic-string: 0.30.21 + typescript: 5.9.3 + optionalDependencies: + vite: 7.3.1(@types/node@22.19.2)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2) + transitivePeerDependencies: + - '@types/node' + - rollup + - supports-color + vite-plugin-dts@4.5.4(@types/node@22.19.8)(rollup@4.57.1)(typescript@5.9.3)(vite@7.3.1(@types/node@22.19.8)(jiti@2.6.1)(tsx@4.21.0)(yaml@2.8.2)): dependencies: '@microsoft/api-extractor': 7.56.1(@types/node@22.19.8) @@ -21732,6 +22021,10 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 + widest-line@4.0.1: + dependencies: + string-width: 5.1.2 + widest-line@5.0.0: dependencies: string-width: 7.2.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 5a2783f74f..13a7b8d8c1 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -4,6 +4,7 @@ packages: - apps/* - packages/**/* - shared/* + - examples/* catalog: '@commitlint/cli': ^19.8.1 @@ -76,8 +77,8 @@ catalog: prosemirror-test-builder: ^1.1.1 prosemirror-transform: ^1.9.0 prosemirror-view: ^1.33.8 - react: 19.2.0 - react-dom: 19.2.0 + react: 19.2.4 + react-dom: 19.2.4 rehype-parse: ^9.0.1 rehype-remark: ^10.0.1 remark-gfm: ^4.0.1